diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 337f47425..f8e229198 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,3 +1,3 @@ { - "recommendations": ["ms-vscode-remote.remote-containers"] + "recommendations": ["ms-vscode-remote.remote-containers", "vitest.explorer"] } diff --git a/Justfile-test b/Justfile-test index 55afb5a05..af5fe932a 100644 --- a/Justfile-test +++ b/Justfile-test @@ -64,4 +64,8 @@ test-typescript: #!/bin/bash set -euo pipefail - bun run --filter '*' test -- --coverage.reporter=lcov --reporter=default --reporter=junit --outputFile.junit=test-results/junit.xml \ No newline at end of file + bun run --filter '*' test -- --coverage.reporter=lcov --reporter=default --reporter=junit --outputFile.junit=test-results/junit.xml + +# Run all parity suites, or a single one if a name is given. +test-parity suite="": + TACHI_SERVER=https://127.0.0.1:8080 bun vitest run {{ if suite != "" { "tests/" + suite + ".test.ts" } else { "" } }} diff --git a/bun.lock b/bun.lock index 381f872c6..b254f3436 100644 --- a/bun.lock +++ b/bun.lock @@ -1,17908 +1,4409 @@ { - "lockfileVersion": 1, - "configVersion": 1, - "workspaces": { - "": { - "name": "tachi", - "devDependencies": { - "@biomejs/biome": "^2.0.6", - "@types/node": "20.19.37", - "@types/tap": "15.0.3", - "eslint": "^9.20.1", - "kanel": "^3.16.1", - "kanel-kysely": "^0.8.0", - "tap": "workspace:*", - "ts-node": "10.9.1", - "tsc-alias": "1.7.1", - "typescript": "5.9.3" - }, - "peerDependencies": { - "@types/bson": "1.0.11", - "@types/mongodb": "3.6.20", - "@types/node": "20.19.37", - "mongodb": "3.6.3" - } - }, - "typescript-vendor/tap": { - "name": "tap", - "version": "15.0.9", - "bin": { - "tap": "bin/run.js" - }, - "dependencies": { - "chokidar": "catalog:", - "coveralls": "catalog:", - "findit": "catalog:", - "foreground-child": "catalog:", - "fs-exists-cached": "catalog:", - "glob": "catalog:", - "import-jsx": "catalog:", - "ink": "catalog:", - "isexe": "catalog:", - "istanbul-lib-processinfo": "catalog:", - "jackspeak": "catalog:", - "libtap": "catalog:", - "minipass": "catalog:", - "mkdirp": "catalog:", - "nyc": "catalog:", - "opener": "catalog:", - "rimraf": "catalog:", - "signal-exit": "catalog:", - "source-map-support": "catalog:", - "tap-mocha-reporter": "catalog:", - "tap-parser": "catalog:", - "tap-yaml": "catalog:", - "tcompare": "catalog:", - "treport": "catalog:", - "which": "catalog:" - }, - "devDependencies": { - "flow-remove-types": "catalog:", - "node-preload": "catalog:", - "process-on-spawn": "catalog:", - "ts-node": "catalog:", - "typescript": "catalog:" - }, - "peerDependencies": { - "flow-remove-types": ">=2.112.0", - "ts-node": ">=8.5.2", - "typescript": ">=3.7.2" - }, - "optionalPeers": ["flow-remove-types", "ts-node", "typescript"] - }, - "typescript/bliss": { - "name": "bliss", - "version": "0.0.1", - "dependencies": { - "pino": "catalog:", - "pino-pretty": "catalog:", - "zod": "^4.3.6" - }, - "devDependencies": { - "@typescript/native-preview": "catalog:", - "eslint-config-tachi": "workspace:*", - "typescript": "catalog:" - } - }, - "typescript/bot": { - "name": "tachi-bot", - "version": "2.2.0", - "dependencies": { - "bliss": "workspace:*", - "@discordjs/builders": "catalog:", - "@discordjs/rest": "catalog:", - "@types/bson": "catalog:", - "@types/humanize-duration": "catalog:", - "@valuabletouch/winston-seq": "catalog:", - "deepmerge": "catalog:", - "discord-api-types": "catalog:", - "discord.js": "catalog:", - "dotenv": "catalog:", - "express": "catalog:", - "humanize-duration": "catalog:", - "json5": "catalog:", - "kysely": "catalog:", - "lodash": "catalog:", - "luxon": "catalog:", - "node-fetch": "catalog:", - "pg": "catalog:", - "prudence": "catalog:", - "seq-logging": "catalog:", - "tachi-common": "workspace:*", - "tachi-db": "workspace:*", - "ts-node": "catalog:", - "tsconfig-paths": "catalog:", - "typescript": "catalog:", - "winston": "catalog:" - }, - "devDependencies": { - "@types/express": "catalog:", - "@types/json5": "catalog:", - "@types/lodash": "catalog:", - "@types/luxon": "catalog:", - "@types/node": "catalog:", - "@types/node-fetch": "catalog:", - "@types/pg": "catalog:", - "@typescript/native-preview": "catalog:", - "@vitest/coverage-v8": "catalog:", - "eslint-config-tachi": "workspace:*", - "vitest": "catalog:" - } - }, - "typescript/client": { - "name": "tachi-client", - "version": "0.1.0-see-project-root", - "dependencies": { - "@fortawesome/fontawesome-free": "catalog:", - "@fullcalendar/core": "catalog:", - "@fullcalendar/daygrid": "catalog:", - "@fullcalendar/react": "catalog:", - "@nivo/bar": "catalog:", - "@nivo/colors": "catalog:", - "@nivo/core": "catalog:", - "@nivo/line": "catalog:", - "@nivo/tooltip": "catalog:", - "@types/lodash": "catalog:", - "@types/natural-compare": "catalog:", - "@types/react-google-recaptcha": "catalog:", - "csstype": "catalog:", - "d3-scale": "catalog:", - "deepmerge": "catalog:", - "dotenv": "catalog:", - "fast-json-stable-hash": "catalog:", - "formik": "catalog:", - "fs-extra": "catalog:", - "hash.js": "catalog:", - "humanize-duration": "catalog:", - "json-2-csv": "catalog:", - "lodash": "catalog:", - "luxon": "catalog:", - "nanoid": "catalog:", - "natural-compare": "catalog:", - "pretty-bytes": "catalog:", - "prop-types": "catalog:", - "prudence": "catalog:", - "react": "catalog:", - "react-async": "catalog:", - "react-bootstrap": "catalog:", - "react-dom": "catalog:", - "react-google-recaptcha": "catalog:", - "react-hot-toast": "catalog:", - "react-markdown": "catalog:", - "react-query": "catalog:", - "react-router-bootstrap": "catalog:", - "react-router-dom": "catalog:", - "react-select": "catalog:", - "rg-stats": "catalog:", - "sync-fetch": "catalog:", - "tachi-common": "workspace:*", - "vite-plugin-html": "catalog:" - }, - "devDependencies": { - "@types/history": "catalog:", - "@types/humanize-duration": "catalog:", - "@types/luxon": "catalog:", - "@types/react": "catalog:", - "@types/react-dom": "catalog:", - "@types/react-router-bootstrap": "catalog:", - "@types/react-router-dom": "catalog:", - "@typescript/native-preview": "catalog:", - "@vitejs/plugin-react": "catalog:", - "bootstrap-scss": "catalog:", - "eslint-config-tachi": "workspace:*", - "sass": "catalog:", - "typescript": "catalog:", - "vite": "catalog:" - } - }, - "typescript/common": { - "name": "tachi-common", - "version": "2.4.0-dev", - "dependencies": { - "@types/express-serve-static-core": "catalog:", - "@types/mongodb": "catalog:", - "deepmerge": "catalog:", - "prudence": "catalog:", - "zod": "catalog:" - }, - "devDependencies": { - "@types/tap": "catalog:", - "@typescript/native-preview": "catalog:", - "eslint-config-tachi": "workspace:*", - "tap": "workspace:*", - "typescript": "catalog:" - } - }, - "typescript/db": { - "name": "tachi-db", - "version": "0.1.0-see-project-root", - "dependencies": { - "kysely": "catalog:", - "pg": "catalog:" - }, - "devDependencies": { - "@types/express": "catalog:", - "@types/node": "catalog:", - "@types/node-fetch": "catalog:", - "@typescript/native-preview": "catalog:", - "@vitest/coverage-v8": "catalog:", - "eslint-config-tachi": "workspace:*", - "typescript": "catalog:", - "vitest": "catalog:" - } - }, - "typescript/db-cli": { - "name": "tachi-db-migration-engine-cli", - "version": "1.0.0", - "bin": { - "tachi-migrate": "./src/index.ts" - }, - "dependencies": { - "commander": "catalog:", - "pg": "catalog:", - "tachi-db-migration-engine": "workspace:*" - }, - "devDependencies": { - "@types/node": "catalog:", - "@types/pg": "catalog:", - "@typescript/native-preview": "catalog:", - "eslint-config-tachi": "workspace:*", - "typescript": "catalog:" - } - }, - "typescript/db-migration-engine": { - "name": "tachi-db-migration-engine", - "version": "1.0.0", - "dependencies": { - "kysely": "catalog:", - "pg": "catalog:" - }, - "devDependencies": { - "@types/node": "catalog:", - "@types/pg": "catalog:", - "@typescript/native-preview": "catalog:", - "eslint-config-tachi": "workspace:*", - "ts-node": "catalog:", - "typescript": "catalog:" - } - }, - "typescript/docs-autogen-scripts": { - "name": "tachi-autogen-docs", - "version": "1.0.0", - "dependencies": { - "commander": "catalog:", - "tachi-common": "workspace:*" - }, - "devDependencies": { - "@typescript/native-preview": "catalog:", - "eslint-config-tachi": "workspace:*" - } - }, - "typescript/eslint-config": { - "name": "eslint-config-tachi", - "version": "1.0.0", - "dependencies": { - "@eslint/js": "catalog:", - "@typescript-eslint/eslint-plugin": "catalog:", - "@typescript-eslint/parser": "catalog:", - "@typescript-eslint/utils": "catalog:", - "eslint-config-prettier": "catalog:", - "eslint-import-resolver-typescript": "catalog:", - "eslint-plugin-import": "catalog:", - "eslint-plugin-jsx-a11y": "catalog:", - "eslint-plugin-perfectionist": "catalog:", - "eslint-plugin-react": "catalog:", - "eslint-plugin-react-hooks": "catalog:", - "eslint-plugin-react-refresh": "catalog:", - "globals": "catalog:", - "typescript-eslint": "catalog:" - }, - "devDependencies": { - "@types/eslint__js": "catalog:" - }, - "peerDependencies": { - "eslint": "^9.20.1", - "prettier": "^3.4.2" - } - }, - "typescript/github-bot": { - "name": "tachi-github-bot", - "version": "0.1.0-see-project-root", - "dependencies": { - "@octokit/app": "catalog:", - "@octokit/webhooks-types": "catalog:", - "dotenv": "catalog:", - "express": "catalog:", - "node-fetch": "catalog:", - "prudence": "catalog:" - }, - "devDependencies": { - "@types/express": "catalog:", - "@types/node": "catalog:", - "@types/node-fetch": "catalog:", - "@typescript/native-preview": "catalog:", - "eslint-config-tachi": "workspace:*", - "typescript": "catalog:" - } - }, - "typescript/seeds-scripts": { - "name": "tachi-seeds-scripts", - "version": "0.1.0-see-project-root", - "dependencies": { - "@types/lodash.get": "catalog:", - "@types/node": "catalog:", - "better-sqlite3": "catalog:", - "binary-parser": "catalog:", - "bms-table-loader": "catalog:", - "chalk": "catalog:", - "cheerio": "catalog:", - "commander": "catalog:", - "csv-parse": "catalog:", - "deepmerge": "catalog:", - "encoding-japanese": "catalog:", - "fast-json-stable-hash": "catalog:", - "fast-xml-parser": "catalog:", - "glob": "catalog:", - "html-entities": "catalog:", - "iconv-lite": "catalog:", - "lodash.get": "catalog:", - "monk": "catalog:", - "node-fetch": "catalog:", - "prudence": "catalog:", - "tachi-common": "workspace:*", - "zod": "catalog:" - }, - "devDependencies": { - "@typescript/native-preview": "catalog:", - "eslint-config-tachi": "workspace:*", - "tsconfig-paths": "catalog:" - } - }, - "typescript/server": { - "name": "tachi-server", - "version": "2.5.1", - "dependencies": { - "@aws-sdk/client-s3": "catalog:", - "@aws-sdk/signature-v4-crt": "catalog:", - "bliss": "workspace:*", - "@types/bcryptjs": "catalog:", - "@types/bson": "catalog:", - "@types/bunyan": "catalog:", - "@types/connect-redis": "catalog:", - "@types/express": "catalog:", - "@types/express-rate-limit": "catalog:", - "@types/express-serve-static-core": "catalog:", - "@types/express-session": "catalog:", - "@types/glob": "catalog:", - "@types/mkdirp": "catalog:", - "@types/mongodb": "catalog:", - "@types/multer": "catalog:", - "@types/node": "catalog:", - "@types/node-fetch": "catalog:", - "@types/nodemailer": "catalog:", - "@types/rate-limit-redis": "catalog:", - "@types/redis": "catalog:", - "@types/rimraf": "catalog:", - "@types/safe-json-stringify": "catalog:", - "@types/semver": "catalog:", - "@valuabletouch/winston-seq": "catalog:", - "bcryptjs": "catalog:", - "bms-table-loader": "catalog:", - "bullmq": "catalog:", - "bunyan": "catalog:", - "commander": "catalog:", - "connect-redis": "catalog:", - "csv-parse": "catalog:", - "deepmerge": "catalog:", - "express": "catalog:", - "express-async-errors": "catalog:", - "express-prom-bundle": "catalog:", - "express-rate-limit": "catalog:", - "express-session": "catalog:", - "fast-json-stable-hash": "catalog:", - "fast-xml-parser": "catalog:", - "helmet": "catalog:", - "html-entities": "catalog:", - "json5": "catalog:", - "kysely": "catalog:", - "mkdirp": "catalog:", - "mongodb": "catalog:", - "monk": "catalog:", - "multer": "catalog:", - "node-cache": "catalog:", - "node-fetch": "catalog:", - "node-html-parser": "catalog:", - "nodemailer": "catalog:", - "pg": "catalog:", - "prudence": "catalog:", - "rate-limit-redis": "catalog:", - "redis": "catalog:", - "rg-stats": "catalog:", - "rimraf": "catalog:", - "safe-json-stringify": "catalog:", - "semver": "catalog:", - "tachi-common": "workspace:*", - "tachi-db": "workspace:*", - "tachi-db-migration-engine": "workspace:*", - "ts-node": "catalog:", - "typescript": "catalog:", - "uuidv7": "catalog:", - "winston": "catalog:", - "winston-loki": "catalog:", - "winston-transport": "catalog:", - "zod": "catalog:" - }, - "devDependencies": { - "@grpc/grpc-js": "catalog:", - "@types/google-protobuf": "catalog:", - "@types/pg": "catalog:", - "@types/supertest": "catalog:", - "@types/tap": "catalog:", - "@typescript/native-preview": "catalog:", - "eslint-config-tachi": "workspace:*", - "glob": "catalog:", - "google-protobuf": "catalog:", - "grpc-tools": "catalog:", - "node-mocks-http": "catalog:", - "nodemon": "catalog:", - "supertest": "catalog:", - "tap": "workspace:*", - "ts-protoc-gen": "catalog:", - "tsconfig-paths": "catalog:" - } - }, - "typescript/sieglinde": { - "name": "tachi-sieglinde", - "version": "0.1.0-see-project-root", - "dependencies": { - "@types/node-fetch": "catalog:", - "bms-table-loader": "catalog:", - "commander": "catalog:", - "fast-xml-parser": "catalog:", - "node-fetch": "catalog:", - "tachi-common": "workspace:*", - "winston": "catalog:" - }, - "devDependencies": { - "@typescript/native-preview": "catalog:", - "eslint-config-tachi": "workspace:*" - } - } - }, - "patchedDependencies": { - "monk@7.3.4": "patches/monk@7.3.4.patch", - "@types/mongodb@3.6.20": "patches/@types__mongodb@3.6.20.patch" - }, - "overrides": { - "@types/bson": "1.0.11", - "@types/express": "4.17.13", - "@types/express-serve-static-core": "4.17.29", - "@types/mongodb": "3.6.20", - "@types/node": "20.19.37", - "mongodb": "3.6.3", - "ts-node": "10.9.1", - "typescript": "5.9.3" - }, - "catalog": { - "@aws-sdk/client-s3": "3.49.0", - "@aws-sdk/signature-v4-crt": "3.49.0", - "@babel/core": "7.1.0", - "@discordjs/builders": "0.5.0", - "@discordjs/rest": "0.1.0-canary.0", - "@eslint/js": "^9.20.0", - "@fortawesome/fontawesome-free": "5.13.0", - "@fullcalendar/core": "^6.0.0", - "@fullcalendar/daygrid": "^6.0.0", - "@fullcalendar/react": "^6.0.0", - "@grpc/grpc-js": "^1.10.6", - "@nivo/bar": "0.79.1", - "@nivo/colors": "0.79.1", - "@nivo/core": "0.79.0", - "@nivo/line": "0.79.1", - "@nivo/tooltip": "0.79.0", - "@octokit/app": "15.1.0", - "@octokit/webhooks-types": "7.5.1", - "@types/bcryptjs": "^2.4.2", - "@types/bson": "1.0.11", - "@types/bunyan": "^1.8.8", - "@types/connect-redis": "0.0.18", - "@types/eslint__js": "8.42.3", - "@types/express": "4.17.13", - "@types/express-rate-limit": "5.1.3", - "@types/express-serve-static-core": "4.17.29", - "@types/express-session": "1.17.4", - "@types/glob": "^7.2.0", - "@types/google-protobuf": "^3.15.12", - "@types/history": "4.7.11", - "@types/humanize-duration": "^3.27.1", - "@types/jest": "^26.0.23", - "@types/json5": "2.2.0", - "@types/lodash": "4.14.172", - "@types/lodash.get": "^4.4.7", - "@types/luxon": "^2.3.1", - "@types/mkdirp": "1.0.2", - "@types/mongodb": "3.6.20", - "@types/multer": "1.4.7", - "@types/natural-compare": "^1.4.1", - "@types/node": "*", - "@types/node-fetch": "2.5.12", - "@types/nodemailer": "^6.4.4", - "@types/pg": "^8.11.11", - "@types/rate-limit-redis": "1.7.4", - "@types/react": "17.0.13", - "@types/react-dom": "17.0.8", - "@types/react-google-recaptcha": "2.1.2", - "@types/react-router-bootstrap": "0.26.1", - "@types/react-router-dom": "5.1.7", - "@types/redis": "2.8.32", - "@types/rimraf": "3.0.2", - "@types/safe-json-stringify": "1.1.2", - "@types/semver": "^7.3.9", - "@types/supertest": "2.0.11", - "@types/tap": "15.0.5", - "@typescript-eslint/eslint-plugin": "^4.27.0", - "@typescript-eslint/parser": "^4.27.0", - "@typescript-eslint/utils": "^8.24.1", - "@typescript/native-preview": "7.0.0-dev.20260309.1", - "@valuabletouch/winston-seq": "1.3.0", - "@vitejs/plugin-react": "^6.0.1", - "@vitest/coverage-istanbul": "~3.2.0", - "@vitest/coverage-v8": "~3.2.0", - "bcryptjs": "2.4.3", - "better-sqlite3": "9.4.5", - "binary-parser": "^2.3.0", - "bms-table-loader": "2.0.0", - "bootstrap-scss": "^5.3.0", - "bullmq": "1.68.4", - "bunyan": "1.8.15", - "chalk": "4", - "cheerio": "^1.0.0-rc.12", - "chokidar": "^3.3.0", - "commander": "^8.2.0", - "connect-redis": "6.1.1", - "coveralls": "^3.0.11", - "csstype": "3.1.1", - "csv-parse": "^5.0.3", - "d3-scale": "3.3.0", - "deepmerge": "^4.2.2", - "discord-api-types": "0.22.0", - "discord.js": "13.6.0", - "dotenv": "16.0.0", - "encoding-japanese": "^1.0.30", - "eslint": "^7.29.0", - "eslint-config-prettier": "^9.1.0", - "eslint-config-standard": "^16.0.3", - "eslint-import-resolver-typescript": "^3.7.0", - "eslint-plugin-import": "^2.31.0", - "eslint-plugin-jest": "^24.3.6", - "eslint-plugin-jsx-a11y": "^6.10.2", - "eslint-plugin-perfectionist": "^3.9.1", - "eslint-plugin-react": "^7.37.4", - "eslint-plugin-react-hooks": "^5.1.0", - "eslint-plugin-react-refresh": "^0.4.14", - "express": "4.20.0", - "express-async-errors": "3.1.1", - "express-prom-bundle": "^7.0.0", - "express-rate-limit": "5.5.1", - "express-session": "1.17.2", - "fast-json-stable-hash": "^1.0.3", - "fast-xml-parser": "^4.2.5", - "findit": "^2.0.0", - "flow-remove-types": "^2.112.0", - "foreground-child": "^2.0.0", - "formik": "2.2.9", - "fs-exists-cached": "^1.0.0", - "fs-extra": "7.0.1", - "glob": "^7.1.6", - "globals": "^15.15.0", - "google-protobuf": "^3.21.2", - "grpc-tools": "^1.12.4", - "hash.js": "1.1.7", - "helmet": "5.0.2", - "html-entities": "^2.3.2", - "humanize-duration": "^3.27.1", - "iconv-lite": "^0.6.3", - "import-jsx": "^4.0.0", - "ink": "^2.7.1", - "isexe": "^2.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "jackspeak": "^1.4.0", - "jest": "^27.0.4", - "json-2-csv": "3.14.4", - "json5": "2.2.0", - "kysely": "^0.27.5", - "libtap": "^1.1.1", - "lodash": "4.17.21", - "lodash.get": "^4.4.2", - "luxon": "^2.3.1", - "minipass": "^3.1.1", - "mkdirp": "^1.0.4", - "mongodb": "3.6.3", - "monk": "^7.3.4", - "multer": "2.0.1", - "nanoid": "3.1.23", - "natural-compare": "^1.4.0", - "node-cache": "5.1.2", - "node-fetch": "2.6.7", - "node-html-parser": "^5.3.3", - "node-mocks-http": "1.11.0", - "node-preload": "^0.2.1", - "node-sass": "9.0.0", - "nodemailer": "7.0.11", - "nodemon": "^2.0.20", - "nyc": "^15.1.0", - "opener": "^1.5.1", - "pg": "^8.13.3", - "pino": "^10.3.1", - "pino-pretty": "^13.1.3", - "prettier": "3.2.5", - "pretty-bytes": "5.6.0", - "process-on-spawn": "^1.0.0", - "prop-types": "15.6.0", - "prudence": "0.10.0", - "rate-limit-redis": "2.1.0", - "react": "17.0.2", - "react-async": "10.0.1", - "react-bootstrap": "2.9.0-beta.0", - "react-dom": "17.0.2", - "react-google-recaptcha": "2.1.0", - "react-hot-toast": "2.0.0", - "react-markdown": "7.0.1", - "react-query": "3.18.1", - "react-router-bootstrap": "^0.25.0", - "react-router-dom": "5.1.2", - "react-select": "^5.6.1", - "redis": "3.1.2", - "rg-stats": "1.2.1", - "rimraf": "^3.0.0", - "safe-json-stringify": "1.2.0", - "sass": "1.64.1", - "semver": "^7.3.7", - "seq-logging": "1.1.1", - "signal-exit": "^3.0.0", - "source-map-support": "^0.5.16", - "standard": "^16.0.3", - "supertest": "6.2.2", - "sync-fetch": "^0.3.1", - "tap-mocha-reporter": "^5.0.0", - "tap-parser": "^10.0.1", - "tap-yaml": "^1.0.0", - "tcompare": "^5.0.6", - "treport": "^2.0.2", - "ts-jest": "^27.0.3", - "ts-node": "^8.5.2", - "ts-protoc-gen": "^0.15.0", - "tsconfig-paths": "3.12.0", - "tsd": "^0.17.0", - "typescript": "^4.3.4", - "typescript-eslint": "^8.24.1", - "uuidv7": "^1.1.0", - "vite": "^8.0.0", - "vite-plugin-html": "^3.2.0", - "vitest": "~3.2.0", - "which": "^2.0.2", - "winston": "3.5.1", - "winston-loki": "^6.1.0", - "winston-transport": "4.5.0", - "zod": "^4.3.6" - }, - "packages": { - "@ampproject/remapping": [ - "@ampproject/remapping@2.3.0", - "", - { - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==" - ], - - "@aws-crypto/crc32": [ - "@aws-crypto/crc32@2.0.0", - "", - { - "dependencies": { - "@aws-crypto/util": "^2.0.0", - "@aws-sdk/types": "^3.1.0", - "tslib": "^1.11.1" - } - }, - "sha512-TvE1r2CUueyXOuHdEigYjIZVesInd9KN+K/TFFNfkkxRThiNxO6i4ZqqAVMoEjAamZZ1AA8WXJkjCz7YShHPQA==" - ], - - "@aws-crypto/ie11-detection": [ - "@aws-crypto/ie11-detection@2.0.2", - "", - { "dependencies": { "tslib": "^1.11.1" } }, - "sha512-5XDMQY98gMAf/WRTic5G++jfmS/VLM0rwpiOpaainKi4L0nqWMSB1SzsrEG5rjFZGYN6ZAefO+/Yta2dFM0kMw==" - ], - - "@aws-crypto/sha256-browser": [ - "@aws-crypto/sha256-browser@2.0.0", - "", - { - "dependencies": { - "@aws-crypto/ie11-detection": "^2.0.0", - "@aws-crypto/sha256-js": "^2.0.0", - "@aws-crypto/supports-web-crypto": "^2.0.0", - "@aws-crypto/util": "^2.0.0", - "@aws-sdk/types": "^3.1.0", - "@aws-sdk/util-locate-window": "^3.0.0", - "@aws-sdk/util-utf8-browser": "^3.0.0", - "tslib": "^1.11.1" - } - }, - "sha512-rYXOQ8BFOaqMEHJrLHul/25ckWH6GTJtdLSajhlqGMx0PmSueAuvboCuZCTqEKlxR8CQOwRarxYMZZSYlhRA1A==" - ], - - "@aws-crypto/sha256-js": [ - "@aws-crypto/sha256-js@2.0.0", - "", - { - "dependencies": { - "@aws-crypto/util": "^2.0.0", - "@aws-sdk/types": "^3.1.0", - "tslib": "^1.11.1" - } - }, - "sha512-VZY+mCY4Nmrs5WGfitmNqXzaE873fcIZDu54cbaDaaamsaTOP1DBImV9F4pICc3EHjQXujyE8jig+PFCaew9ig==" - ], - - "@aws-crypto/supports-web-crypto": [ - "@aws-crypto/supports-web-crypto@2.0.2", - "", - { "dependencies": { "tslib": "^1.11.1" } }, - "sha512-6mbSsLHwZ99CTOOswvCRP3C+VCWnzBf+1SnbWxzzJ9lR0mA0JnY2JEAhp8rqmTE0GPFy88rrM27ffgp62oErMQ==" - ], - - "@aws-crypto/util": [ - "@aws-crypto/util@2.0.2", - "", - { - "dependencies": { - "@aws-sdk/types": "^3.110.0", - "@aws-sdk/util-utf8-browser": "^3.0.0", - "tslib": "^1.11.1" - } - }, - "sha512-Lgu5v/0e/BcrZ5m/IWqzPUf3UYFTy/PpeED+uc9SWUR1iZQL8XXbGQg10UfllwwBryO3hFF5dizK+78aoXC1eA==" - ], - - "@aws-sdk/abort-controller": [ - "@aws-sdk/abort-controller@3.49.0", - "", - { "dependencies": { "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, - "sha512-1qLlgOgg3yrtm+AJEP7yoIk90o6ns3Dia8S9DRjj29jY40446etH3v/tIbHPE+em69HLXl1K6e5KD6t7EDxnlg==" - ], - - "@aws-sdk/chunked-blob-reader": [ - "@aws-sdk/chunked-blob-reader@3.49.0", - "", - { "dependencies": { "tslib": "^2.3.0" } }, - "sha512-UI1rK4aBgwsQ6dOQs5Im1cNSb3c/RH1wKjD49zcwWyxe8e96C5G2LcshhVH3onWY5NgqQgs/ffEsXziGcNXRIg==" - ], - - "@aws-sdk/chunked-blob-reader-native": [ - "@aws-sdk/chunked-blob-reader-native@3.49.0", - "", - { "dependencies": { "@aws-sdk/util-base64-browser": "3.49.0", "tslib": "^2.3.0" } }, - "sha512-ppjmDWyufMB41Hmq5Gixd2+/c4kk2IPKKWT9zI9spKOYbbL/vY3FmRq4beQ6n5kWOzDPxKZ6wv04yrMS9yBy1A==" - ], - - "@aws-sdk/client-s3": [ - "@aws-sdk/client-s3@3.49.0", - "", - { - "dependencies": { - "@aws-crypto/sha256-browser": "2.0.0", - "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/client-sts": "3.49.0", - "@aws-sdk/config-resolver": "3.49.0", - "@aws-sdk/credential-provider-node": "3.49.0", - "@aws-sdk/eventstream-serde-browser": "3.49.0", - "@aws-sdk/eventstream-serde-config-resolver": "3.49.0", - "@aws-sdk/eventstream-serde-node": "3.49.0", - "@aws-sdk/fetch-http-handler": "3.49.0", - "@aws-sdk/hash-blob-browser": "3.49.0", - "@aws-sdk/hash-node": "3.49.0", - "@aws-sdk/hash-stream-node": "3.49.0", - "@aws-sdk/invalid-dependency": "3.49.0", - "@aws-sdk/md5-js": "3.49.0", - "@aws-sdk/middleware-apply-body-checksum": "3.49.0", - "@aws-sdk/middleware-bucket-endpoint": "3.49.0", - "@aws-sdk/middleware-content-length": "3.49.0", - "@aws-sdk/middleware-expect-continue": "3.49.0", - "@aws-sdk/middleware-host-header": "3.49.0", - "@aws-sdk/middleware-location-constraint": "3.49.0", - "@aws-sdk/middleware-logger": "3.49.0", - "@aws-sdk/middleware-retry": "3.49.0", - "@aws-sdk/middleware-sdk-s3": "3.49.0", - "@aws-sdk/middleware-serde": "3.49.0", - "@aws-sdk/middleware-signing": "3.49.0", - "@aws-sdk/middleware-ssec": "3.49.0", - "@aws-sdk/middleware-stack": "3.49.0", - "@aws-sdk/middleware-user-agent": "3.49.0", - "@aws-sdk/node-config-provider": "3.49.0", - "@aws-sdk/node-http-handler": "3.49.0", - "@aws-sdk/protocol-http": "3.49.0", - "@aws-sdk/smithy-client": "3.49.0", - "@aws-sdk/types": "3.49.0", - "@aws-sdk/url-parser": "3.49.0", - "@aws-sdk/util-base64-browser": "3.49.0", - "@aws-sdk/util-base64-node": "3.49.0", - "@aws-sdk/util-body-length-browser": "3.49.0", - "@aws-sdk/util-body-length-node": "3.49.0", - "@aws-sdk/util-defaults-mode-browser": "3.49.0", - "@aws-sdk/util-defaults-mode-node": "3.49.0", - "@aws-sdk/util-user-agent-browser": "3.49.0", - "@aws-sdk/util-user-agent-node": "3.49.0", - "@aws-sdk/util-utf8-browser": "3.49.0", - "@aws-sdk/util-utf8-node": "3.49.0", - "@aws-sdk/util-waiter": "3.49.0", - "@aws-sdk/xml-builder": "3.49.0", - "entities": "2.2.0", - "fast-xml-parser": "3.19.0", - "tslib": "^2.3.0" - } - }, - "sha512-LidddhZFxYb/jlEtHnbBpqVZmjgZNKY/jaZy3jRNcVhw8L0m1IYVigqgw5E6ta9/dma5EwLOA8Z21O/rCuDapw==" - ], - - "@aws-sdk/client-sso": [ - "@aws-sdk/client-sso@3.49.0", - "", - { - "dependencies": { - "@aws-crypto/sha256-browser": "2.0.0", - "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/config-resolver": "3.49.0", - "@aws-sdk/fetch-http-handler": "3.49.0", - "@aws-sdk/hash-node": "3.49.0", - "@aws-sdk/invalid-dependency": "3.49.0", - "@aws-sdk/middleware-content-length": "3.49.0", - "@aws-sdk/middleware-host-header": "3.49.0", - "@aws-sdk/middleware-logger": "3.49.0", - "@aws-sdk/middleware-retry": "3.49.0", - "@aws-sdk/middleware-serde": "3.49.0", - "@aws-sdk/middleware-stack": "3.49.0", - "@aws-sdk/middleware-user-agent": "3.49.0", - "@aws-sdk/node-config-provider": "3.49.0", - "@aws-sdk/node-http-handler": "3.49.0", - "@aws-sdk/protocol-http": "3.49.0", - "@aws-sdk/smithy-client": "3.49.0", - "@aws-sdk/types": "3.49.0", - "@aws-sdk/url-parser": "3.49.0", - "@aws-sdk/util-base64-browser": "3.49.0", - "@aws-sdk/util-base64-node": "3.49.0", - "@aws-sdk/util-body-length-browser": "3.49.0", - "@aws-sdk/util-body-length-node": "3.49.0", - "@aws-sdk/util-defaults-mode-browser": "3.49.0", - "@aws-sdk/util-defaults-mode-node": "3.49.0", - "@aws-sdk/util-user-agent-browser": "3.49.0", - "@aws-sdk/util-user-agent-node": "3.49.0", - "@aws-sdk/util-utf8-browser": "3.49.0", - "@aws-sdk/util-utf8-node": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-rY8uZo4DeNwwKf+Sx0TX/5ysXJKf+0SQSCTWD9S4a0AjtiaLc6hKCX+sJY43VDHvNYieKtXLDYHBdhhqZKwG+g==" - ], - - "@aws-sdk/client-sts": [ - "@aws-sdk/client-sts@3.49.0", - "", - { - "dependencies": { - "@aws-crypto/sha256-browser": "2.0.0", - "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/config-resolver": "3.49.0", - "@aws-sdk/credential-provider-node": "3.49.0", - "@aws-sdk/fetch-http-handler": "3.49.0", - "@aws-sdk/hash-node": "3.49.0", - "@aws-sdk/invalid-dependency": "3.49.0", - "@aws-sdk/middleware-content-length": "3.49.0", - "@aws-sdk/middleware-host-header": "3.49.0", - "@aws-sdk/middleware-logger": "3.49.0", - "@aws-sdk/middleware-retry": "3.49.0", - "@aws-sdk/middleware-sdk-sts": "3.49.0", - "@aws-sdk/middleware-serde": "3.49.0", - "@aws-sdk/middleware-signing": "3.49.0", - "@aws-sdk/middleware-stack": "3.49.0", - "@aws-sdk/middleware-user-agent": "3.49.0", - "@aws-sdk/node-config-provider": "3.49.0", - "@aws-sdk/node-http-handler": "3.49.0", - "@aws-sdk/protocol-http": "3.49.0", - "@aws-sdk/smithy-client": "3.49.0", - "@aws-sdk/types": "3.49.0", - "@aws-sdk/url-parser": "3.49.0", - "@aws-sdk/util-base64-browser": "3.49.0", - "@aws-sdk/util-base64-node": "3.49.0", - "@aws-sdk/util-body-length-browser": "3.49.0", - "@aws-sdk/util-body-length-node": "3.49.0", - "@aws-sdk/util-defaults-mode-browser": "3.49.0", - "@aws-sdk/util-defaults-mode-node": "3.49.0", - "@aws-sdk/util-user-agent-browser": "3.49.0", - "@aws-sdk/util-user-agent-node": "3.49.0", - "@aws-sdk/util-utf8-browser": "3.49.0", - "@aws-sdk/util-utf8-node": "3.49.0", - "entities": "2.2.0", - "fast-xml-parser": "3.19.0", - "tslib": "^2.3.0" - } - }, - "sha512-vqHNCuQriMZV1aeXc6cza5S9A/2zgfNiTelsmbDQdlCiZQ+YL3nTp1WFeYHap4ffYlLOAD0xv0yz/+naV4oHtQ==" - ], - - "@aws-sdk/config-resolver": [ - "@aws-sdk/config-resolver@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/signature-v4": "3.49.0", - "@aws-sdk/types": "3.49.0", - "@aws-sdk/util-config-provider": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-4kYV+89E9MG+/wfPY3dmwqzquQxNd951jdfjQbSg1ii68X/owqmWda4bLulV0Z4iGUz9TXkbaJCWyRyjsFNe4w==" - ], - - "@aws-sdk/credential-provider-env": [ - "@aws-sdk/credential-provider-env@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/property-provider": "3.49.0", - "@aws-sdk/types": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-mx82N0un6URmmiM11X3ObK3ka5R99lEFdhwPc0jqsCPnXRVioUtK5DXkJ8FmgixbDcs5Pdij9A8MINSeBrG0bQ==" - ], - - "@aws-sdk/credential-provider-imds": [ - "@aws-sdk/credential-provider-imds@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/node-config-provider": "3.49.0", - "@aws-sdk/property-provider": "3.49.0", - "@aws-sdk/types": "3.49.0", - "@aws-sdk/url-parser": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-d/H5VgmRiIupQdPg9QcX16kdvuiS/YytRYCQOncVstNXHvYZM9EgeIXJLXyPNaD2W8SS7CBf4KKWYJn3V+9AZw==" - ], - - "@aws-sdk/credential-provider-ini": [ - "@aws-sdk/credential-provider-ini@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/credential-provider-env": "3.49.0", - "@aws-sdk/credential-provider-imds": "3.49.0", - "@aws-sdk/credential-provider-sso": "3.49.0", - "@aws-sdk/credential-provider-web-identity": "3.49.0", - "@aws-sdk/property-provider": "3.49.0", - "@aws-sdk/shared-ini-file-loader": "3.49.0", - "@aws-sdk/types": "3.49.0", - "@aws-sdk/util-credentials": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-QlWfxDwZVyX36pghgkKGBR+fBmX/mjmvc0kzxUmqGhUYAkDQ0YKR11ybpGBrxBKT4lIOE+9z6Tu4nLjp3OlJIg==" - ], - - "@aws-sdk/credential-provider-node": [ - "@aws-sdk/credential-provider-node@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/credential-provider-env": "3.49.0", - "@aws-sdk/credential-provider-imds": "3.49.0", - "@aws-sdk/credential-provider-ini": "3.49.0", - "@aws-sdk/credential-provider-process": "3.49.0", - "@aws-sdk/credential-provider-sso": "3.49.0", - "@aws-sdk/credential-provider-web-identity": "3.49.0", - "@aws-sdk/property-provider": "3.49.0", - "@aws-sdk/shared-ini-file-loader": "3.49.0", - "@aws-sdk/types": "3.49.0", - "@aws-sdk/util-credentials": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-DonoqOZHcqfNuwMG1fGJpHJTqf1QinihRKzlOoUWzmseqBCiuagGouSN7nOQgee5BrzF0X9/nao9lnPc4on2TA==" - ], - - "@aws-sdk/credential-provider-process": [ - "@aws-sdk/credential-provider-process@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/property-provider": "3.49.0", - "@aws-sdk/shared-ini-file-loader": "3.49.0", - "@aws-sdk/types": "3.49.0", - "@aws-sdk/util-credentials": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-Zn7CJHoXln8O+yBKdTBvcwCz6GDh48s7HtIsqjoOrqoL0oZWhgy8gn8S9KQ+HIqpiO8N0lMMteXuPl5fbC2zGg==" - ], - - "@aws-sdk/credential-provider-sso": [ - "@aws-sdk/credential-provider-sso@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/client-sso": "3.49.0", - "@aws-sdk/property-provider": "3.49.0", - "@aws-sdk/shared-ini-file-loader": "3.49.0", - "@aws-sdk/types": "3.49.0", - "@aws-sdk/util-credentials": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-sFTqbQOyGR88K10Y1OgauEPKDmEibxtAkLSFjkJ6Yw/Jyp+lftchoa+TxRrNvDY1zjZX+XauVI6UmD5Pi4E1NQ==" - ], - - "@aws-sdk/credential-provider-web-identity": [ - "@aws-sdk/credential-provider-web-identity@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/property-provider": "3.49.0", - "@aws-sdk/types": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-mlIHUTn04unB0HEwEO12YIY5848uE9B+gYI+YwlNZ70KXGs3lj2horOgPgbxeIfulCVw0aRTKChUg2ActTosYg==" - ], - - "@aws-sdk/eventstream-marshaller": [ - "@aws-sdk/eventstream-marshaller@3.49.0", - "", - { - "dependencies": { - "@aws-crypto/crc32": "2.0.0", - "@aws-sdk/types": "3.49.0", - "@aws-sdk/util-hex-encoding": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-EDE7aim4c/G9vCWE+jaHQNWHzrHgF1WlUEok1tgLj+fbvqKduDK/1SNleMZbMLC7tFRARN+KKFB0Ctegyp8j4w==" - ], - - "@aws-sdk/eventstream-serde-browser": [ - "@aws-sdk/eventstream-serde-browser@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/eventstream-marshaller": "3.49.0", - "@aws-sdk/eventstream-serde-universal": "3.49.0", - "@aws-sdk/types": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-XHDHVGmxzEEXzHESzXYiycE3CxHLedBQljQPCIXKJkUhmwf84oUDB/cRsgWoOwOpcRQQBZGUPTPOOOHVWQOlZA==" - ], - - "@aws-sdk/eventstream-serde-config-resolver": [ - "@aws-sdk/eventstream-serde-config-resolver@3.49.0", - "", - { "dependencies": { "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, - "sha512-7xCaQGfZD0xLpWVUsGEQ2PDAkkfnl1gc10h4jLm0xtEGzr0x3B3fLrmDiZTz+wBxRRuCqjiaBaNuPT+HocGYmA==" - ], - - "@aws-sdk/eventstream-serde-node": [ - "@aws-sdk/eventstream-serde-node@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/eventstream-marshaller": "3.49.0", - "@aws-sdk/eventstream-serde-universal": "3.49.0", - "@aws-sdk/types": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-hRZa1QSCtSve3vSgOxtGRn7nlOJFGzaov6hDj+bFEWY6ukHWtG9lbit6ECALcud4BjxvaJet37kqToxnpDFMuQ==" - ], - - "@aws-sdk/eventstream-serde-universal": [ - "@aws-sdk/eventstream-serde-universal@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/eventstream-marshaller": "3.49.0", - "@aws-sdk/types": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-oW/k0QdJTEwRLbdWpakIKABYKEOokBaPd+VSOYmCNceYPzv74RTDqlzTTRVIGj51Jp+Bm1af3l0k1cpjPDnWfQ==" - ], - - "@aws-sdk/fetch-http-handler": [ - "@aws-sdk/fetch-http-handler@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/protocol-http": "3.49.0", - "@aws-sdk/querystring-builder": "3.49.0", - "@aws-sdk/types": "3.49.0", - "@aws-sdk/util-base64-browser": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-ougJRsvoIGP0qTgHSGVF1B5Ui95Y/SP5CpY/y6B8vMGrwJ+MmvcCUE3Qd2UJGjO1PfUneno8PHK4u5x7hc2ceA==" - ], - - "@aws-sdk/hash-blob-browser": [ - "@aws-sdk/hash-blob-browser@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/chunked-blob-reader": "3.49.0", - "@aws-sdk/chunked-blob-reader-native": "3.49.0", - "@aws-sdk/types": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-DLLP8dY0eYAXefJJzAYO1QxHW567MN4D2KDxyOKkWOVR2S6ZLgtJb24MhT9RpV3AOM/x686HOv5V4r1rPbuHhw==" - ], - - "@aws-sdk/hash-node": [ - "@aws-sdk/hash-node@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/types": "3.49.0", - "@aws-sdk/util-buffer-from": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-nRNCmSkcJOzWzKU6NihlKW/6H1HxaaBjUe9ETnwWIgwPC7NZ6IWtri48Cf7Itvveu3dln3ZM2WSXN20TlQpuBw==" - ], - - "@aws-sdk/hash-stream-node": [ - "@aws-sdk/hash-stream-node@3.49.0", - "", - { "dependencies": { "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, - "sha512-ZsqGEs3yp5YH5vk1LhpIiSAzNzXHW89DvKn+BSSiDPdufPdOjLks8wKIVhAUfADcJ+S/AATTAt4SoA4mD+IHvQ==" - ], - - "@aws-sdk/invalid-dependency": [ - "@aws-sdk/invalid-dependency@3.49.0", - "", - { "dependencies": { "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, - "sha512-MXf/9l/Oiy+KGKDvInv0RT4rtS+iNftYRTlTmUn3RR74Kz8Fvw+O0RcUjzSrNn5SpjCf/UsGrF+KBTm2gFYQCA==" - ], - - "@aws-sdk/is-array-buffer": [ - "@aws-sdk/is-array-buffer@3.49.0", - "", - { "dependencies": { "tslib": "^2.3.0" } }, - "sha512-tLba+xvlm1+aAnv+bGieVZo8DCENbqfS9kLf/hp+9hrUSiNAsxs9Pqi34JBpMKGn6h9qORp6f8ClRS+gK8yvWg==" - ], - - "@aws-sdk/md5-js": [ - "@aws-sdk/md5-js@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/types": "3.49.0", - "@aws-sdk/util-utf8-browser": "3.49.0", - "@aws-sdk/util-utf8-node": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-CJJxl7FfTNseaw3RAPmihpys1cfbCyg7sLTev6PncqBhoVl+5AWOoITeZj3azE3CKevY2V7PEdmHjzKRNLmcdA==" - ], - - "@aws-sdk/middleware-apply-body-checksum": [ - "@aws-sdk/middleware-apply-body-checksum@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/is-array-buffer": "3.49.0", - "@aws-sdk/protocol-http": "3.49.0", - "@aws-sdk/types": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-uNUETgYrOLCZNad+vVsTblTqzuaCVCt67o4VawsziR5QuOCxX/27Ni3x1VNtpI5pUhD8FiT/9/lBpcMTvCSIgA==" - ], - - "@aws-sdk/middleware-bucket-endpoint": [ - "@aws-sdk/middleware-bucket-endpoint@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/protocol-http": "3.49.0", - "@aws-sdk/types": "3.49.0", - "@aws-sdk/util-arn-parser": "3.49.0", - "@aws-sdk/util-config-provider": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-6GK6BXNRRe+JpBUomW1Wrj7HGU3gdl9XvrQekj772kmiBLx/40ntAxZnhjFjkNKLy7IM+he8yygnEUhbV/dEmg==" - ], - - "@aws-sdk/middleware-content-length": [ - "@aws-sdk/middleware-content-length@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/protocol-http": "3.49.0", - "@aws-sdk/types": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-7IaghPT7X92gNoyn9LzZj4V5YpGPDCYQTWhpzZoIlw88vOR4I0zKg7jwYeElRoNfRCI4OYhF26ajKnNHzNMlbA==" - ], - - "@aws-sdk/middleware-expect-continue": [ - "@aws-sdk/middleware-expect-continue@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/middleware-header-default": "3.49.0", - "@aws-sdk/protocol-http": "3.49.0", - "@aws-sdk/types": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-i0FMywhvCdn3+gPuUgtM0ZRd3xBHozropbhvs3fu9Y6g1/YiOgTYuVVqHtObvktVWCV72i8fTvn8TEkyFHRDYQ==" - ], - - "@aws-sdk/middleware-header-default": [ - "@aws-sdk/middleware-header-default@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/protocol-http": "3.49.0", - "@aws-sdk/types": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-3xRNPwFMWQqgGKgxDWMgQXNdIr4EVq5ltrLqwsZopXKZli9/fidOrDN9z9j4AW9YAXyEAYB0fscKT7LcsvxFZg==" - ], - - "@aws-sdk/middleware-host-header": [ - "@aws-sdk/middleware-host-header@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/protocol-http": "3.49.0", - "@aws-sdk/types": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-5l1ILqHs2mGqNvJb5mRe7hHbTQOO292jghE/LItpNx2tiu7BBGzP1bslHcyEVYoRBX9Oqyfou7s9Ww2yBWtImQ==" - ], - - "@aws-sdk/middleware-location-constraint": [ - "@aws-sdk/middleware-location-constraint@3.49.0", - "", - { "dependencies": { "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, - "sha512-PUQr06/9XQP0JfUY6nFvK5HHcO4aQbzn/iKvB8dl471IXcKVLnJdB2OuIjUUW6fQbKX1K4xcDEifWTSMIECIlg==" - ], - - "@aws-sdk/middleware-logger": [ - "@aws-sdk/middleware-logger@3.49.0", - "", - { "dependencies": { "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, - "sha512-OicQ0w5sCJXgpeZ+t3XeJA2R/09YfuSe53Ma6aWZm/2/r8vG/SW0yAnwFvwJeCm3DKtBxU1qO2eWhFqvJuWRVA==" - ], - - "@aws-sdk/middleware-retry": [ - "@aws-sdk/middleware-retry@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/protocol-http": "3.49.0", - "@aws-sdk/service-error-classification": "3.49.0", - "@aws-sdk/types": "3.49.0", - "tslib": "^2.3.0", - "uuid": "^8.3.2" - } - }, - "sha512-RSS4R4PNULHA1b1eYR50YPPfOV2jRuXgLNLVVYMEzzC23MabKEXJYPge+pI1Q9rRrbahVj7aQcOTSpT0MsiEeA==" - ], - - "@aws-sdk/middleware-sdk-s3": [ - "@aws-sdk/middleware-sdk-s3@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/protocol-http": "3.49.0", - "@aws-sdk/signature-v4": "3.49.0", - "@aws-sdk/types": "3.49.0", - "@aws-sdk/util-arn-parser": "3.49.0", - "tslib": "^2.3.0" - }, - "peerDependencies": { "@aws-sdk/signature-v4-crt": "^3.31.0" } - }, - "sha512-PeQHJsecGCnXILgOPLgcoZXCa4+2bctus2krhN08ES5oh1obeQB+EOC4v1sWV0DdfyTHEZMDSVLS9qTFHl9IUA==" - ], - - "@aws-sdk/middleware-sdk-sts": [ - "@aws-sdk/middleware-sdk-sts@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/middleware-signing": "3.49.0", - "@aws-sdk/property-provider": "3.49.0", - "@aws-sdk/protocol-http": "3.49.0", - "@aws-sdk/signature-v4": "3.49.0", - "@aws-sdk/types": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-ZnLV37HKpMdK2x+69ZNqAqKr8rmweyMc//yZQRLtUKpKyQ/XSr0/KUBZXkgIny27aaBsrkplA5g1X2GrClRRZA==" - ], - - "@aws-sdk/middleware-serde": [ - "@aws-sdk/middleware-serde@3.49.0", - "", - { "dependencies": { "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, - "sha512-bMAlwR19uFUZ4om+U+/vnPvkcyYw83HdtERF9wrjAqNUnqYsifA0xn4R7Sakg6CW8V0h82dsST6zVfmHd+E2VA==" - ], - - "@aws-sdk/middleware-signing": [ - "@aws-sdk/middleware-signing@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/property-provider": "3.49.0", - "@aws-sdk/protocol-http": "3.49.0", - "@aws-sdk/signature-v4": "3.49.0", - "@aws-sdk/types": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-9p0xZjxV9zEQdOpA4MtzmblPRUgchevg5Q70E23yAU/Wjwzwf/6J93cUxdcS8HnmOIl0zQjJaYMTcBsvgJF1eg==" - ], - - "@aws-sdk/middleware-ssec": [ - "@aws-sdk/middleware-ssec@3.49.0", - "", - { "dependencies": { "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, - "sha512-S7hfgOCYoqPe4YegSnwhQJ0KBVEhP6dIp7yLa1/yCJkqW2KSnLTvg6ao9vEFf/lhctZ72YZjm8v/2siXWCnDEA==" - ], - - "@aws-sdk/middleware-stack": [ - "@aws-sdk/middleware-stack@3.49.0", - "", - { "dependencies": { "tslib": "^2.3.0" } }, - "sha512-OZxs2P7EH58gkvkTI7ESlUPGam0TkE0ZxOX35KjCOcYMuWvTMshKBzHRLX64nz3DYdaHSIGHgB1v8LKELZjltw==" - ], - - "@aws-sdk/middleware-user-agent": [ - "@aws-sdk/middleware-user-agent@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/protocol-http": "3.49.0", - "@aws-sdk/types": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-uAcKgafZ12L8UnyeQGgSFtwOKUfiBWDLt4P2fEHvZRz/HAIcK4pu1PXPArjwteinhUiCDNFfPw8hAPvstMoG6w==" - ], - - "@aws-sdk/node-config-provider": [ - "@aws-sdk/node-config-provider@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/property-provider": "3.49.0", - "@aws-sdk/shared-ini-file-loader": "3.49.0", - "@aws-sdk/types": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-OCn5c6M/RJDEO80Q+Iy4ADSYgqd/uyEsvp+7lU4di4bMND9kYT4JO2ky2SWjIuARGq/mhMOhaN2DO9MbcqV20g==" - ], - - "@aws-sdk/node-http-handler": [ - "@aws-sdk/node-http-handler@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/abort-controller": "3.49.0", - "@aws-sdk/protocol-http": "3.49.0", - "@aws-sdk/querystring-builder": "3.49.0", - "@aws-sdk/types": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-t7D9hoSigBihC9RRgYrkzgSER0fYzZe7192pJAaP6jk13ZOpccQRfXZoKge/cm42aHJsTy8DdQdGtLg7wLTp0g==" - ], - - "@aws-sdk/property-provider": [ - "@aws-sdk/property-provider@3.49.0", - "", - { "dependencies": { "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, - "sha512-6D48YpriOUpniezVuRI8J+MG+vgwb5C1SzBdgN4+S6DqbsEZy+kdEubXdoMICEd+Z8h7lH3p5zMr6po0icGCfA==" - ], - - "@aws-sdk/protocol-http": [ - "@aws-sdk/protocol-http@3.49.0", - "", - { "dependencies": { "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, - "sha512-lb9CO7/vm26v4UwveWb4jSapqWWP/p0b9SuHpRExq+yMuvHqwxcoGrxmvS7FsanWbepRF1895dxU/Ar6/4pviA==" - ], - - "@aws-sdk/querystring-builder": [ - "@aws-sdk/querystring-builder@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/types": "3.49.0", - "@aws-sdk/util-uri-escape": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-+NlgIYihVyUetZcrF1ADY0eg8WW1/ETD5bzTwguTiKduXVHmavSakXK1jJF5vg05mefljToZXjQnOaEs9+K9LA==" - ], - - "@aws-sdk/querystring-parser": [ - "@aws-sdk/querystring-parser@3.49.0", - "", - { "dependencies": { "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, - "sha512-4bSCHI5A8wi+JjsD1gAhMuGRGjDmlw6MoMWUiv4R2J8Ow/9mV8biKRo2ZytUPiSSu4G5JQ7mEkqFsm/VgkstDQ==" - ], - - "@aws-sdk/service-error-classification": [ - "@aws-sdk/service-error-classification@3.49.0", - "", - {}, - "sha512-iVmf7RcrIsM/We5ip8fe14RzEpSLF5eN8oqhCMftEdmMVnOYMd/9x0f1w69fbyBJNIIpyREqM8eAKz5OWQn5/g==" - ], - - "@aws-sdk/shared-ini-file-loader": [ - "@aws-sdk/shared-ini-file-loader@3.49.0", - "", - { "dependencies": { "tslib": "^2.3.0" } }, - "sha512-TcgKU6U/3JZpenRFhGSy5R5QsBWkYoeawTK1rTK6deu3UbxVwtOkietbfwP3kIwKZ4hz6OkNeHcOJtXX/InZKw==" - ], - - "@aws-sdk/signature-v4": [ - "@aws-sdk/signature-v4@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/is-array-buffer": "3.49.0", - "@aws-sdk/types": "3.49.0", - "@aws-sdk/util-hex-encoding": "3.49.0", - "@aws-sdk/util-uri-escape": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-mQSGclWmv/9/MsgthBuKMHN6nkkhGTLXspkhqJ9xSUhjhoaHQVwMoJc39PowJGbYFn1AtCvHAqJtFXTGsMRwPA==" - ], - - "@aws-sdk/signature-v4-crt": [ - "@aws-sdk/signature-v4-crt@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/is-array-buffer": "3.49.0", - "@aws-sdk/querystring-parser": "3.49.0", - "@aws-sdk/signature-v4": "3.49.0", - "@aws-sdk/util-hex-encoding": "3.49.0", - "@aws-sdk/util-uri-escape": "3.49.0", - "aws-crt": "^1.9.7", - "tslib": "^2.3.0" - } - }, - "sha512-jTHX6kNBV4ulj3y7klUznsmb8SsSz1IcDoorYftuVcGZsXtRsd96XSsPA9NSWHWtAj+1O7iQ28u4nRV7d04WdA==" - ], - - "@aws-sdk/smithy-client": [ - "@aws-sdk/smithy-client@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/middleware-stack": "3.49.0", - "@aws-sdk/types": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-ANh9SlEvuru1DcalVoQ7K6wSCYuw4jyeTsIDsJSa13ckrmXAg+ql9vq61ELAXTSNVmuAISuuPjbVaWvOYCtdCQ==" - ], - - "@aws-sdk/types": [ - "@aws-sdk/types@3.49.0", - "", - {}, - "sha512-8bCqEpquTlPN6xkjaJ+s+RoEFIu5r4G8oXOsQ5HYBvBdpx62HnCqzHLFNHycL2b8sE+VysQgNvmdQYR98vdMGQ==" - ], - - "@aws-sdk/url-parser": [ - "@aws-sdk/url-parser@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/querystring-parser": "3.49.0", - "@aws-sdk/types": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-l5td6eu+sIjzNsZYVGr7Mz6vssf2j/8/QrrTYF76J2R6OoceCsKdyJgJPP/tXBdcp4HUZDdVcMqtWRbxGC4izQ==" - ], - - "@aws-sdk/util-arn-parser": [ - "@aws-sdk/util-arn-parser@3.49.0", - "", - { "dependencies": { "tslib": "^2.3.0" } }, - "sha512-mAF4lzxqMUFMQAf+NQSxW7jC5hYXNM7mPItBFs/yI3F25MXBw88Q+wAof7iIyRnRcpJvgZ3I7P8vJriAwrSbFg==" - ], - - "@aws-sdk/util-base64-browser": [ - "@aws-sdk/util-base64-browser@3.49.0", - "", - { "dependencies": { "tslib": "^2.3.0" } }, - "sha512-HFXJbsJC6AfrnO9M8KuFDo4ihvLbCbCFCfpWy0Gs4t8kTcvGqH8fIpfVsQKAtFHMmb8fen2LduOk+NNSA7srYw==" - ], - - "@aws-sdk/util-base64-node": [ - "@aws-sdk/util-base64-node@3.49.0", - "", - { "dependencies": { "@aws-sdk/util-buffer-from": "3.49.0", "tslib": "^2.3.0" } }, - "sha512-xFAzOLZJOEZipG3KVLjB5z1g5PJSi6cmZOGWg2NC2/H5N0/Z+e5ObnIH8mpfO1d6kWchUuo3qJ6fTOvg/ynw7A==" - ], - - "@aws-sdk/util-body-length-browser": [ - "@aws-sdk/util-body-length-browser@3.49.0", - "", - { "dependencies": { "tslib": "^2.3.0" } }, - "sha512-4a9Bw33JGKefaZDORlosQRMKxJGEYEiDD5kgNvwIv+KRl5yj2unePia6aFWMqXTWqidOb9WVlqc0Lh73ei5pTg==" - ], - - "@aws-sdk/util-body-length-node": [ - "@aws-sdk/util-body-length-node@3.49.0", - "", - { "dependencies": { "tslib": "^2.3.0" } }, - "sha512-ME5Sc8jo9BzToUjWskQKZM/NqN9PpwRDTOSH6EISDBUiH5bhWfY8MLkZqIN2UZz/XOiV3yOeWAU+fMYNnGdAQQ==" - ], - - "@aws-sdk/util-buffer-from": [ - "@aws-sdk/util-buffer-from@3.49.0", - "", - { "dependencies": { "@aws-sdk/is-array-buffer": "3.49.0", "tslib": "^2.3.0" } }, - "sha512-8JbIPYn91f+16QpDk000PdIBlBZu8/SoL1nF2fpAJ+M98jXpKUws3oiCztJ2FPIKRe/3ikKuZM4HxWrDyJa40Q==" - ], - - "@aws-sdk/util-config-provider": [ - "@aws-sdk/util-config-provider@3.49.0", - "", - { "dependencies": { "tslib": "^2.3.0" } }, - "sha512-oVGT9q9UIGdv9Cra4B51QNciWKYQXTlfh8oD2FgLp91NbGTIkQLvK7Pah4TbBoa5+0u/obBI07UwCVn7wphWBQ==" - ], - - "@aws-sdk/util-credentials": [ - "@aws-sdk/util-credentials@3.49.0", - "", - { "dependencies": { "@aws-sdk/shared-ini-file-loader": "3.49.0", "tslib": "^2.3.0" } }, - "sha512-RzbKeuylb56m0zPuLGl5/TkN07+c4PKhZu3hikpsvN8n8n7aFHWPUus63QEGgVaUMCZD0QV6HqJfsCVVFF7UIg==" - ], - - "@aws-sdk/util-defaults-mode-browser": [ - "@aws-sdk/util-defaults-mode-browser@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/property-provider": "3.49.0", - "@aws-sdk/types": "3.49.0", - "bowser": "^2.11.0", - "tslib": "^2.3.0" - } - }, - "sha512-MNOvFET5TNBHgvsmfcLuxVDDUV0OIjE1lxrdbXWol7bMgLc2uL3/QOXWKCOUzcFCqTOnWCvbnwkOjs3f7Dpzmw==" - ], - - "@aws-sdk/util-defaults-mode-node": [ - "@aws-sdk/util-defaults-mode-node@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/config-resolver": "3.49.0", - "@aws-sdk/credential-provider-imds": "3.49.0", - "@aws-sdk/node-config-provider": "3.49.0", - "@aws-sdk/property-provider": "3.49.0", - "@aws-sdk/types": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-bd5/ZJlNIX25n83mvcCh9eYQiDdf6gLHNH6ZftA/EbFfkE0o/qHrFhBhiB9HBY9ZoHhtoqrJNv5W9qKFHx1EIA==" - ], - - "@aws-sdk/util-hex-encoding": [ - "@aws-sdk/util-hex-encoding@3.49.0", - "", - { "dependencies": { "tslib": "^2.3.0" } }, - "sha512-ZbPu8Dd3Qm0BMP71FWUH7KPpZA/6izfkDlxbvHxtHdW7XYZALuJ0cVRpWGIY2fCSuA9X8Jfn60KMyjuSAuzM1w==" - ], - - "@aws-sdk/util-locate-window": [ - "@aws-sdk/util-locate-window@3.965.5", - "", - { "dependencies": { "tslib": "^2.6.2" } }, - "sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ==" - ], - - "@aws-sdk/util-uri-escape": [ - "@aws-sdk/util-uri-escape@3.49.0", - "", - { "dependencies": { "tslib": "^2.3.0" } }, - "sha512-NH7iQUYvijYZEOzZkF/QQrp8kBOA9H0Z89hR/63FDCjr1M0Cdcs1bLaFO0a0qbW9NQtoYNsMBMk7pTveDrAzTw==" - ], - - "@aws-sdk/util-user-agent-browser": [ - "@aws-sdk/util-user-agent-browser@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/types": "3.49.0", - "bowser": "^2.11.0", - "tslib": "^2.3.0" - } - }, - "sha512-RR4E6WlDSu9SivPjx/Jddo87PeVg6dhRL0XGdDBpew7i8bfwqCvxQydkbWIetxucLrt9zII9QnLDQUPBue1xUw==" - ], - - "@aws-sdk/util-user-agent-node": [ - "@aws-sdk/util-user-agent-node@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/node-config-provider": "3.49.0", - "@aws-sdk/types": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-ixUkF6kcDfsWO0kivyOKAnBITJm7InGa04ALbgAfuuE7RU1cVkXVMFIn5vux7QkziK7+JwozM9SNPIwNukElDw==" - ], - - "@aws-sdk/util-utf8-browser": [ - "@aws-sdk/util-utf8-browser@3.49.0", - "", - { "dependencies": { "tslib": "^2.3.0" } }, - "sha512-u9ZgAiTWX9yZFQ/ptlnVpYJ/rXF7aE2Wagar1IjhZrnxXbpVJvcX1EeRayxI1P5AAp2y2fiEKHZzX9ugTwOcEg==" - ], - - "@aws-sdk/util-utf8-node": [ - "@aws-sdk/util-utf8-node@3.49.0", - "", - { "dependencies": { "@aws-sdk/util-buffer-from": "3.49.0", "tslib": "^2.3.0" } }, - "sha512-QTF5b5OT2y6xsQl8sDiiXqg2n/VtgqFA+tP3WMooOSFd/ZFBbT6HoiSHXHMeTjpB/L9ZT+eUaCoBz8Jq09lBDg==" - ], - - "@aws-sdk/util-waiter": [ - "@aws-sdk/util-waiter@3.49.0", - "", - { - "dependencies": { - "@aws-sdk/abort-controller": "3.49.0", - "@aws-sdk/types": "3.49.0", - "tslib": "^2.3.0" - } - }, - "sha512-eKrKOLcIhjA/MyjIfwgLL6ZUfGYf6VxBXryuRf8CmJKAo71ZO6ipAsy1X3uYrfwQQBMKV4VZu48BJx5PUBM7GA==" - ], - - "@aws-sdk/xml-builder": [ - "@aws-sdk/xml-builder@3.49.0", - "", - { "dependencies": { "tslib": "^2.3.0" } }, - "sha512-eU5sIZRWq8pNmw++RfpFI8396UtDW8JxYLcKfJLGQC/qDhwCo+sNPKydXFmDrXTIt/khs3K0qx/vZ5V76irc2Q==" - ], - - "@babel/code-frame": [ - "@babel/code-frame@7.29.0", - "", - { - "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - } - }, - "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==" - ], - - "@babel/compat-data": [ - "@babel/compat-data@7.29.0", - "", - {}, - "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==" - ], - - "@babel/core": [ - "@babel/core@7.29.0", - "", - { - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - } - }, - "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==" - ], - - "@babel/generator": [ - "@babel/generator@7.29.1", - "", - { - "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - } - }, - "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==" - ], - - "@babel/helper-annotate-as-pure": [ - "@babel/helper-annotate-as-pure@7.27.3", - "", - { "dependencies": { "@babel/types": "^7.27.3" } }, - "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==" - ], - - "@babel/helper-compilation-targets": [ - "@babel/helper-compilation-targets@7.28.6", - "", - { - "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - } - }, - "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==" - ], - - "@babel/helper-globals": [ - "@babel/helper-globals@7.28.0", - "", - {}, - "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==" - ], - - "@babel/helper-module-imports": [ - "@babel/helper-module-imports@7.28.6", - "", - { "dependencies": { "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6" } }, - "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==" - ], - - "@babel/helper-module-transforms": [ - "@babel/helper-module-transforms@7.28.6", - "", - { - "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" - }, - "peerDependencies": { "@babel/core": "^7.0.0" } - }, - "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==" - ], - - "@babel/helper-plugin-utils": [ - "@babel/helper-plugin-utils@7.28.6", - "", - {}, - "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==" - ], - - "@babel/helper-string-parser": [ - "@babel/helper-string-parser@7.27.1", - "", - {}, - "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==" - ], - - "@babel/helper-validator-identifier": [ - "@babel/helper-validator-identifier@7.28.5", - "", - {}, - "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==" - ], - - "@babel/helper-validator-option": [ - "@babel/helper-validator-option@7.27.1", - "", - {}, - "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==" - ], - - "@babel/helpers": [ - "@babel/helpers@7.28.6", - "", - { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.28.6" } }, - "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==" - ], - - "@babel/parser": [ - "@babel/parser@7.29.0", - "", - { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, - "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==" - ], - - "@babel/plugin-proposal-object-rest-spread": [ - "@babel/plugin-proposal-object-rest-spread@7.20.7", - "", - { - "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.20.7" - }, - "peerDependencies": { "@babel/core": "^7.0.0-0" } - }, - "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==" - ], - - "@babel/plugin-syntax-jsx": [ - "@babel/plugin-syntax-jsx@7.28.6", - "", - { - "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, - "peerDependencies": { "@babel/core": "^7.0.0-0" } - }, - "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==" - ], - - "@babel/plugin-syntax-object-rest-spread": [ - "@babel/plugin-syntax-object-rest-spread@7.8.3", - "", - { - "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, - "peerDependencies": { "@babel/core": "^7.0.0-0" } - }, - "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==" - ], - - "@babel/plugin-transform-destructuring": [ - "@babel/plugin-transform-destructuring@7.28.5", - "", - { - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.5" - }, - "peerDependencies": { "@babel/core": "^7.0.0-0" } - }, - "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==" - ], - - "@babel/plugin-transform-parameters": [ - "@babel/plugin-transform-parameters@7.27.7", - "", - { - "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, - "peerDependencies": { "@babel/core": "^7.0.0-0" } - }, - "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==" - ], - - "@babel/plugin-transform-react-jsx": [ - "@babel/plugin-transform-react-jsx@7.28.6", - "", - { - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/plugin-syntax-jsx": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "peerDependencies": { "@babel/core": "^7.0.0-0" } - }, - "sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==" - ], - - "@babel/runtime": [ - "@babel/runtime@7.28.6", - "", - {}, - "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==" - ], - - "@babel/template": [ - "@babel/template@7.28.6", - "", - { - "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" - } - }, - "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==" - ], - - "@babel/traverse": [ - "@babel/traverse@7.29.0", - "", - { - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", - "debug": "^4.3.1" - } - }, - "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==" - ], - - "@babel/types": [ - "@babel/types@7.29.0", - "", - { - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - } - }, - "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==" - ], - - "@bcoe/v8-coverage": [ - "@bcoe/v8-coverage@1.0.2", - "", - {}, - "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==" - ], - - "@biomejs/biome": [ - "@biomejs/biome@2.4.6", - "", - { - "optionalDependencies": { - "@biomejs/cli-darwin-arm64": "2.4.6", - "@biomejs/cli-darwin-x64": "2.4.6", - "@biomejs/cli-linux-arm64": "2.4.6", - "@biomejs/cli-linux-arm64-musl": "2.4.6", - "@biomejs/cli-linux-x64": "2.4.6", - "@biomejs/cli-linux-x64-musl": "2.4.6", - "@biomejs/cli-win32-arm64": "2.4.6", - "@biomejs/cli-win32-x64": "2.4.6" - }, - "bin": { "biome": "bin/biome" } - }, - "sha512-QnHe81PMslpy3mnpL8DnO2M4S4ZnYPkjlGCLWBZT/3R9M6b5daArWMMtEfP52/n174RKnwRIf3oT8+wc9ihSfQ==" - ], - - "@biomejs/cli-darwin-arm64": [ - "@biomejs/cli-darwin-arm64@2.4.6", - "", - { "os": "darwin", "cpu": "arm64" }, - "sha512-NW18GSyxr+8sJIqgoGwVp5Zqm4SALH4b4gftIA0n62PTuBs6G2tHlwNAOj0Vq0KKSs7Sf88VjjmHh0O36EnzrQ==" - ], - - "@biomejs/cli-darwin-x64": [ - "@biomejs/cli-darwin-x64@2.4.6", - "", - { "os": "darwin", "cpu": "x64" }, - "sha512-4uiE/9tuI7cnjtY9b07RgS7gGyYOAfIAGeVJWEfeCnAarOAS7qVmuRyX6d7JTKw28/mt+rUzMasYeZ+0R/U1Mw==" - ], - - "@biomejs/cli-linux-arm64": [ - "@biomejs/cli-linux-arm64@2.4.6", - "", - { "os": "linux", "cpu": "arm64" }, - "sha512-kMLaI7OF5GN1Q8Doymjro1P8rVEoy7BKQALNz6fiR8IC1WKduoNyteBtJlHT7ASIL0Cx2jR6VUOBIbcB1B8pew==" - ], - - "@biomejs/cli-linux-arm64-musl": [ - "@biomejs/cli-linux-arm64-musl@2.4.6", - "", - { "os": "linux", "cpu": "arm64" }, - "sha512-F/JdB7eN22txiTqHM5KhIVt0jVkzZwVYrdTR1O3Y4auBOQcXxHK4dxULf4z43QyZI5tsnQJrRBHZy7wwtL+B3A==" - ], - - "@biomejs/cli-linux-x64": [ - "@biomejs/cli-linux-x64@2.4.6", - "", - { "os": "linux", "cpu": "x64" }, - "sha512-oHXmUFEoH8Lql1xfc3QkFLiC1hGR7qedv5eKNlC185or+o4/4HiaU7vYODAH3peRCfsuLr1g6v2fK9dFFOYdyw==" - ], - - "@biomejs/cli-linux-x64-musl": [ - "@biomejs/cli-linux-x64-musl@2.4.6", - "", - { "os": "linux", "cpu": "x64" }, - "sha512-C9s98IPDu7DYarjlZNuzJKTjVHN03RUnmHV5htvqsx6vEUXCDSJ59DNwjKVD5XYoSS4N+BYhq3RTBAL8X6svEg==" - ], - - "@biomejs/cli-win32-arm64": [ - "@biomejs/cli-win32-arm64@2.4.6", - "", - { "os": "win32", "cpu": "arm64" }, - "sha512-xzThn87Pf3YrOGTEODFGONmqXpTwUNxovQb72iaUOdcw8sBSY3+3WD8Hm9IhMYLnPi0n32s3L3NWU6+eSjfqFg==" - ], - - "@biomejs/cli-win32-x64": [ - "@biomejs/cli-win32-x64@2.4.6", - "", - { "os": "win32", "cpu": "x64" }, - "sha512-7++XhnsPlr1HDbor5amovPjOH6vsrFOCdp93iKXhFn6bcMUI6soodj3WWKfgEO6JosKU1W5n3uky3WW9RlRjTg==" - ], - - "bliss": ["bliss@workspace:typescript/bliss"], - - "@colors/colors": [ - "@colors/colors@1.6.0", - "", - {}, - "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==" - ], - - "@cspotcode/source-map-support": [ - "@cspotcode/source-map-support@0.8.1", - "", - { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, - "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==" - ], - - "@dabh/diagnostics": [ - "@dabh/diagnostics@2.0.8", - "", - { - "dependencies": { - "@so-ric/colorspace": "^1.1.6", - "enabled": "2.0.x", - "kuler": "^2.0.0" - } - }, - "sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q==" - ], - - "@discordjs/builders": [ - "@discordjs/builders@0.5.0", - "", - { - "dependencies": { - "@sindresorhus/is": "^4.0.1", - "discord-api-types": "^0.22.0", - "ow": "^0.27.0", - "ts-mixer": "^6.0.0", - "tslib": "^2.3.0" - } - }, - "sha512-HP5y4Rqw68o61Qv4qM5tVmDbWi4mdTFftqIOGRo33SNPpLJ1Ga3KEIR2ibKofkmsoQhEpLmopD1AZDs3cKpHuw==" - ], - - "@discordjs/collection": [ - "@discordjs/collection@0.1.6", - "", - {}, - "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ==" - ], - - "@discordjs/rest": [ - "@discordjs/rest@0.1.0-canary.0", - "", - { - "dependencies": { - "@discordjs/collection": "^0.1.6", - "@sapphire/async-queue": "^1.1.4", - "@sapphire/snowflake": "^1.3.5", - "abort-controller": "^3.0.0", - "discord-api-types": "^0.18.1", - "form-data": "^4.0.0", - "node-fetch": "^2.6.1", - "tslib": "^2.3.0" - } - }, - "sha512-d+s//ISYVV+e0w/926wMEeO7vju+Pn11x1JM4tcmVMCHSDgpi6pnFCNAXF1TEdnDcy7xf9tq5cf2pQkb/7ySTQ==" - ], - - "@electric-sql/pglite": [ - "@electric-sql/pglite@0.3.15", - "", - {}, - "sha512-Cj++n1Mekf9ETfdc16TlDi+cDDQF0W7EcbyRHYOAeZdsAe8M/FJg18itDTSwyHfar2WIezawM9o0EKaRGVKygQ==" - ], - - "@emnapi/core": [ - "@emnapi/core@1.8.1", - "", - { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, - "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==" - ], - - "@emnapi/runtime": [ - "@emnapi/runtime@1.8.1", - "", - { "dependencies": { "tslib": "^2.4.0" } }, - "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==" - ], - - "@emnapi/wasi-threads": [ - "@emnapi/wasi-threads@1.1.0", - "", - { "dependencies": { "tslib": "^2.4.0" } }, - "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==" - ], - - "@emotion/babel-plugin": [ - "@emotion/babel-plugin@11.13.5", - "", - { - "dependencies": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/runtime": "^7.18.3", - "@emotion/hash": "^0.9.2", - "@emotion/memoize": "^0.9.0", - "@emotion/serialize": "^1.3.3", - "babel-plugin-macros": "^3.1.0", - "convert-source-map": "^1.5.0", - "escape-string-regexp": "^4.0.0", - "find-root": "^1.1.0", - "source-map": "^0.5.7", - "stylis": "4.2.0" - } - }, - "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==" - ], - - "@emotion/cache": [ - "@emotion/cache@11.14.0", - "", - { - "dependencies": { - "@emotion/memoize": "^0.9.0", - "@emotion/sheet": "^1.4.0", - "@emotion/utils": "^1.4.2", - "@emotion/weak-memoize": "^0.4.0", - "stylis": "4.2.0" - } - }, - "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==" - ], - - "@emotion/hash": [ - "@emotion/hash@0.9.2", - "", - {}, - "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==" - ], - - "@emotion/memoize": [ - "@emotion/memoize@0.9.0", - "", - {}, - "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" - ], - - "@emotion/react": [ - "@emotion/react@11.14.0", - "", - { - "dependencies": { - "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.13.5", - "@emotion/cache": "^11.14.0", - "@emotion/serialize": "^1.3.3", - "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", - "@emotion/utils": "^1.4.2", - "@emotion/weak-memoize": "^0.4.0", - "hoist-non-react-statics": "^3.3.1" - }, - "peerDependencies": { "react": ">=16.8.0" } - }, - "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==" - ], - - "@emotion/serialize": [ - "@emotion/serialize@1.3.3", - "", - { - "dependencies": { - "@emotion/hash": "^0.9.2", - "@emotion/memoize": "^0.9.0", - "@emotion/unitless": "^0.10.0", - "@emotion/utils": "^1.4.2", - "csstype": "^3.0.2" - } - }, - "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==" - ], - - "@emotion/sheet": [ - "@emotion/sheet@1.4.0", - "", - {}, - "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==" - ], - - "@emotion/unitless": [ - "@emotion/unitless@0.10.0", - "", - {}, - "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==" - ], - - "@emotion/use-insertion-effect-with-fallbacks": [ - "@emotion/use-insertion-effect-with-fallbacks@1.2.0", - "", - { "peerDependencies": { "react": ">=16.8.0" } }, - "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==" - ], - - "@emotion/utils": [ - "@emotion/utils@1.4.2", - "", - {}, - "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==" - ], - - "@emotion/weak-memoize": [ - "@emotion/weak-memoize@0.4.0", - "", - {}, - "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" - ], - - "@esbuild/aix-ppc64": [ - "@esbuild/aix-ppc64@0.27.3", - "", - { "os": "aix", "cpu": "ppc64" }, - "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==" - ], - - "@esbuild/android-arm": [ - "@esbuild/android-arm@0.27.3", - "", - { "os": "android", "cpu": "arm" }, - "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==" - ], - - "@esbuild/android-arm64": [ - "@esbuild/android-arm64@0.27.3", - "", - { "os": "android", "cpu": "arm64" }, - "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==" - ], - - "@esbuild/android-x64": [ - "@esbuild/android-x64@0.27.3", - "", - { "os": "android", "cpu": "x64" }, - "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==" - ], - - "@esbuild/darwin-arm64": [ - "@esbuild/darwin-arm64@0.27.3", - "", - { "os": "darwin", "cpu": "arm64" }, - "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==" - ], - - "@esbuild/darwin-x64": [ - "@esbuild/darwin-x64@0.27.3", - "", - { "os": "darwin", "cpu": "x64" }, - "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==" - ], - - "@esbuild/freebsd-arm64": [ - "@esbuild/freebsd-arm64@0.27.3", - "", - { "os": "freebsd", "cpu": "arm64" }, - "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==" - ], - - "@esbuild/freebsd-x64": [ - "@esbuild/freebsd-x64@0.27.3", - "", - { "os": "freebsd", "cpu": "x64" }, - "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==" - ], - - "@esbuild/linux-arm": [ - "@esbuild/linux-arm@0.27.3", - "", - { "os": "linux", "cpu": "arm" }, - "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==" - ], - - "@esbuild/linux-arm64": [ - "@esbuild/linux-arm64@0.27.3", - "", - { "os": "linux", "cpu": "arm64" }, - "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==" - ], - - "@esbuild/linux-ia32": [ - "@esbuild/linux-ia32@0.27.3", - "", - { "os": "linux", "cpu": "ia32" }, - "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==" - ], - - "@esbuild/linux-loong64": [ - "@esbuild/linux-loong64@0.27.3", - "", - { "os": "linux", "cpu": "none" }, - "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==" - ], - - "@esbuild/linux-mips64el": [ - "@esbuild/linux-mips64el@0.27.3", - "", - { "os": "linux", "cpu": "none" }, - "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==" - ], - - "@esbuild/linux-ppc64": [ - "@esbuild/linux-ppc64@0.27.3", - "", - { "os": "linux", "cpu": "ppc64" }, - "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==" - ], - - "@esbuild/linux-riscv64": [ - "@esbuild/linux-riscv64@0.27.3", - "", - { "os": "linux", "cpu": "none" }, - "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==" - ], - - "@esbuild/linux-s390x": [ - "@esbuild/linux-s390x@0.27.3", - "", - { "os": "linux", "cpu": "s390x" }, - "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==" - ], - - "@esbuild/linux-x64": [ - "@esbuild/linux-x64@0.27.3", - "", - { "os": "linux", "cpu": "x64" }, - "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==" - ], - - "@esbuild/netbsd-arm64": [ - "@esbuild/netbsd-arm64@0.27.3", - "", - { "os": "none", "cpu": "arm64" }, - "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==" - ], - - "@esbuild/netbsd-x64": [ - "@esbuild/netbsd-x64@0.27.3", - "", - { "os": "none", "cpu": "x64" }, - "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==" - ], - - "@esbuild/openbsd-arm64": [ - "@esbuild/openbsd-arm64@0.27.3", - "", - { "os": "openbsd", "cpu": "arm64" }, - "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==" - ], - - "@esbuild/openbsd-x64": [ - "@esbuild/openbsd-x64@0.27.3", - "", - { "os": "openbsd", "cpu": "x64" }, - "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==" - ], - - "@esbuild/openharmony-arm64": [ - "@esbuild/openharmony-arm64@0.27.3", - "", - { "os": "none", "cpu": "arm64" }, - "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==" - ], - - "@esbuild/sunos-x64": [ - "@esbuild/sunos-x64@0.27.3", - "", - { "os": "sunos", "cpu": "x64" }, - "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==" - ], - - "@esbuild/win32-arm64": [ - "@esbuild/win32-arm64@0.27.3", - "", - { "os": "win32", "cpu": "arm64" }, - "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==" - ], - - "@esbuild/win32-ia32": [ - "@esbuild/win32-ia32@0.27.3", - "", - { "os": "win32", "cpu": "ia32" }, - "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==" - ], - - "@esbuild/win32-x64": [ - "@esbuild/win32-x64@0.27.3", - "", - { "os": "win32", "cpu": "x64" }, - "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==" - ], - - "@eslint-community/eslint-utils": [ - "@eslint-community/eslint-utils@4.9.1", - "", - { - "dependencies": { "eslint-visitor-keys": "^3.4.3" }, - "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } - }, - "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==" - ], - - "@eslint-community/regexpp": [ - "@eslint-community/regexpp@4.12.2", - "", - {}, - "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==" - ], - - "@eslint/config-array": [ - "@eslint/config-array@0.21.2", - "", - { - "dependencies": { - "@eslint/object-schema": "^2.1.7", - "debug": "^4.3.1", - "minimatch": "^3.1.5" - } - }, - "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==" - ], - - "@eslint/config-helpers": [ - "@eslint/config-helpers@0.4.2", - "", - { "dependencies": { "@eslint/core": "^0.17.0" } }, - "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==" - ], - - "@eslint/core": [ - "@eslint/core@0.17.0", - "", - { "dependencies": { "@types/json-schema": "^7.0.15" } }, - "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==" - ], - - "@eslint/eslintrc": [ - "@eslint/eslintrc@3.3.5", - "", - { - "dependencies": { - "ajv": "^6.14.0", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", - "minimatch": "^3.1.5", - "strip-json-comments": "^3.1.1" - } - }, - "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==" - ], - - "@eslint/js": [ - "@eslint/js@9.39.4", - "", - {}, - "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==" - ], - - "@eslint/object-schema": [ - "@eslint/object-schema@2.1.7", - "", - {}, - "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==" - ], - - "@eslint/plugin-kit": [ - "@eslint/plugin-kit@0.4.1", - "", - { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, - "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==" - ], - - "@floating-ui/core": [ - "@floating-ui/core@1.7.5", - "", - { "dependencies": { "@floating-ui/utils": "^0.2.11" } }, - "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==" - ], - - "@floating-ui/dom": [ - "@floating-ui/dom@1.7.6", - "", - { "dependencies": { "@floating-ui/core": "^1.7.5", "@floating-ui/utils": "^0.2.11" } }, - "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==" - ], - - "@floating-ui/utils": [ - "@floating-ui/utils@0.2.11", - "", - {}, - "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==" - ], - - "@fortawesome/fontawesome-free": [ - "@fortawesome/fontawesome-free@5.13.0", - "", - {}, - "sha512-xKOeQEl5O47GPZYIMToj6uuA2syyFlq9EMSl2ui0uytjY9xbe8XS0pexNWmxrdcCyNGyDmLyYw5FtKsalBUeOg==" - ], - - "@fullcalendar/core": [ - "@fullcalendar/core@6.1.20", - "", - { "dependencies": { "preact": "~10.12.1" } }, - "sha512-1cukXLlePFiJ8YKXn/4tMKsy0etxYLCkXk8nUCFi11nRONF2Ba2CD5b21/ovtOO2tL6afTJfwmc1ed3HG7eB1g==" - ], - - "@fullcalendar/daygrid": [ - "@fullcalendar/daygrid@6.1.20", - "", - { "peerDependencies": { "@fullcalendar/core": "~6.1.20" } }, - "sha512-AO9vqhkLP77EesmJzuU+IGXgxNulsA8mgQHynclJ8U70vSwAVnbcLG9qftiTAFSlZjiY/NvhE7sflve6cJelyQ==" - ], - - "@fullcalendar/react": [ - "@fullcalendar/react@6.1.20", - "", - { - "peerDependencies": { - "@fullcalendar/core": "~6.1.20", - "react": "^16.7.0 || ^17 || ^18 || ^19", - "react-dom": "^16.7.0 || ^17 || ^18 || ^19" - } - }, - "sha512-1w0pZtceaUdfAnxMSCGHCQalhi+mR1jOe76sXzyAXpcPz/Lf0zHSdcGK/U2XpZlnQgQtBZW+d+QBnnzVQKCxAA==" - ], - - "@grpc/grpc-js": [ - "@grpc/grpc-js@1.14.3", - "", - { - "dependencies": { "@grpc/proto-loader": "^0.8.0", "@js-sdsl/ordered-map": "^4.4.2" } - }, - "sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA==" - ], - - "@grpc/proto-loader": [ - "@grpc/proto-loader@0.8.0", - "", - { - "dependencies": { - "lodash.camelcase": "^4.3.0", - "long": "^5.0.0", - "protobufjs": "^7.5.3", - "yargs": "^17.7.2" - }, - "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } - }, - "sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ==" - ], - - "@httptoolkit/websocket-stream": [ - "@httptoolkit/websocket-stream@6.0.1", - "", - { - "dependencies": { - "@types/ws": "*", - "duplexify": "^3.5.1", - "inherits": "^2.0.1", - "isomorphic-ws": "^4.0.1", - "readable-stream": "^2.3.3", - "safe-buffer": "^5.1.2", - "ws": "*", - "xtend": "^4.0.0" - } - }, - "sha512-A0NOZI+Glp3Xgcz6Na7i7o09+/+xm2m0UCU8gdtM2nIv6/cjLmhMZMqehSpTlgbx9omtLmV8LVqOskPEyWnmZQ==" - ], - - "@humanfs/core": [ - "@humanfs/core@0.19.1", - "", - {}, - "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==" - ], - - "@humanfs/node": [ - "@humanfs/node@0.16.7", - "", - { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.4.0" } }, - "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==" - ], - - "@humanwhocodes/module-importer": [ - "@humanwhocodes/module-importer@1.0.1", - "", - {}, - "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==" - ], - - "@humanwhocodes/retry": [ - "@humanwhocodes/retry@0.4.3", - "", - {}, - "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==" - ], - - "@ioredis/commands": [ - "@ioredis/commands@1.5.1", - "", - {}, - "sha512-JH8ZL/ywcJyR9MmJ5BNqZllXNZQqQbnVZOqpPQqE1vHiFgAw4NHbvE0FOduNU8IX9babitBT46571OnPTT0Zcw==" - ], - - "@isaacs/cliui": [ - "@isaacs/cliui@8.0.2", - "", - { - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - } - }, - "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==" - ], - - "@isaacs/fs-minipass": [ - "@isaacs/fs-minipass@4.0.1", - "", - { "dependencies": { "minipass": "^7.0.4" } }, - "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==" - ], - - "@istanbuljs/load-nyc-config": [ - "@istanbuljs/load-nyc-config@1.1.0", - "", - { - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - } - }, - "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==" - ], - - "@istanbuljs/schema": [ - "@istanbuljs/schema@0.1.3", - "", - {}, - "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==" - ], - - "@jridgewell/gen-mapping": [ - "@jridgewell/gen-mapping@0.3.13", - "", - { - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==" - ], - - "@jridgewell/remapping": [ - "@jridgewell/remapping@2.3.5", - "", - { - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==" - ], - - "@jridgewell/resolve-uri": [ - "@jridgewell/resolve-uri@3.1.2", - "", - {}, - "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==" - ], - - "@jridgewell/source-map": [ - "@jridgewell/source-map@0.3.11", - "", - { - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" - } - }, - "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==" - ], - - "@jridgewell/sourcemap-codec": [ - "@jridgewell/sourcemap-codec@1.5.5", - "", - {}, - "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==" - ], - - "@jridgewell/trace-mapping": [ - "@jridgewell/trace-mapping@0.3.9", - "", - { - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==" - ], - - "@js-sdsl/ordered-map": [ - "@js-sdsl/ordered-map@4.4.2", - "", - {}, - "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==" - ], - - "@kristiandupont/recase": [ - "@kristiandupont/recase@1.4.1", - "", - { "dependencies": { "ramda": "^0.30.0" } }, - "sha512-e5t4YqhnRGbS9sU4N52cQgTn37qKwTsxDDcIuIkgPvX0UmnL+7eoOR6oFXeCib5zYuw03vYKpR55NBq+W43j1A==" - ], - - "@mapbox/node-pre-gyp": [ - "@mapbox/node-pre-gyp@2.0.3", - "", - { - "dependencies": { - "consola": "^3.2.3", - "detect-libc": "^2.0.0", - "https-proxy-agent": "^7.0.5", - "node-fetch": "^2.6.7", - "nopt": "^8.0.0", - "semver": "^7.5.3", - "tar": "^7.4.0" - }, - "bin": { "node-pre-gyp": "bin/node-pre-gyp" } - }, - "sha512-uwPAhccfFJlsfCxMYTwOdVfOz3xqyj8xYL3zJj8f0pb30tLohnnFPhLuqp4/qoEz8sNxe4SESZedcBojRefIzg==" - ], - - "@msgpackr-extract/msgpackr-extract-darwin-arm64": [ - "@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3", - "", - { "os": "darwin", "cpu": "arm64" }, - "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==" - ], - - "@msgpackr-extract/msgpackr-extract-darwin-x64": [ - "@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3", - "", - { "os": "darwin", "cpu": "x64" }, - "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==" - ], - - "@msgpackr-extract/msgpackr-extract-linux-arm": [ - "@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3", - "", - { "os": "linux", "cpu": "arm" }, - "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==" - ], - - "@msgpackr-extract/msgpackr-extract-linux-arm64": [ - "@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3", - "", - { "os": "linux", "cpu": "arm64" }, - "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==" - ], - - "@msgpackr-extract/msgpackr-extract-linux-x64": [ - "@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3", - "", - { "os": "linux", "cpu": "x64" }, - "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==" - ], - - "@msgpackr-extract/msgpackr-extract-win32-x64": [ - "@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3", - "", - { "os": "win32", "cpu": "x64" }, - "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==" - ], - - "@napi-rs/snappy-android-arm-eabi": [ - "@napi-rs/snappy-android-arm-eabi@7.3.3", - "", - { "os": "android", "cpu": "arm" }, - "sha512-d4vUFFzNBvazGfB/KU8MnEax6itTIgRWXodPdZDnWKHy9HwVBndpCiedQDcSNHcZNYV36rx034rpn7SAuTL2NA==" - ], - - "@napi-rs/snappy-android-arm64": [ - "@napi-rs/snappy-android-arm64@7.3.3", - "", - { "os": "android", "cpu": "arm64" }, - "sha512-Uh+w18dhzjVl85MGhRnojb7OLlX2ErvMsYIunO/7l3Frvc2zQvfqsWsFJanu2dwqlE2YDooeNP84S+ywgN9sxg==" - ], - - "@napi-rs/snappy-darwin-arm64": [ - "@napi-rs/snappy-darwin-arm64@7.3.3", - "", - { "os": "darwin", "cpu": "arm64" }, - "sha512-AmJn+6yOu/0V0YNHLKmRUNYkn93iv/1wtPayC7O1OHtfY6YqHQ31/MVeeRBiEYtQW9TwVZxXrDirxSB1PxRdtw==" - ], - - "@napi-rs/snappy-darwin-x64": [ - "@napi-rs/snappy-darwin-x64@7.3.3", - "", - { "os": "darwin", "cpu": "x64" }, - "sha512-biLTXBmPjPmO7HIpv+5BaV9Gy/4+QJSUNJW8Pjx1UlWAVnocPy7um+zbvAWStZssTI5sfn/jOClrAegD4w09UA==" - ], - - "@napi-rs/snappy-freebsd-x64": [ - "@napi-rs/snappy-freebsd-x64@7.3.3", - "", - { "os": "freebsd", "cpu": "x64" }, - "sha512-E3R3ewm8Mrjm0yL2TC3VgnphDsQaCPixNJqBbGiz3NTshVDhlPlOgPKF0NGYqKiKaDGdD9PKtUgOR4vagUtn7g==" - ], - - "@napi-rs/snappy-linux-arm-gnueabihf": [ - "@napi-rs/snappy-linux-arm-gnueabihf@7.3.3", - "", - { "os": "linux", "cpu": "arm" }, - "sha512-ZuNgtmk9j0KyT7TfLyEnvZJxOhbkyNR761nk04F0Q4NTHMICP28wQj0xgEsnCHUsEeA9OXrRL4R7waiLn+rOQA==" - ], - - "@napi-rs/snappy-linux-arm64-gnu": [ - "@napi-rs/snappy-linux-arm64-gnu@7.3.3", - "", - { "os": "linux", "cpu": "arm64" }, - "sha512-KIzwtq0dAzshzpqZWjg0Q9lUx93iZN7wCCUzCdLYIQ+mvJZKM10VCdn0RcuQze1R3UJTPwpPLXQIVskNMBYyPA==" - ], - - "@napi-rs/snappy-linux-arm64-musl": [ - "@napi-rs/snappy-linux-arm64-musl@7.3.3", - "", - { "os": "linux", "cpu": "arm64" }, - "sha512-AAED4cQS74xPvktsyVmz5sy8vSxG/+3d7Rq2FDBZzj3Fv6v5vux6uZnECPCAqpALCdTtJ61unqpOyqO7hZCt1Q==" - ], - - "@napi-rs/snappy-linux-ppc64-gnu": [ - "@napi-rs/snappy-linux-ppc64-gnu@7.3.3", - "", - { "os": "linux", "cpu": "ppc64" }, - "sha512-pofO5eSLg8ZTBwVae4WHHwJxJGZI8NEb4r5Mppvq12J/1/Hq1HecClXmfY3A7bdT2fsS2Td+Q7CI9VdBOj2sbA==" - ], - - "@napi-rs/snappy-linux-riscv64-gnu": [ - "@napi-rs/snappy-linux-riscv64-gnu@7.3.3", - "", - { "os": "linux", "cpu": "none" }, - "sha512-OiHYdeuwj0TVBXADUmmQDQ4lL1TB+8EwmXnFgOutoDVXHaUl0CJFyXLa6tYUXe+gRY8hs1v7eb0vyE97LKY06Q==" - ], - - "@napi-rs/snappy-linux-s390x-gnu": [ - "@napi-rs/snappy-linux-s390x-gnu@7.3.3", - "", - { "os": "linux", "cpu": "s390x" }, - "sha512-66QdmuV9CTq/S/xifZXlMy3PsZTviAgkqqpZ+7vPCmLtuP+nqhaeupShOFf/sIDsS0gZePazPosPTeTBbhkLHg==" - ], - - "@napi-rs/snappy-linux-x64-gnu": [ - "@napi-rs/snappy-linux-x64-gnu@7.3.3", - "", - { "os": "linux", "cpu": "x64" }, - "sha512-g6KURjOxrgb8yXDEZMuIcHkUr/7TKlDwSiydEQtMtP3n4iI4sNjkcE/WNKlR3+t9bZh1pFGAq7NFRBtouQGHpQ==" - ], - - "@napi-rs/snappy-linux-x64-musl": [ - "@napi-rs/snappy-linux-x64-musl@7.3.3", - "", - { "os": "linux", "cpu": "x64" }, - "sha512-6UvOyczHknpaKjrlKKSlX3rwpOrfJwiMG6qA0NRKJFgbcCAEUxmN9A8JvW4inP46DKdQ0bekdOxwRtAhFiTDfg==" - ], - - "@napi-rs/snappy-openharmony-arm64": [ - "@napi-rs/snappy-openharmony-arm64@7.3.3", - "", - { "os": "none", "cpu": "arm64" }, - "sha512-I5mak/5rTprobf7wMCk0vFhClmWOL/QiIJM4XontysnadmP/R9hAcmuFmoMV2GaxC9MblqLA7Z++gy8ou5hJVw==" - ], - - "@napi-rs/snappy-wasm32-wasi": [ - "@napi-rs/snappy-wasm32-wasi@7.3.3", - "", - { "dependencies": { "@napi-rs/wasm-runtime": "^1.0.3" }, "cpu": "none" }, - "sha512-+EroeygVYo9RksOchjF206frhMkfD2PaIun3yH4Zp5j/Y0oIEgs/+VhAYx/f+zHRylQYUIdLzDRclcoepvlR8Q==" - ], - - "@napi-rs/snappy-win32-arm64-msvc": [ - "@napi-rs/snappy-win32-arm64-msvc@7.3.3", - "", - { "os": "win32", "cpu": "arm64" }, - "sha512-rxqfntBsCfzgOha/OlG8ld2hs6YSMGhpMUbFjeQLyVDbooY041fRXv3S7yk52DfO6H4QQhLT5+p7cW0mYdhyiQ==" - ], - - "@napi-rs/snappy-win32-ia32-msvc": [ - "@napi-rs/snappy-win32-ia32-msvc@7.3.3", - "", - { "os": "win32", "cpu": "ia32" }, - "sha512-joRV16DsRtqjGt0CdSpxGCkO0UlHGeTZ/GqvdscoALpRKbikR2Top4C61dxEchmOd3lSYsXutuwWWGg3Nr++WA==" - ], - - "@napi-rs/snappy-win32-x64-msvc": [ - "@napi-rs/snappy-win32-x64-msvc@7.3.3", - "", - { "os": "win32", "cpu": "x64" }, - "sha512-cEnQwcsdJyOU7HSZODWsHpKuQoSYM4jaqw/hn9pOXYbRN1+02WxYppD3fdMuKN6TOA6YG5KA5PHRNeVilNX86Q==" - ], - - "@napi-rs/wasm-runtime": [ - "@napi-rs/wasm-runtime@0.2.12", - "", - { - "dependencies": { - "@emnapi/core": "^1.4.3", - "@emnapi/runtime": "^1.4.3", - "@tybys/wasm-util": "^0.10.0" - } - }, - "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==" - ], - - "@nivo/annotations": [ - "@nivo/annotations@0.79.1", - "", - { - "dependencies": { - "@nivo/colors": "0.79.1", - "@react-spring/web": "9.3.1", - "lodash": "^4.17.21" - }, - "peerDependencies": { "@nivo/core": "0.79.0", "react": ">= 16.14.0 < 18.0.0" } - }, - "sha512-lYso9Luu0maSDtIufwvyVt2+Wue7R9Fh3CIjuRDmNR72UjAgAVEcCar27Fy865UXGsj2hRJZ7KY/1s6kT3gu/w==" - ], - - "@nivo/axes": [ - "@nivo/axes@0.79.0", - "", - { - "dependencies": { - "@nivo/scales": "0.79.0", - "@react-spring/web": "9.3.1", - "d3-format": "^1.4.4", - "d3-time-format": "^3.0.0" - }, - "peerDependencies": { - "@nivo/core": "0.79.0", - "prop-types": ">= 15.5.10 < 16.0.0", - "react": ">= 16.14.0 < 18.0.0" - } - }, - "sha512-EhSeCPxtWEuxqnifeyF/pIJEzL7pRM3rfygL+MpfT5ypu5NcXYRGQo/Bw0Vh+GF1ML+tNAE0rRvCu2jgLSdVNQ==" - ], - - "@nivo/bar": [ - "@nivo/bar@0.79.1", - "", - { - "dependencies": { - "@nivo/annotations": "0.79.1", - "@nivo/axes": "0.79.0", - "@nivo/colors": "0.79.1", - "@nivo/legends": "0.79.1", - "@nivo/scales": "0.79.0", - "@nivo/tooltip": "0.79.0", - "@react-spring/web": "9.3.1", - "d3-scale": "^3.2.3", - "d3-shape": "^1.2.2", - "lodash": "^4.17.21" - }, - "peerDependencies": { "@nivo/core": "0.79.0", "react": ">= 16.14.0 < 18.0.0" } - }, - "sha512-swJ2FtFeRPWJK9O6aZiqTDi2J6GrU2Z6kIHBBCXBlFmq6+vfd5AqOHytdXPTaN80JsKDBBdtY7tqRjpRPlDZwQ==" - ], - - "@nivo/colors": [ - "@nivo/colors@0.79.1", - "", - { - "dependencies": { - "d3-color": "^2.0.0", - "d3-scale": "^3.2.3", - "d3-scale-chromatic": "^2.0.0", - "lodash": "^4.17.21" - }, - "peerDependencies": { - "@nivo/core": "0.79.0", - "prop-types": ">= 15.5.10 < 16.0.0", - "react": ">= 16.14.0 < 18.0.0" - } - }, - "sha512-45huBmz46OoQtfqzHrnqDJ9msebOBX84fTijyOBi8mn8iTDOK2xWgzT7cCYP3hKE58IclkibkzVyWCeJ+rUlqg==" - ], - - "@nivo/core": [ - "@nivo/core@0.79.0", - "", - { - "dependencies": { - "@nivo/recompose": "0.79.0", - "@react-spring/web": "9.3.1", - "d3-color": "^2.0.0", - "d3-format": "^1.4.4", - "d3-interpolate": "^2.0.1", - "d3-scale": "^3.2.3", - "d3-scale-chromatic": "^2.0.0", - "d3-shape": "^1.3.5", - "d3-time-format": "^3.0.0", - "lodash": "^4.17.21" - }, - "peerDependencies": { - "@nivo/tooltip": "0.79.0", - "prop-types": ">= 15.5.10 < 16.0.0", - "react": ">= 16.14.0 < 18.0.0" - } - }, - "sha512-e1iGodmGuXkF+QWAjhHVFc+lUnfBoUwaWqVcBXBfebzNc50tTJrTTMHyQczjgOIfTc8gEu23lAY4mVZCDKscig==" - ], - - "@nivo/legends": [ - "@nivo/legends@0.79.1", - "", - { - "peerDependencies": { - "@nivo/core": "0.79.0", - "prop-types": ">= 15.5.10 < 16.0.0", - "react": ">= 16.14.0 < 18.0.0" - } - }, - "sha512-AoabiLherOAk3/HR/N791fONxNdwNk/gCTJC/6BKUo2nX+JngEYm3nVFmTC1R6RdjwJTeCb9Vtuc4MHA+mcgig==" - ], - - "@nivo/line": [ - "@nivo/line@0.79.1", - "", - { - "dependencies": { - "@nivo/annotations": "0.79.1", - "@nivo/axes": "0.79.0", - "@nivo/colors": "0.79.1", - "@nivo/legends": "0.79.1", - "@nivo/scales": "0.79.0", - "@nivo/tooltip": "0.79.0", - "@nivo/voronoi": "0.79.0", - "@react-spring/web": "9.3.1", - "d3-shape": "^1.3.5" - }, - "peerDependencies": { - "@nivo/core": "0.79.0", - "prop-types": ">= 15.5.10 < 16.0.0", - "react": ">= 16.14.0 < 18.0.0" - } - }, - "sha512-V+2wY5TGpWiWBcb2LDtNsO79Ix93QtSq1HAdEIsjYtwFT/ekoCUA/OorIjRVUVzyf27vjjlbhmNNKrqIsYQR1Q==" - ], - - "@nivo/recompose": [ - "@nivo/recompose@0.79.0", - "", - { - "dependencies": { "react-lifecycles-compat": "^3.0.4" }, - "peerDependencies": { "react": ">= 16.14.0 < 18.0.0" } - }, - "sha512-2GFnOHfA2jzTOA5mdKMwJ6myCRGoXQQbQvFFQ7B/+hnHfU/yrOVpiGt6TPAn3qReC4dyDYrzy1hr9UeQh677ig==" - ], - - "@nivo/scales": [ - "@nivo/scales@0.79.0", - "", - { - "dependencies": { - "d3-scale": "^3.2.3", - "d3-time": "^1.0.11", - "d3-time-format": "^3.0.0", - "lodash": "^4.17.21" - } - }, - "sha512-5fAt5Wejp8yzAk6qmA3KU+celCxNYrrBhfvOi2ECDG8KQi+orbDnrO6qjVF6+ebfOn9az8ZVukcSeGA5HceiMg==" - ], - - "@nivo/tooltip": [ - "@nivo/tooltip@0.79.0", - "", - { - "dependencies": { "@react-spring/web": "9.3.1" }, - "peerDependencies": { "@nivo/core": "0.79.0" } - }, - "sha512-hsJsvhDVR9P/QqIEDIttaA6aslR3tU9So1s/k2jMdppL7J9ZH/IrVx9TbIP7jDKmnU5AMIP5uSstXj9JiKLhQA==" - ], - - "@nivo/voronoi": [ - "@nivo/voronoi@0.79.0", - "", - { - "dependencies": { "d3-delaunay": "^5.3.0", "d3-scale": "^3.2.3" }, - "peerDependencies": { "@nivo/core": "0.79.0", "react": ">= 16.14.0 < 18.0.0" } - }, - "sha512-0MrY33MBjLPQsgtf6PU+NUeQVib0g5fR9UBWsbO3YdkgDhXNnbXZ4FZlMAznoDSOxQ/efAuP7jWfnemFCpSwUg==" - ], - - "@noble/hashes": [ - "@noble/hashes@1.8.0", - "", - {}, - "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==" - ], - - "@nodelib/fs.scandir": [ - "@nodelib/fs.scandir@2.1.5", - "", - { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, - "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==" - ], - - "@nodelib/fs.stat": [ - "@nodelib/fs.stat@2.0.5", - "", - {}, - "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" - ], - - "@nodelib/fs.walk": [ - "@nodelib/fs.walk@1.2.8", - "", - { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, - "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==" - ], - - "@nolyfill/is-core-module": [ - "@nolyfill/is-core-module@1.0.39", - "", - {}, - "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==" - ], - - "@octokit/app": [ - "@octokit/app@15.1.0", - "", - { - "dependencies": { - "@octokit/auth-app": "^7.0.0", - "@octokit/auth-unauthenticated": "^6.0.0", - "@octokit/core": "^6.1.2", - "@octokit/oauth-app": "^7.0.0", - "@octokit/plugin-paginate-rest": "^11.0.0", - "@octokit/types": "^13.0.0", - "@octokit/webhooks": "^13.0.0" - } - }, - "sha512-TkBr7QgOmE6ORxvIAhDbZsqPkF7RSqTY4pLTtUQCvr6dTXqvi2fFo46q3h1lxlk/sGMQjqyZ0kEahkD/NyzOHg==" - ], - - "@octokit/auth-app": [ - "@octokit/auth-app@7.2.2", - "", - { - "dependencies": { - "@octokit/auth-oauth-app": "^8.1.4", - "@octokit/auth-oauth-user": "^5.1.4", - "@octokit/request": "^9.2.3", - "@octokit/request-error": "^6.1.8", - "@octokit/types": "^14.0.0", - "toad-cache": "^3.7.0", - "universal-github-app-jwt": "^2.2.0", - "universal-user-agent": "^7.0.0" - } - }, - "sha512-p6hJtEyQDCJEPN9ijjhEC/kpFHMHN4Gca9r+8S0S8EJi7NaWftaEmexjxxpT1DFBeJpN4u/5RE22ArnyypupJw==" - ], - - "@octokit/auth-oauth-app": [ - "@octokit/auth-oauth-app@8.1.4", - "", - { - "dependencies": { - "@octokit/auth-oauth-device": "^7.1.5", - "@octokit/auth-oauth-user": "^5.1.4", - "@octokit/request": "^9.2.3", - "@octokit/types": "^14.0.0", - "universal-user-agent": "^7.0.0" - } - }, - "sha512-71iBa5SflSXcclk/OL3lJzdt4iFs56OJdpBGEBl1wULp7C58uiswZLV6TdRaiAzHP1LT8ezpbHlKuxADb+4NkQ==" - ], - - "@octokit/auth-oauth-device": [ - "@octokit/auth-oauth-device@7.1.5", - "", - { - "dependencies": { - "@octokit/oauth-methods": "^5.1.5", - "@octokit/request": "^9.2.3", - "@octokit/types": "^14.0.0", - "universal-user-agent": "^7.0.0" - } - }, - "sha512-lR00+k7+N6xeECj0JuXeULQ2TSBB/zjTAmNF2+vyGPDEFx1dgk1hTDmL13MjbSmzusuAmuJD8Pu39rjp9jH6yw==" - ], - - "@octokit/auth-oauth-user": [ - "@octokit/auth-oauth-user@5.1.6", - "", - { - "dependencies": { - "@octokit/auth-oauth-device": "^7.1.5", - "@octokit/oauth-methods": "^5.1.5", - "@octokit/request": "^9.2.3", - "@octokit/types": "^14.0.0", - "universal-user-agent": "^7.0.0" - } - }, - "sha512-/R8vgeoulp7rJs+wfJ2LtXEVC7pjQTIqDab7wPKwVG6+2v/lUnCOub6vaHmysQBbb45FknM3tbHW8TOVqYHxCw==" - ], - - "@octokit/auth-token": [ - "@octokit/auth-token@5.1.2", - "", - {}, - "sha512-JcQDsBdg49Yky2w2ld20IHAlwr8d/d8N6NiOXbtuoPCqzbsiJgF633mVUw3x4mo0H5ypataQIX7SFu3yy44Mpw==" - ], - - "@octokit/auth-unauthenticated": [ - "@octokit/auth-unauthenticated@6.1.3", - "", - { "dependencies": { "@octokit/request-error": "^6.1.8", "@octokit/types": "^14.0.0" } }, - "sha512-d5gWJla3WdSl1yjbfMpET+hUSFCE15qM0KVSB0H1shyuJihf/RL1KqWoZMIaonHvlNojkL9XtLFp8QeLe+1iwA==" - ], - - "@octokit/core": [ - "@octokit/core@6.1.6", - "", - { - "dependencies": { - "@octokit/auth-token": "^5.0.0", - "@octokit/graphql": "^8.2.2", - "@octokit/request": "^9.2.3", - "@octokit/request-error": "^6.1.8", - "@octokit/types": "^14.0.0", - "before-after-hook": "^3.0.2", - "universal-user-agent": "^7.0.0" - } - }, - "sha512-kIU8SLQkYWGp3pVKiYzA5OSaNF5EE03P/R8zEmmrG6XwOg5oBjXyQVVIauQ0dgau4zYhpZEhJrvIYt6oM+zZZA==" - ], - - "@octokit/endpoint": [ - "@octokit/endpoint@10.1.4", - "", - { "dependencies": { "@octokit/types": "^14.0.0", "universal-user-agent": "^7.0.2" } }, - "sha512-OlYOlZIsfEVZm5HCSR8aSg02T2lbUWOsCQoPKfTXJwDzcHQBrVBGdGXb89dv2Kw2ToZaRtudp8O3ZIYoaOjKlA==" - ], - - "@octokit/graphql": [ - "@octokit/graphql@8.2.2", - "", - { - "dependencies": { - "@octokit/request": "^9.2.3", - "@octokit/types": "^14.0.0", - "universal-user-agent": "^7.0.0" - } - }, - "sha512-Yi8hcoqsrXGdt0yObxbebHXFOiUA+2v3n53epuOg1QUgOB6c4XzvisBNVXJSl8RYA5KrDuSL2yq9Qmqe5N0ryA==" - ], - - "@octokit/oauth-app": [ - "@octokit/oauth-app@7.1.6", - "", - { - "dependencies": { - "@octokit/auth-oauth-app": "^8.1.3", - "@octokit/auth-oauth-user": "^5.1.3", - "@octokit/auth-unauthenticated": "^6.1.2", - "@octokit/core": "^6.1.4", - "@octokit/oauth-authorization-url": "^7.1.1", - "@octokit/oauth-methods": "^5.1.4", - "@types/aws-lambda": "^8.10.83", - "universal-user-agent": "^7.0.0" - } - }, - "sha512-OMcMzY2WFARg80oJNFwWbY51TBUfLH4JGTy119cqiDawSFXSIBujxmpXiKbGWQlvfn0CxE6f7/+c6+Kr5hI2YA==" - ], - - "@octokit/oauth-authorization-url": [ - "@octokit/oauth-authorization-url@7.1.1", - "", - {}, - "sha512-ooXV8GBSabSWyhLUowlMIVd9l1s2nsOGQdlP2SQ4LnkEsGXzeCvbSbCPdZThXhEFzleGPwbapT0Sb+YhXRyjCA==" - ], - - "@octokit/oauth-methods": [ - "@octokit/oauth-methods@5.1.5", - "", - { - "dependencies": { - "@octokit/oauth-authorization-url": "^7.0.0", - "@octokit/request": "^9.2.3", - "@octokit/request-error": "^6.1.8", - "@octokit/types": "^14.0.0" - } - }, - "sha512-Ev7K8bkYrYLhoOSZGVAGsLEscZQyq7XQONCBBAl2JdMg7IT3PQn/y8P0KjloPoYpI5UylqYrLeUcScaYWXwDvw==" - ], - - "@octokit/openapi-types": [ - "@octokit/openapi-types@24.2.0", - "", - {}, - "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==" - ], - - "@octokit/openapi-webhooks-types": [ - "@octokit/openapi-webhooks-types@11.0.0", - "", - {}, - "sha512-ZBzCFj98v3SuRM7oBas6BHZMJRadlnDoeFfvm1olVxZnYeU6Vh97FhPxyS5aLh5pN51GYv2I51l/hVUAVkGBlA==" - ], - - "@octokit/plugin-paginate-rest": [ - "@octokit/plugin-paginate-rest@11.6.0", - "", - { - "dependencies": { "@octokit/types": "^13.10.0" }, - "peerDependencies": { "@octokit/core": ">=6" } - }, - "sha512-n5KPteiF7pWKgBIBJSk8qzoZWcUkza2O6A0za97pMGVrGfPdltxrfmfF5GucHYvHGZD8BdaZmmHGz5cX/3gdpw==" - ], - - "@octokit/request": [ - "@octokit/request@9.2.4", - "", - { - "dependencies": { - "@octokit/endpoint": "^10.1.4", - "@octokit/request-error": "^6.1.8", - "@octokit/types": "^14.0.0", - "fast-content-type-parse": "^2.0.0", - "universal-user-agent": "^7.0.2" - } - }, - "sha512-q8ybdytBmxa6KogWlNa818r0k1wlqzNC+yNkcQDECHvQo8Vmstrg18JwqJHdJdUiHD2sjlwBgSm9kHkOKe2iyA==" - ], - - "@octokit/request-error": [ - "@octokit/request-error@6.1.8", - "", - { "dependencies": { "@octokit/types": "^14.0.0" } }, - "sha512-WEi/R0Jmq+IJKydWlKDmryPcmdYSVjL3ekaiEL1L9eo1sUnqMJ+grqmC9cjk7CA7+b2/T397tO5d8YLOH3qYpQ==" - ], - - "@octokit/types": [ - "@octokit/types@13.10.0", - "", - { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, - "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==" - ], - - "@octokit/webhooks": [ - "@octokit/webhooks@13.9.1", - "", - { - "dependencies": { - "@octokit/openapi-webhooks-types": "11.0.0", - "@octokit/request-error": "^6.1.7", - "@octokit/webhooks-methods": "^5.1.1" - } - }, - "sha512-Nss2b4Jyn4wB3EAqAPJypGuCJFalz/ZujKBQQ5934To7Xw9xjf4hkr/EAByxQY7hp7MKd790bWGz7XYSTsHmaw==" - ], - - "@octokit/webhooks-methods": [ - "@octokit/webhooks-methods@5.1.1", - "", - {}, - "sha512-NGlEHZDseJTCj8TMMFehzwa9g7On4KJMPVHDSrHxCQumL6uSQR8wIkP/qesv52fXqV1BPf4pTxwtS31ldAt9Xg==" - ], - - "@octokit/webhooks-types": [ - "@octokit/webhooks-types@7.5.1", - "", - {}, - "sha512-1dozxWEP8lKGbtEu7HkRbK1F/nIPuJXNfT0gd96y6d3LcHZTtRtlf8xz3nicSJfesADxJyDh+mWBOsdLkqgzYw==" - ], - - "@opentelemetry/api": [ - "@opentelemetry/api@1.9.0", - "", - {}, - "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==" - ], - - "@oxc-project/runtime": [ - "@oxc-project/runtime@0.115.0", - "", - {}, - "sha512-Rg8Wlt5dCbXhQnsXPrkOjL1DTSvXLgb2R/KYfnf1/K+R0k6UMLEmbQXPM+kwrWqSmWA2t0B1EtHy2/3zikQpvQ==" - ], - - "@oxc-project/types": [ - "@oxc-project/types@0.115.0", - "", - {}, - "sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw==" - ], - - "@paralleldrive/cuid2": [ - "@paralleldrive/cuid2@2.3.1", - "", - { "dependencies": { "@noble/hashes": "^1.1.5" } }, - "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==" - ], - - "@pinojs/redact": [ - "@pinojs/redact@0.4.0", - "", - {}, - "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==" - ], - - "@pkgjs/parseargs": [ - "@pkgjs/parseargs@0.11.0", - "", - {}, - "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==" - ], - - "@popperjs/core": [ - "@popperjs/core@2.11.8", - "", - {}, - "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==" - ], - - "@protobufjs/aspromise": [ - "@protobufjs/aspromise@1.1.2", - "", - {}, - "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" - ], - - "@protobufjs/base64": [ - "@protobufjs/base64@1.1.2", - "", - {}, - "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - ], - - "@protobufjs/codegen": [ - "@protobufjs/codegen@2.0.4", - "", - {}, - "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - ], - - "@protobufjs/eventemitter": [ - "@protobufjs/eventemitter@1.1.0", - "", - {}, - "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" - ], - - "@protobufjs/fetch": [ - "@protobufjs/fetch@1.1.0", - "", - { - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==" - ], - - "@protobufjs/float": [ - "@protobufjs/float@1.0.2", - "", - {}, - "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" - ], - - "@protobufjs/inquire": [ - "@protobufjs/inquire@1.1.0", - "", - {}, - "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" - ], - - "@protobufjs/path": [ - "@protobufjs/path@1.1.2", - "", - {}, - "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" - ], - - "@protobufjs/pool": [ - "@protobufjs/pool@1.1.0", - "", - {}, - "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" - ], - - "@protobufjs/utf8": [ - "@protobufjs/utf8@1.1.0", - "", - {}, - "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" - ], - - "@react-aria/ssr": [ - "@react-aria/ssr@3.9.10", - "", - { - "dependencies": { "@swc/helpers": "^0.5.0" }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" - } - }, - "sha512-hvTm77Pf+pMBhuBm760Li0BVIO38jv1IBws1xFm1NoL26PU+fe+FMW5+VZWyANR6nYL65joaJKZqOdTQMkO9IQ==" - ], - - "@react-spring/animated": [ - "@react-spring/animated@9.3.2", - "", - { - "dependencies": { - "@react-spring/shared": "~9.3.0", - "@react-spring/types": "~9.3.0" - }, - "peerDependencies": { "react": "^16.8.0 || ^17.0.0" } - }, - "sha512-pBvKydRHbTzuyaeHtxGIOvnskZxGo/S5/YK1rtYm88b9NQZuZa95Rgd3O0muFL+99nvBMBL8cvQGD0UJmsqQsg==" - ], - - "@react-spring/core": [ - "@react-spring/core@9.3.2", - "", - { - "dependencies": { - "@react-spring/animated": "~9.3.0", - "@react-spring/shared": "~9.3.0", - "@react-spring/types": "~9.3.0" - }, - "peerDependencies": { "react": "^16.8.0 || ^17.0.0" } - }, - "sha512-kMRjkgdQ6LJ0lmb/wQlONpghaMT83UxglXHJC6m9kZS/GKVmN//TYMEK85xN1rC5Gg+BmjG61DtLCSkkLDTfNw==" - ], - - "@react-spring/rafz": [ - "@react-spring/rafz@9.3.2", - "", - {}, - "sha512-YtqNnAYp5bl6NdnDOD5TcYS40VJmB+Civ4LPtcWuRPKDAOa/XAf3nep48r0wPTmkK936mpX8aIm7h+luW59u5A==" - ], - - "@react-spring/shared": [ - "@react-spring/shared@9.3.2", - "", - { - "dependencies": { "@react-spring/rafz": "~9.3.0", "@react-spring/types": "~9.3.0" }, - "peerDependencies": { "react": "^16.8.0 || ^17.0.0" } - }, - "sha512-ypGQQ8w7mWnrELLon4h6mBCBxdd8j1pgLzmHXLpTC/f4ya2wdP+0WIKBWXJymIf+5NiTsXgSJra5SnHP5FBY+A==" - ], - - "@react-spring/types": [ - "@react-spring/types@9.3.2", - "", - {}, - "sha512-u+IK9z9Re4hjNkBYKebZr7xVDYTai2RNBsI4UPL/k0B6lCNSwuqWIXfKZUDVlMOeZHtDqayJn4xz6HcSkTj3FQ==" - ], - - "@react-spring/web": [ - "@react-spring/web@9.3.1", - "", - { - "dependencies": { - "@react-spring/animated": "~9.3.0", - "@react-spring/core": "~9.3.0", - "@react-spring/shared": "~9.3.0", - "@react-spring/types": "~9.3.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" - } - }, - "sha512-sisZIgFGva/Z+xKWPSfXpukF0AP3kR9ALTxlHL87fVotMUCJX5vtH/YlVcywToEFwTHKt3MpI5Wy2M+vgVEeaw==" - ], - - "@restart/hooks": [ - "@restart/hooks@0.4.16", - "", - { "dependencies": { "dequal": "^2.0.3" }, "peerDependencies": { "react": ">=16.8.0" } }, - "sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==" - ], - - "@restart/ui": [ - "@restart/ui@1.9.4", - "", - { - "dependencies": { - "@babel/runtime": "^7.26.0", - "@popperjs/core": "^2.11.8", - "@react-aria/ssr": "^3.5.0", - "@restart/hooks": "^0.5.0", - "@types/warning": "^3.0.3", - "dequal": "^2.0.3", - "dom-helpers": "^5.2.0", - "uncontrollable": "^8.0.4", - "warning": "^4.0.3" - }, - "peerDependencies": { "react": ">=16.14.0", "react-dom": ">=16.14.0" } - }, - "sha512-N4C7haUc3vn4LTwVUPlkJN8Ach/+yIMvRuTVIhjilNHqegY60SGLrzud6errOMNJwSnmYFnt1J0H/k8FE3A4KA==" - ], - - "@rolldown/binding-android-arm64": [ - "@rolldown/binding-android-arm64@1.0.0-rc.9", - "", - { "os": "android", "cpu": "arm64" }, - "sha512-lcJL0bN5hpgJfSIz/8PIf02irmyL43P+j1pTCfbD1DbLkmGRuFIA4DD3B3ZOvGqG0XiVvRznbKtN0COQVaKUTg==" - ], - - "@rolldown/binding-darwin-arm64": [ - "@rolldown/binding-darwin-arm64@1.0.0-rc.9", - "", - { "os": "darwin", "cpu": "arm64" }, - "sha512-J7Zk3kLYFsLtuH6U+F4pS2sYVzac0qkjcO5QxHS7OS7yZu2LRs+IXo+uvJ/mvpyUljDJ3LROZPoQfgBIpCMhdQ==" - ], - - "@rolldown/binding-darwin-x64": [ - "@rolldown/binding-darwin-x64@1.0.0-rc.9", - "", - { "os": "darwin", "cpu": "x64" }, - "sha512-iwtmmghy8nhfRGeNAIltcNXzD0QMNaaA5U/NyZc1Ia4bxrzFByNMDoppoC+hl7cDiUq5/1CnFthpT9n+UtfFyg==" - ], - - "@rolldown/binding-freebsd-x64": [ - "@rolldown/binding-freebsd-x64@1.0.0-rc.9", - "", - { "os": "freebsd", "cpu": "x64" }, - "sha512-DLFYI78SCiZr5VvdEplsVC2Vx53lnA4/Ga5C65iyldMVaErr86aiqCoNBLl92PXPfDtUYjUh+xFFor40ueNs4Q==" - ], - - "@rolldown/binding-linux-arm-gnueabihf": [ - "@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.9", - "", - { "os": "linux", "cpu": "arm" }, - "sha512-CsjTmTwd0Hri6iTw/DRMK7kOZ7FwAkrO4h8YWKoX/kcj833e4coqo2wzIFywtch/8Eb5enQ/lwLM7w6JX1W5RQ==" - ], - - "@rolldown/binding-linux-arm64-gnu": [ - "@rolldown/binding-linux-arm64-gnu@1.0.0-rc.9", - "", - { "os": "linux", "cpu": "arm64" }, - "sha512-2x9O2JbSPxpxMDhP9Z74mahAStibTlrBMW0520+epJH5sac7/LwZW5Bmg/E6CXuEF53JJFW509uP+lSedaUNxg==" - ], - - "@rolldown/binding-linux-arm64-musl": [ - "@rolldown/binding-linux-arm64-musl@1.0.0-rc.9", - "", - { "os": "linux", "cpu": "arm64" }, - "sha512-JA1QRW31ogheAIRhIg9tjMfsYbglXXYGNPLdPEYrwFxdbkQCAzvpSCSHCDWNl4hTtrol8WeboCSEpjdZK8qrCg==" - ], - - "@rolldown/binding-linux-ppc64-gnu": [ - "@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.9", - "", - { "os": "linux", "cpu": "ppc64" }, - "sha512-aOKU9dJheda8Kj8Y3w9gnt9QFOO+qKPAl8SWd7JPHP+Cu0EuDAE5wokQubLzIDQWg2myXq2XhTpOVS07qqvT+w==" - ], - - "@rolldown/binding-linux-s390x-gnu": [ - "@rolldown/binding-linux-s390x-gnu@1.0.0-rc.9", - "", - { "os": "linux", "cpu": "s390x" }, - "sha512-OalO94fqj7IWRn3VdXWty75jC5dk4C197AWEuMhIpvVv2lw9fiPhud0+bW2ctCxb3YoBZor71QHbY+9/WToadA==" - ], - - "@rolldown/binding-linux-x64-gnu": [ - "@rolldown/binding-linux-x64-gnu@1.0.0-rc.9", - "", - { "os": "linux", "cpu": "x64" }, - "sha512-cVEl1vZtBsBZna3YMjGXNvnYYrOJ7RzuWvZU0ffvJUexWkukMaDuGhUXn0rjnV0ptzGVkvc+vW9Yqy6h8YX4pg==" - ], - - "@rolldown/binding-linux-x64-musl": [ - "@rolldown/binding-linux-x64-musl@1.0.0-rc.9", - "", - { "os": "linux", "cpu": "x64" }, - "sha512-UzYnKCIIc4heAKgI4PZ3dfBGUZefGCJ1TPDuLHoCzgrMYPb5Rv6TLFuYtyM4rWyHM7hymNdsg5ik2C+UD9VDbA==" - ], - - "@rolldown/binding-openharmony-arm64": [ - "@rolldown/binding-openharmony-arm64@1.0.0-rc.9", - "", - { "os": "none", "cpu": "arm64" }, - "sha512-+6zoiF+RRyf5cdlFQP7nm58mq7+/2PFaY2DNQeD4B87N36JzfF/l9mdBkkmTvSYcYPE8tMh/o3cRlsx1ldLfog==" - ], - - "@rolldown/binding-wasm32-wasi": [ - "@rolldown/binding-wasm32-wasi@1.0.0-rc.9", - "", - { "dependencies": { "@napi-rs/wasm-runtime": "^1.1.1" }, "cpu": "none" }, - "sha512-rgFN6sA/dyebil3YTlL2evvi/M+ivhfnyxec7AccTpRPccno/rPoNlqybEZQBkcbZu8Hy+eqNJCqfBR8P7Pg8g==" - ], - - "@rolldown/binding-win32-arm64-msvc": [ - "@rolldown/binding-win32-arm64-msvc@1.0.0-rc.9", - "", - { "os": "win32", "cpu": "arm64" }, - "sha512-lHVNUG/8nlF1IQk1C0Ci574qKYyty2goMiPlRqkC5R+3LkXDkL5Dhx8ytbxq35m+pkHVIvIxviD+TWLdfeuadA==" - ], - - "@rolldown/binding-win32-x64-msvc": [ - "@rolldown/binding-win32-x64-msvc@1.0.0-rc.9", - "", - { "os": "win32", "cpu": "x64" }, - "sha512-G0oA4+w1iY5AGi5HcDTxWsoxF509hrFIPB2rduV5aDqS9FtDg1CAfa7V34qImbjfhIcA8C+RekocJZA96EarwQ==" - ], - - "@rolldown/pluginutils": [ - "@rolldown/pluginutils@1.0.0-rc.7", - "", - {}, - "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==" - ], - - "@rollup/pluginutils": [ - "@rollup/pluginutils@4.2.1", - "", - { "dependencies": { "estree-walker": "^2.0.1", "picomatch": "^2.2.2" } }, - "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==" - ], - - "@rollup/rollup-android-arm-eabi": [ - "@rollup/rollup-android-arm-eabi@4.59.0", - "", - { "os": "android", "cpu": "arm" }, - "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==" - ], - - "@rollup/rollup-android-arm64": [ - "@rollup/rollup-android-arm64@4.59.0", - "", - { "os": "android", "cpu": "arm64" }, - "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==" - ], - - "@rollup/rollup-darwin-arm64": [ - "@rollup/rollup-darwin-arm64@4.59.0", - "", - { "os": "darwin", "cpu": "arm64" }, - "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==" - ], - - "@rollup/rollup-darwin-x64": [ - "@rollup/rollup-darwin-x64@4.59.0", - "", - { "os": "darwin", "cpu": "x64" }, - "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==" - ], - - "@rollup/rollup-freebsd-arm64": [ - "@rollup/rollup-freebsd-arm64@4.59.0", - "", - { "os": "freebsd", "cpu": "arm64" }, - "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==" - ], - - "@rollup/rollup-freebsd-x64": [ - "@rollup/rollup-freebsd-x64@4.59.0", - "", - { "os": "freebsd", "cpu": "x64" }, - "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==" - ], - - "@rollup/rollup-linux-arm-gnueabihf": [ - "@rollup/rollup-linux-arm-gnueabihf@4.59.0", - "", - { "os": "linux", "cpu": "arm" }, - "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==" - ], - - "@rollup/rollup-linux-arm-musleabihf": [ - "@rollup/rollup-linux-arm-musleabihf@4.59.0", - "", - { "os": "linux", "cpu": "arm" }, - "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==" - ], - - "@rollup/rollup-linux-arm64-gnu": [ - "@rollup/rollup-linux-arm64-gnu@4.59.0", - "", - { "os": "linux", "cpu": "arm64" }, - "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==" - ], - - "@rollup/rollup-linux-arm64-musl": [ - "@rollup/rollup-linux-arm64-musl@4.59.0", - "", - { "os": "linux", "cpu": "arm64" }, - "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==" - ], - - "@rollup/rollup-linux-loong64-gnu": [ - "@rollup/rollup-linux-loong64-gnu@4.59.0", - "", - { "os": "linux", "cpu": "none" }, - "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==" - ], - - "@rollup/rollup-linux-loong64-musl": [ - "@rollup/rollup-linux-loong64-musl@4.59.0", - "", - { "os": "linux", "cpu": "none" }, - "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==" - ], - - "@rollup/rollup-linux-ppc64-gnu": [ - "@rollup/rollup-linux-ppc64-gnu@4.59.0", - "", - { "os": "linux", "cpu": "ppc64" }, - "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==" - ], - - "@rollup/rollup-linux-ppc64-musl": [ - "@rollup/rollup-linux-ppc64-musl@4.59.0", - "", - { "os": "linux", "cpu": "ppc64" }, - "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==" - ], - - "@rollup/rollup-linux-riscv64-gnu": [ - "@rollup/rollup-linux-riscv64-gnu@4.59.0", - "", - { "os": "linux", "cpu": "none" }, - "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==" - ], - - "@rollup/rollup-linux-riscv64-musl": [ - "@rollup/rollup-linux-riscv64-musl@4.59.0", - "", - { "os": "linux", "cpu": "none" }, - "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==" - ], - - "@rollup/rollup-linux-s390x-gnu": [ - "@rollup/rollup-linux-s390x-gnu@4.59.0", - "", - { "os": "linux", "cpu": "s390x" }, - "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==" - ], - - "@rollup/rollup-linux-x64-gnu": [ - "@rollup/rollup-linux-x64-gnu@4.59.0", - "", - { "os": "linux", "cpu": "x64" }, - "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==" - ], - - "@rollup/rollup-linux-x64-musl": [ - "@rollup/rollup-linux-x64-musl@4.59.0", - "", - { "os": "linux", "cpu": "x64" }, - "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==" - ], - - "@rollup/rollup-openbsd-x64": [ - "@rollup/rollup-openbsd-x64@4.59.0", - "", - { "os": "openbsd", "cpu": "x64" }, - "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==" - ], - - "@rollup/rollup-openharmony-arm64": [ - "@rollup/rollup-openharmony-arm64@4.59.0", - "", - { "os": "none", "cpu": "arm64" }, - "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==" - ], - - "@rollup/rollup-win32-arm64-msvc": [ - "@rollup/rollup-win32-arm64-msvc@4.59.0", - "", - { "os": "win32", "cpu": "arm64" }, - "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==" - ], - - "@rollup/rollup-win32-ia32-msvc": [ - "@rollup/rollup-win32-ia32-msvc@4.59.0", - "", - { "os": "win32", "cpu": "ia32" }, - "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==" - ], - - "@rollup/rollup-win32-x64-gnu": [ - "@rollup/rollup-win32-x64-gnu@4.59.0", - "", - { "os": "win32", "cpu": "x64" }, - "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==" - ], - - "@rollup/rollup-win32-x64-msvc": [ - "@rollup/rollup-win32-x64-msvc@4.59.0", - "", - { "os": "win32", "cpu": "x64" }, - "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==" - ], - - "@rtsao/scc": [ - "@rtsao/scc@1.1.0", - "", - {}, - "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==" - ], - - "@sapphire/async-queue": [ - "@sapphire/async-queue@1.5.5", - "", - {}, - "sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg==" - ], - - "@sapphire/snowflake": [ - "@sapphire/snowflake@1.3.6", - "", - {}, - "sha512-QnzuLp+p9D7agynVub/zqlDVriDza9y3STArBhNiNBUgIX8+GL5FpQxstRfw1jDr5jkZUjcuKYAHxjIuXKdJAg==" - ], - - "@sindresorhus/is": [ - "@sindresorhus/is@4.6.0", - "", - {}, - "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==" - ], - - "@smithy/types": [ - "@smithy/types@4.13.0", - "", - { "dependencies": { "tslib": "^2.6.2" } }, - "sha512-COuLsZILbbQsdrwKQpkkpyep7lCsByxwj7m0Mg5v66/ZTyenlfBc40/QFQ5chO0YN/PNEH1Bi3fGtfXPnYNeDw==" - ], - - "@so-ric/colorspace": [ - "@so-ric/colorspace@1.1.6", - "", - { "dependencies": { "color": "^5.0.2", "text-hex": "1.0.x" } }, - "sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw==" - ], - - "@swc/helpers": [ - "@swc/helpers@0.5.19", - "", - { "dependencies": { "tslib": "^2.8.0" } }, - "sha512-QamiFeIK3txNjgUTNppE6MiG3p7TdninpZu0E0PbqVh1a9FNLT2FRhisaa4NcaX52XVhA5l7Pk58Ft7Sqi/2sA==" - ], - - "@tsconfig/node10": [ - "@tsconfig/node10@1.0.12", - "", - {}, - "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==" - ], - - "@tsconfig/node12": [ - "@tsconfig/node12@1.0.11", - "", - {}, - "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" - ], - - "@tsconfig/node14": [ - "@tsconfig/node14@1.0.3", - "", - {}, - "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" - ], - - "@tsconfig/node16": [ - "@tsconfig/node16@1.0.4", - "", - {}, - "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==" - ], - - "@tybys/wasm-util": [ - "@tybys/wasm-util@0.10.1", - "", - { "dependencies": { "tslib": "^2.4.0" } }, - "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==" - ], - - "@types/aws-lambda": [ - "@types/aws-lambda@8.10.161", - "", - {}, - "sha512-rUYdp+MQwSFocxIOcSsYSF3YYYC/uUpMbCY/mbO21vGqfrEYvNSoPyKYDj6RhXXpPfS0KstW9RwG3qXh9sL7FQ==" - ], - - "@types/bcryptjs": [ - "@types/bcryptjs@2.4.6", - "", - {}, - "sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==" - ], - - "@types/body-parser": [ - "@types/body-parser@1.19.6", - "", - { "dependencies": { "@types/connect": "*", "@types/node": "*" } }, - "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==" - ], - - "@types/bson": [ - "@types/bson@1.0.11", - "", - { "dependencies": { "@types/node": "*" } }, - "sha512-j+UcCWI+FsbI5/FQP/Kj2CXyplWAz39ktHFkXk84h7dNblKRSoNJs95PZFRd96NQGqsPEPgeclqnznWZr14ZDA==" - ], - - "@types/bunyan": [ - "@types/bunyan@1.8.11", - "", - { "dependencies": { "@types/node": "*" } }, - "sha512-758fRH7umIMk5qt5ELmRMff4mLDlN+xyYzC+dkPTdKwbSkJFvz6xwyScrytPU0QIBbRRwbiE8/BIg8bpajerNQ==" - ], - - "@types/chai": [ - "@types/chai@5.2.3", - "", - { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, - "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==" - ], - - "@types/connect": [ - "@types/connect@3.4.38", - "", - { "dependencies": { "@types/node": "*" } }, - "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==" - ], - - "@types/connect-redis": [ - "@types/connect-redis@0.0.18", - "", - { - "dependencies": { - "@types/express": "*", - "@types/express-session": "*", - "@types/ioredis": "*", - "@types/redis": "^2.8.0" - } - }, - "sha512-iGygGbXgPIr94DEAuoluWhzre3c2/ew5NPlbW9IWvwCTXMM1YCmc7M9wpXMkYqt6kB9aO1sjZnmDzyugUu+2vQ==" - ], - - "@types/cookiejar": [ - "@types/cookiejar@2.1.5", - "", - {}, - "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==" - ], - - "@types/debug": [ - "@types/debug@4.1.12", - "", - { "dependencies": { "@types/ms": "*" } }, - "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==" - ], - - "@types/deep-eql": [ - "@types/deep-eql@4.0.2", - "", - {}, - "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==" - ], - - "@types/eslint": [ - "@types/eslint@9.6.1", - "", - { "dependencies": { "@types/estree": "*", "@types/json-schema": "*" } }, - "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==" - ], - - "@types/eslint__js": [ - "@types/eslint__js@8.42.3", - "", - { "dependencies": { "@types/eslint": "*" } }, - "sha512-alfG737uhmPdnvkrLdZLcEKJ/B8s9Y4hrZ+YAdzUeoArBlSUERA2E87ROfOaS4jd/C45fzOoZzidLc1IPwLqOw==" - ], - - "@types/estree": [ - "@types/estree@1.0.8", - "", - {}, - "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==" - ], - - "@types/express": [ - "@types/express@4.17.13", - "", - { - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==" - ], - - "@types/express-rate-limit": [ - "@types/express-rate-limit@5.1.3", - "", - { "dependencies": { "@types/express": "*" } }, - "sha512-H+TYy3K53uPU2TqPGFYaiWc2xJV6+bIFkDd/Ma2/h67Pa6ARk9kWE0p/K9OH1Okm0et9Sfm66fmXoAxsH2PHXg==" - ], - - "@types/express-serve-static-core": [ - "@types/express-serve-static-core@4.17.29", - "", - { - "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*" } - }, - "sha512-uMd++6dMKS32EOuw1Uli3e3BPgdLIXmezcfHv7N4c1s3gkhikBplORPpMq3fuWkxncZN1reb16d5n8yhQ80x7Q==" - ], - - "@types/express-session": [ - "@types/express-session@1.17.4", - "", - { "dependencies": { "@types/express": "*" } }, - "sha512-7cNlSI8+oOBUHTfPXMwDxF/Lchx5aJ3ho7+p9jJZYVg9dVDJFh3qdMXmJtRsysnvS+C6x46k9DRYmrmCkE+MVg==" - ], - - "@types/glob": [ - "@types/glob@7.2.0", - "", - { "dependencies": { "@types/minimatch": "*", "@types/node": "*" } }, - "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==" - ], - - "@types/google-protobuf": [ - "@types/google-protobuf@3.15.12", - "", - {}, - "sha512-40um9QqwHjRS92qnOaDpL7RmDK15NuZYo9HihiJRbYkMQZlWnuH8AdvbMy8/o6lgLmKbDUKa+OALCltHdbOTpQ==" - ], - - "@types/hast": [ - "@types/hast@2.3.10", - "", - { "dependencies": { "@types/unist": "^2" } }, - "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==" - ], - - "@types/history": [ - "@types/history@4.7.11", - "", - {}, - "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==" - ], - - "@types/http-errors": [ - "@types/http-errors@2.0.5", - "", - {}, - "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==" - ], - - "@types/humanize-duration": [ - "@types/humanize-duration@3.27.4", - "", - {}, - "sha512-yaf7kan2Sq0goxpbcwTQ+8E9RP6HutFBPv74T/IA/ojcHKhuKVlk2YFYyHhWZeLvZPzzLE3aatuQB4h0iqyyUA==" - ], - - "@types/ioredis": [ - "@types/ioredis@5.0.0", - "", - { "dependencies": { "ioredis": "*" } }, - "sha512-zJbJ3FVE17CNl5KXzdeSPtdltc4tMT3TzC6fxQS0sQngkbFZ6h+0uTafsRqu+eSLIugf6Yb0Ea0SUuRr42Nk9g==" - ], - - "@types/json-schema": [ - "@types/json-schema@7.0.15", - "", - {}, - "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" - ], - - "@types/json5": [ - "@types/json5@2.2.0", - "", - { "dependencies": { "json5": "*" } }, - "sha512-NrVug5woqbvNZ0WX+Gv4R+L4TGddtmFek2u8RtccAgFZWtS9QXF2xCXY22/M4nzkaKF0q9Fc6M/5rxLDhfwc/A==" - ], - - "@types/lodash": [ - "@types/lodash@4.14.172", - "", - {}, - "sha512-/BHF5HAx3em7/KkzVKm3LrsD6HZAXuXO1AJZQ3cRRBZj4oHZDviWPYu0aEplAqDFNHZPW6d3G7KN+ONcCCC7pw==" - ], - - "@types/lodash.get": [ - "@types/lodash.get@4.4.9", - "", - { "dependencies": { "@types/lodash": "*" } }, - "sha512-J5dvW98sxmGnamqf+/aLP87PYXyrha9xIgc2ZlHl6OHMFR2Ejdxep50QfU0abO1+CH6+ugx+8wEUN1toImAinA==" - ], - - "@types/luxon": [ - "@types/luxon@2.4.0", - "", - {}, - "sha512-oCavjEjRXuR6URJEtQm0eBdfsBiEcGBZbq21of8iGkeKxU1+1xgKuFPClaBZl2KB8ZZBSWlgk61tH6Mf+nvZVw==" - ], - - "@types/mdast": [ - "@types/mdast@3.0.15", - "", - { "dependencies": { "@types/unist": "^2" } }, - "sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==" - ], - - "@types/mdurl": [ - "@types/mdurl@1.0.5", - "", - {}, - "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==" - ], - - "@types/methods": [ - "@types/methods@1.1.4", - "", - {}, - "sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==" - ], - - "@types/minimatch": [ - "@types/minimatch@6.0.0", - "", - { "dependencies": { "minimatch": "*" } }, - "sha512-zmPitbQ8+6zNutpwgcQuLcsEpn/Cj54Kbn7L5pX0Os5kdWplB7xPgEh/g+SWOB/qmows2gpuCaPyduq8ZZRnxA==" - ], - - "@types/mkdirp": [ - "@types/mkdirp@1.0.2", - "", - { "dependencies": { "@types/node": "*" } }, - "sha512-o0K1tSO0Dx5X6xlU5F1D6625FawhC3dU3iqr25lluNv/+/QIVH8RLNEiVokgIZo+mz+87w/3Mkg/VvQS+J51fQ==" - ], - - "@types/mongodb": [ - "@types/mongodb@3.6.20", - "", - { "dependencies": { "@types/bson": "*", "@types/node": "*" } }, - "sha512-WcdpPJCakFzcWWD9juKoZbRtQxKIMYF/JIAM4JrNHrMcnJL6/a2NWjXxW7fo9hxboxxkg+icff8d7+WIEvKgYQ==" - ], - - "@types/ms": [ - "@types/ms@2.1.0", - "", - {}, - "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==" - ], - - "@types/multer": [ - "@types/multer@1.4.7", - "", - { "dependencies": { "@types/express": "*" } }, - "sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==" - ], - - "@types/natural-compare": [ - "@types/natural-compare@1.4.3", - "", - {}, - "sha512-XCAxy+Gg6+S6VagwzcknnvCKujj/bVv1q+GFuCrFEelqaZPqJoC+FeXLwc2dp+oLP7qDZQ4ZfQiTJQ9sIUmlLw==" - ], - - "@types/node": [ - "@types/node@20.19.37", - "", - { "dependencies": { "undici-types": "~6.21.0" } }, - "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==" - ], - - "@types/node-fetch": [ - "@types/node-fetch@2.5.12", - "", - { "dependencies": { "@types/node": "*", "form-data": "^3.0.0" } }, - "sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw==" - ], - - "@types/nodemailer": [ - "@types/nodemailer@6.4.23", - "", - { "dependencies": { "@types/node": "*" } }, - "sha512-aFV3/NsYFLSx9mbb5gtirBSXJnAlrusoKNuPbxsASWc7vrKLmIrTQRpdcxNcSFL3VW2A2XpeLEavwb2qMi6nlQ==" - ], - - "@types/parse-json": [ - "@types/parse-json@4.0.2", - "", - {}, - "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" - ], - - "@types/pg": [ - "@types/pg@8.18.0", - "", - { "dependencies": { "@types/node": "*", "pg-protocol": "*", "pg-types": "^2.2.0" } }, - "sha512-gT+oueVQkqnj6ajGJXblFR4iavIXWsGAFCk3dP4Kki5+a9R4NMt0JARdk6s8cUKcfUoqP5dAtDSLU8xYUTFV+Q==" - ], - - "@types/prop-types": [ - "@types/prop-types@15.7.15", - "", - {}, - "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==" - ], - - "@types/qs": [ - "@types/qs@6.15.0", - "", - {}, - "sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==" - ], - - "@types/range-parser": [ - "@types/range-parser@1.2.7", - "", - {}, - "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==" - ], - - "@types/rate-limit-redis": [ - "@types/rate-limit-redis@1.7.4", - "", - { - "dependencies": { - "@types/express-rate-limit": "3", - "@types/ioredis": "*", - "@types/redis": "^2.8.0" - } - }, - "sha512-TDsh9CJHHhx+sGHlqF6MI+PgEv91o/wQ67e2IR02ebYPzWQ8Rk0pcVY+WBy2pjxa+cAkPwjcOFDd21VToKaOzQ==" - ], - - "@types/react": [ - "@types/react@17.0.13", - "", - { - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "sha512-D/G3PiuqTfE3IMNjLn/DCp6umjVCSvtZTPdtAFy5+Ved6CsdRvivfKeCzw79W4AatShtU4nGqgvOv5Gro534vQ==" - ], - - "@types/react-dom": [ - "@types/react-dom@17.0.8", - "", - { "dependencies": { "@types/react": "*" } }, - "sha512-0ohAiJAx1DAUEcY9UopnfwCE9sSMDGnY/oXjWMax6g3RpzmTt2GMyMVAXcbn0mo8XAff0SbQJl2/SBU+hjSZ1A==" - ], - - "@types/react-google-recaptcha": [ - "@types/react-google-recaptcha@2.1.2", - "", - { "dependencies": { "@types/react": "*" } }, - "sha512-Zeb0pwDeXHYIQy5mNgewMr+jf4xtrjSHTdJW8wrubNB6sNEaxqo8yk02HVpwy7p7Hzh5y6iSz6gKoPonVBlswQ==" - ], - - "@types/react-router": [ - "@types/react-router@5.1.20", - "", - { "dependencies": { "@types/history": "^4.7.11", "@types/react": "*" } }, - "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==" - ], - - "@types/react-router-bootstrap": [ - "@types/react-router-bootstrap@0.26.1", - "", - { "dependencies": { "@types/react": "*" } }, - "sha512-EdgZn/PmSA8+I0RW6WyDUgBvkVXc8AmbbgOJ8WJfec1R/V06X++OrIOzwzdgYl4g3uXvEB6oEIxzcjx1/8Opqw==" - ], - - "@types/react-router-dom": [ - "@types/react-router-dom@5.1.7", - "", - { - "dependencies": { - "@types/history": "*", - "@types/react": "*", - "@types/react-router": "*" - } - }, - "sha512-D5mHD6TbdV/DNHYsnwBTv+y73ei+mMjrkGrla86HthE4/PVvL1J94Bu3qABU+COXzpL23T1EZapVVpwHuBXiUg==" - ], - - "@types/react-transition-group": [ - "@types/react-transition-group@4.4.12", - "", - { "peerDependencies": { "@types/react": "*" } }, - "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==" - ], - - "@types/redis": [ - "@types/redis@2.8.32", - "", - { "dependencies": { "@types/node": "*" } }, - "sha512-7jkMKxcGq9p242exlbsVzuJb57KqHRhNl4dHoQu2Y5v9bCAbtIXXH0R3HleSQW4CTOqpHIYUW3t6tpUj4BVQ+w==" - ], - - "@types/rimraf": [ - "@types/rimraf@3.0.2", - "", - { "dependencies": { "@types/glob": "*", "@types/node": "*" } }, - "sha512-F3OznnSLAUxFrCEu/L5PY8+ny8DtcFRjx7fZZ9bycvXRi3KPTRS9HOitGZwvPg0juRhXFWIeKX58cnX5YqLohQ==" - ], - - "@types/safe-json-stringify": [ - "@types/safe-json-stringify@1.1.2", - "", - {}, - "sha512-Hj/LZMBXFH3Qj9sNmNu6syBpkZqBaM00HgP7naf9CnZhB3kdxmrenWUD2cY6vvTWjuBM3NPOLknPKDUOQuTWXA==" - ], - - "@types/scheduler": [ - "@types/scheduler@0.26.0", - "", - {}, - "sha512-WFHp9YUJQ6CKshqoC37iOlHnQSmxNc795UhB26CyBBttrN9svdIrUjl/NjnNmfcwtncN0h/0PPAFWv9ovP8mLA==" - ], - - "@types/semver": [ - "@types/semver@7.7.1", - "", - {}, - "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==" - ], - - "@types/serve-static": [ - "@types/serve-static@2.2.0", - "", - { "dependencies": { "@types/http-errors": "*", "@types/node": "*" } }, - "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==" - ], - - "@types/superagent": [ - "@types/superagent@8.1.9", - "", - { - "dependencies": { - "@types/cookiejar": "^2.1.5", - "@types/methods": "^1.1.4", - "@types/node": "*", - "form-data": "^4.0.0" - } - }, - "sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==" - ], - - "@types/supertest": [ - "@types/supertest@2.0.11", - "", - { "dependencies": { "@types/superagent": "*" } }, - "sha512-uci4Esokrw9qGb9bvhhSVEjd6rkny/dk5PK/Qz4yxKiyppEI+dOPlNrZBahE3i+PoKFYyDxChVXZ/ysS/nrm1Q==" - ], - - "@types/tap": [ - "@types/tap@15.0.3", - "", - { "dependencies": { "@types/node": "*" } }, - "sha512-usOLtmMm1jfjPdkt9R9HMTU/J6m9QNYjgFs5U2tFiOzQSd7lDd/aAMprExYLnJnZb6tM4ujmGv7ITe+1smIRgg==" - ], - - "@types/triple-beam": [ - "@types/triple-beam@1.3.5", - "", - {}, - "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" - ], - - "@types/unist": [ - "@types/unist@2.0.11", - "", - {}, - "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==" - ], - - "@types/warning": [ - "@types/warning@3.0.3", - "", - {}, - "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==" - ], - - "@types/ws": [ - "@types/ws@8.18.1", - "", - { "dependencies": { "@types/node": "*" } }, - "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==" - ], - - "@types/yoga-layout": [ - "@types/yoga-layout@1.9.2", - "", - {}, - "sha512-S9q47ByT2pPvD65IvrWp7qppVMpk9WGMbVq9wbWZOHg6tnXSD4vyhao6nOSBwwfDdV2p3Kx9evA9vI+XWTfDvw==" - ], - - "@typescript-eslint/eslint-plugin": [ - "@typescript-eslint/eslint-plugin@4.33.0", - "", - { - "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" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^4.0.0", - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" - } - }, - "sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==" - ], - - "@typescript-eslint/experimental-utils": [ - "@typescript-eslint/experimental-utils@4.33.0", - "", - { - "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" - }, - "peerDependencies": { "eslint": "*" } - }, - "sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==" - ], - - "@typescript-eslint/parser": [ - "@typescript-eslint/parser@4.33.0", - "", - { - "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" - }, - "peerDependencies": { "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" } - }, - "sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==" - ], - - "@typescript-eslint/project-service": [ - "@typescript-eslint/project-service@8.56.1", - "", - { - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.56.1", - "@typescript-eslint/types": "^8.56.1", - "debug": "^4.4.3" - }, - "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } - }, - "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==" - ], - - "@typescript-eslint/scope-manager": [ - "@typescript-eslint/scope-manager@4.33.0", - "", - { - "dependencies": { - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/visitor-keys": "4.33.0" - } - }, - "sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==" - ], - - "@typescript-eslint/tsconfig-utils": [ - "@typescript-eslint/tsconfig-utils@8.56.1", - "", - { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, - "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==" - ], - - "@typescript-eslint/type-utils": [ - "@typescript-eslint/type-utils@8.56.1", - "", - { - "dependencies": { - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1", - "@typescript-eslint/utils": "8.56.1", - "debug": "^4.4.3", - "ts-api-utils": "^2.4.0" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==" - ], - - "@typescript-eslint/types": [ - "@typescript-eslint/types@4.33.0", - "", - {}, - "sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==" - ], - - "@typescript-eslint/typescript-estree": [ - "@typescript-eslint/typescript-estree@4.33.0", - "", - { - "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" - } - }, - "sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==" - ], - - "@typescript-eslint/utils": [ - "@typescript-eslint/utils@8.56.1", - "", - { - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==" - ], - - "@typescript-eslint/visitor-keys": [ - "@typescript-eslint/visitor-keys@4.33.0", - "", - { - "dependencies": { - "@typescript-eslint/types": "4.33.0", - "eslint-visitor-keys": "^2.0.0" - } - }, - "sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==" - ], - - "@typescript/native-preview": [ - "@typescript/native-preview@7.0.0-dev.20260309.1", - "", - { - "optionalDependencies": { - "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260309.1", - "@typescript/native-preview-darwin-x64": "7.0.0-dev.20260309.1", - "@typescript/native-preview-linux-arm": "7.0.0-dev.20260309.1", - "@typescript/native-preview-linux-arm64": "7.0.0-dev.20260309.1", - "@typescript/native-preview-linux-x64": "7.0.0-dev.20260309.1", - "@typescript/native-preview-win32-arm64": "7.0.0-dev.20260309.1", - "@typescript/native-preview-win32-x64": "7.0.0-dev.20260309.1" - }, - "bin": { "tsgo": "bin/tsgo.js" } - }, - "sha512-ZK+ExK7scBzUCAXCTtAwUm6QENJ+l3tCDQXNCly4WcGUvbIAWdaiNns4brganGN9nrxxRkC9Rx0CrxvIsn9zHA==" - ], - - "@typescript/native-preview-darwin-arm64": [ - "@typescript/native-preview-darwin-arm64@7.0.0-dev.20260309.1", - "", - { "os": "darwin", "cpu": "arm64" }, - "sha512-Vszk6vbONyyT47mUTEFNAXk+bJisM8F0pI+MyNPM8i2oorex7Gbp7ivFUGzdZHRFPDXMrlw6AXmgx1U2tZxiHw==" - ], - - "@typescript/native-preview-darwin-x64": [ - "@typescript/native-preview-darwin-x64@7.0.0-dev.20260309.1", - "", - { "os": "darwin", "cpu": "x64" }, - "sha512-UmmW/L1fW6URMILx5HqxcL2kElOyTYbY6M8yRMQK7gmBzsbkGj37JYN+WZgPkz/PQCVsxwIFcot6WmKRRXeBxQ==" - ], - - "@typescript/native-preview-linux-arm": [ - "@typescript/native-preview-linux-arm@7.0.0-dev.20260309.1", - "", - { "os": "linux", "cpu": "arm" }, - "sha512-G5zgoOZP2NjZ1kga9mend2in1e3C+Mm3XufelVZ9RwWRka744s6KxAsen853LizCrxBh58foj9pPVnH6gKUJvg==" - ], - - "@typescript/native-preview-linux-arm64": [ - "@typescript/native-preview-linux-arm64@7.0.0-dev.20260309.1", - "", - { "os": "linux", "cpu": "arm64" }, - "sha512-sN5rQRvqre8JHUISJhybUQ1e4a+mb/Ifa+uWHJawJ2tojTXWkU1rJTZBnAN3/XeoIJgeSdaZQAZRDlW9B7zbvw==" - ], - - "@typescript/native-preview-linux-x64": [ - "@typescript/native-preview-linux-x64@7.0.0-dev.20260309.1", - "", - { "os": "linux", "cpu": "x64" }, - "sha512-ZuHu9Sg4/akGSrO49hKLNKwrFXx7AZ2CS3PcTd85cC4nKudqB1aGD9rHxZZZyClj++e0qcNQ+4eTMn1sxDA9VQ==" - ], - - "@typescript/native-preview-win32-arm64": [ - "@typescript/native-preview-win32-arm64@7.0.0-dev.20260309.1", - "", - { "os": "win32", "cpu": "arm64" }, - "sha512-RNIidoGPsRaALc1znXiWfNARkGptm9e55qYnaz11YPvMrqbRKP9Y6Ipx4Oh/diIeF7y9UYiikeyk7EsyKe//sw==" - ], - - "@typescript/native-preview-win32-x64": [ - "@typescript/native-preview-win32-x64@7.0.0-dev.20260309.1", - "", - { "os": "win32", "cpu": "x64" }, - "sha512-/rEvAKowcoEdL2VeNju8apkGHEmbat10jIn1Sncny1zIaWvaMFw6bhmny+kKwX+9deitMfo9ihLlo5GCPJuMPQ==" - ], - - "@unrs/resolver-binding-android-arm-eabi": [ - "@unrs/resolver-binding-android-arm-eabi@1.11.1", - "", - { "os": "android", "cpu": "arm" }, - "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==" - ], - - "@unrs/resolver-binding-android-arm64": [ - "@unrs/resolver-binding-android-arm64@1.11.1", - "", - { "os": "android", "cpu": "arm64" }, - "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==" - ], - - "@unrs/resolver-binding-darwin-arm64": [ - "@unrs/resolver-binding-darwin-arm64@1.11.1", - "", - { "os": "darwin", "cpu": "arm64" }, - "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==" - ], - - "@unrs/resolver-binding-darwin-x64": [ - "@unrs/resolver-binding-darwin-x64@1.11.1", - "", - { "os": "darwin", "cpu": "x64" }, - "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==" - ], - - "@unrs/resolver-binding-freebsd-x64": [ - "@unrs/resolver-binding-freebsd-x64@1.11.1", - "", - { "os": "freebsd", "cpu": "x64" }, - "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==" - ], - - "@unrs/resolver-binding-linux-arm-gnueabihf": [ - "@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1", - "", - { "os": "linux", "cpu": "arm" }, - "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==" - ], - - "@unrs/resolver-binding-linux-arm-musleabihf": [ - "@unrs/resolver-binding-linux-arm-musleabihf@1.11.1", - "", - { "os": "linux", "cpu": "arm" }, - "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==" - ], - - "@unrs/resolver-binding-linux-arm64-gnu": [ - "@unrs/resolver-binding-linux-arm64-gnu@1.11.1", - "", - { "os": "linux", "cpu": "arm64" }, - "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==" - ], - - "@unrs/resolver-binding-linux-arm64-musl": [ - "@unrs/resolver-binding-linux-arm64-musl@1.11.1", - "", - { "os": "linux", "cpu": "arm64" }, - "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==" - ], - - "@unrs/resolver-binding-linux-ppc64-gnu": [ - "@unrs/resolver-binding-linux-ppc64-gnu@1.11.1", - "", - { "os": "linux", "cpu": "ppc64" }, - "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==" - ], - - "@unrs/resolver-binding-linux-riscv64-gnu": [ - "@unrs/resolver-binding-linux-riscv64-gnu@1.11.1", - "", - { "os": "linux", "cpu": "none" }, - "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==" - ], - - "@unrs/resolver-binding-linux-riscv64-musl": [ - "@unrs/resolver-binding-linux-riscv64-musl@1.11.1", - "", - { "os": "linux", "cpu": "none" }, - "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==" - ], - - "@unrs/resolver-binding-linux-s390x-gnu": [ - "@unrs/resolver-binding-linux-s390x-gnu@1.11.1", - "", - { "os": "linux", "cpu": "s390x" }, - "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==" - ], - - "@unrs/resolver-binding-linux-x64-gnu": [ - "@unrs/resolver-binding-linux-x64-gnu@1.11.1", - "", - { "os": "linux", "cpu": "x64" }, - "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==" - ], - - "@unrs/resolver-binding-linux-x64-musl": [ - "@unrs/resolver-binding-linux-x64-musl@1.11.1", - "", - { "os": "linux", "cpu": "x64" }, - "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==" - ], - - "@unrs/resolver-binding-wasm32-wasi": [ - "@unrs/resolver-binding-wasm32-wasi@1.11.1", - "", - { "dependencies": { "@napi-rs/wasm-runtime": "^0.2.11" }, "cpu": "none" }, - "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==" - ], - - "@unrs/resolver-binding-win32-arm64-msvc": [ - "@unrs/resolver-binding-win32-arm64-msvc@1.11.1", - "", - { "os": "win32", "cpu": "arm64" }, - "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==" - ], - - "@unrs/resolver-binding-win32-ia32-msvc": [ - "@unrs/resolver-binding-win32-ia32-msvc@1.11.1", - "", - { "os": "win32", "cpu": "ia32" }, - "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==" - ], - - "@unrs/resolver-binding-win32-x64-msvc": [ - "@unrs/resolver-binding-win32-x64-msvc@1.11.1", - "", - { "os": "win32", "cpu": "x64" }, - "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==" - ], - - "@valuabletouch/winston-seq": [ - "@valuabletouch/winston-seq@1.3.0", - "", - { "dependencies": { "seq-logging": "^1.1.1", "winston-transport": "^4.4.0" } }, - "sha512-j6oHAXTTdhwUap0VJGHIwiKhbw9IffOWYMrMI1Y2uXStNCNSnwIHYHHfjDw46hrynbVN838DRR+voGtYEvzF1w==" - ], - - "@vitejs/plugin-react": [ - "@vitejs/plugin-react@6.0.1", - "", - { - "dependencies": { "@rolldown/pluginutils": "1.0.0-rc.7" }, - "peerDependencies": { - "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", - "babel-plugin-react-compiler": "^1.0.0", - "vite": "^8.0.0" - }, - "optionalPeers": ["@rolldown/plugin-babel", "babel-plugin-react-compiler"] - }, - "sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==" - ], - - "@vitest/coverage-v8": [ - "@vitest/coverage-v8@3.2.4", - "", - { - "dependencies": { - "@ampproject/remapping": "^2.3.0", - "@bcoe/v8-coverage": "^1.0.2", - "ast-v8-to-istanbul": "^0.3.3", - "debug": "^4.4.1", - "istanbul-lib-coverage": "^3.2.2", - "istanbul-lib-report": "^3.0.1", - "istanbul-lib-source-maps": "^5.0.6", - "istanbul-reports": "^3.1.7", - "magic-string": "^0.30.17", - "magicast": "^0.3.5", - "std-env": "^3.9.0", - "test-exclude": "^7.0.1", - "tinyrainbow": "^2.0.0" - }, - "peerDependencies": { "@vitest/browser": "3.2.4", "vitest": "3.2.4" }, - "optionalPeers": ["@vitest/browser"] - }, - "sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ==" - ], - - "@vitest/expect": [ - "@vitest/expect@3.2.4", - "", - { - "dependencies": { - "@types/chai": "^5.2.2", - "@vitest/spy": "3.2.4", - "@vitest/utils": "3.2.4", - "chai": "^5.2.0", - "tinyrainbow": "^2.0.0" - } - }, - "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==" - ], - - "@vitest/mocker": [ - "@vitest/mocker@3.2.4", - "", - { - "dependencies": { - "@vitest/spy": "3.2.4", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.17" - }, - "peerDependencies": { "msw": "^2.4.9", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, - "optionalPeers": ["msw", "vite"] - }, - "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==" - ], - - "@vitest/pretty-format": [ - "@vitest/pretty-format@3.2.4", - "", - { "dependencies": { "tinyrainbow": "^2.0.0" } }, - "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==" - ], - - "@vitest/runner": [ - "@vitest/runner@3.2.4", - "", - { - "dependencies": { - "@vitest/utils": "3.2.4", - "pathe": "^2.0.3", - "strip-literal": "^3.0.0" - } - }, - "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==" - ], - - "@vitest/snapshot": [ - "@vitest/snapshot@3.2.4", - "", - { - "dependencies": { - "@vitest/pretty-format": "3.2.4", - "magic-string": "^0.30.17", - "pathe": "^2.0.3" - } - }, - "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==" - ], - - "@vitest/spy": [ - "@vitest/spy@3.2.4", - "", - { "dependencies": { "tinyspy": "^4.0.3" } }, - "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==" - ], - - "@vitest/utils": [ - "@vitest/utils@3.2.4", - "", - { - "dependencies": { - "@vitest/pretty-format": "3.2.4", - "loupe": "^3.1.4", - "tinyrainbow": "^2.0.0" - } - }, - "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==" - ], - - "abbrev": [ - "abbrev@3.0.1", - "", - {}, - "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==" - ], - - "abort-controller": [ - "abort-controller@3.0.0", - "", - { "dependencies": { "event-target-shim": "^5.0.0" } }, - "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==" - ], - - "accepts": [ - "accepts@1.3.8", - "", - { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, - "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==" - ], - - "acorn": [ - "acorn@8.16.0", - "", - { "bin": { "acorn": "bin/acorn" } }, - "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==" - ], - - "acorn-jsx": [ - "acorn-jsx@5.3.2", - "", - { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==" - ], - - "acorn-walk": [ - "acorn-walk@8.3.5", - "", - { "dependencies": { "acorn": "^8.11.0" } }, - "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==" - ], - - "agent-base": [ - "agent-base@7.1.4", - "", - {}, - "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==" - ], - - "aggregate-error": [ - "aggregate-error@3.1.0", - "", - { "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" } }, - "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==" - ], - - "ajv": [ - "ajv@6.14.0", - "", - { - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==" - ], - - "ansi-escapes": [ - "ansi-escapes@4.3.2", - "", - { "dependencies": { "type-fest": "^0.21.3" } }, - "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==" - ], - - "ansi-regex": [ - "ansi-regex@4.1.1", - "", - {}, - "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==" - ], - - "ansi-styles": [ - "ansi-styles@4.3.0", - "", - { "dependencies": { "color-convert": "^2.0.1" } }, - "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==" - ], - - "ansicolors": [ - "ansicolors@0.3.2", - "", - {}, - "sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==" - ], - - "anymatch": [ - "anymatch@3.1.3", - "", - { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, - "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==" - ], - - "append-field": [ - "append-field@1.0.0", - "", - {}, - "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" - ], - - "append-transform": [ - "append-transform@2.0.0", - "", - { "dependencies": { "default-require-extensions": "^3.0.0" } }, - "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==" - ], - - "archy": [ - "archy@1.0.0", - "", - {}, - "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==" - ], - - "arg": [ - "arg@4.1.3", - "", - {}, - "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" - ], - - "argparse": [ - "argparse@1.0.10", - "", - { "dependencies": { "sprintf-js": "~1.0.2" } }, - "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==" - ], - - "aria-query": [ - "aria-query@5.3.2", - "", - {}, - "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==" - ], - - "array-buffer-byte-length": [ - "array-buffer-byte-length@1.0.2", - "", - { "dependencies": { "call-bound": "^1.0.3", "is-array-buffer": "^3.0.5" } }, - "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==" - ], - - "array-flatten": [ - "array-flatten@1.1.1", - "", - {}, - "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - ], - - "array-includes": [ - "array-includes@3.1.9", - "", - { - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.24.0", - "es-object-atoms": "^1.1.1", - "get-intrinsic": "^1.3.0", - "is-string": "^1.1.1", - "math-intrinsics": "^1.1.0" - } - }, - "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==" - ], - - "array-union": [ - "array-union@2.1.0", - "", - {}, - "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" - ], - - "array.prototype.findlast": [ - "array.prototype.findlast@1.2.5", - "", - { - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" - } - }, - "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==" - ], - - "array.prototype.findlastindex": [ - "array.prototype.findlastindex@1.2.6", - "", - { - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-shim-unscopables": "^1.1.0" - } - }, - "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==" - ], - - "array.prototype.flat": [ - "array.prototype.flat@1.3.3", - "", - { - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" - } - }, - "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==" - ], - - "array.prototype.flatmap": [ - "array.prototype.flatmap@1.3.3", - "", - { - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" - } - }, - "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==" - ], - - "array.prototype.tosorted": [ - "array.prototype.tosorted@1.1.4", - "", - { - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", - "es-errors": "^1.3.0", - "es-shim-unscopables": "^1.0.2" - } - }, - "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==" - ], - - "arraybuffer.prototype.slice": [ - "arraybuffer.prototype.slice@1.0.4", - "", - { - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "is-array-buffer": "^3.0.4" - } - }, - "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==" - ], - - "arrify": [ - "arrify@2.0.1", - "", - {}, - "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" - ], - - "asap": [ - "asap@2.0.6", - "", - {}, - "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" - ], - - "asn1": [ - "asn1@0.2.6", - "", - { "dependencies": { "safer-buffer": "~2.1.0" } }, - "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==" - ], - - "assert-plus": [ - "assert-plus@1.0.0", - "", - {}, - "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==" - ], - - "assertion-error": [ - "assertion-error@2.0.1", - "", - {}, - "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==" - ], - - "ast-types-flow": [ - "ast-types-flow@0.0.8", - "", - {}, - "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==" - ], - - "ast-v8-to-istanbul": [ - "ast-v8-to-istanbul@0.3.12", - "", - { - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.31", - "estree-walker": "^3.0.3", - "js-tokens": "^10.0.0" - } - }, - "sha512-BRRC8VRZY2R4Z4lFIL35MwNXmwVqBityvOIwETtsCSwvjl0IdgFsy9NhdaA6j74nUdtJJlIypeRhpDam19Wq3g==" - ], - - "astral-regex": [ - "astral-regex@2.0.0", - "", - {}, - "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==" - ], - - "async": [ - "async@3.2.6", - "", - {}, - "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" - ], - - "async-exit-hook": [ - "async-exit-hook@2.0.1", - "", - {}, - "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==" - ], - - "async-function": [ - "async-function@1.0.0", - "", - {}, - "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==" - ], - - "async-hook-domain": [ - "async-hook-domain@2.0.4", - "", - {}, - "sha512-14LjCmlK1PK8eDtTezR6WX8TMaYNIzBIsd2D1sGoGjgx0BuNMMoSdk7i/drlbtamy0AWv9yv2tkB+ASdmeqFIw==" - ], - - "asynckit": [ - "asynckit@0.4.0", - "", - {}, - "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - ], - - "atomic-sleep": [ - "atomic-sleep@1.0.0", - "", - {}, - "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==" - ], - - "auto-bind": [ - "auto-bind@4.0.0", - "", - {}, - "sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ==" - ], - - "available-typed-arrays": [ - "available-typed-arrays@1.0.7", - "", - { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, - "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==" - ], - - "aws-crt": [ - "aws-crt@1.29.1", - "", - { - "dependencies": { - "@aws-sdk/util-utf8-browser": "^3.259.0", - "@httptoolkit/websocket-stream": "^6.0.1", - "axios": "^1.12.2", - "buffer": "^6.0.3", - "crypto-js": "^4.2.0", - "mqtt": "^4.3.8", - "process": "^0.11.10" - } - }, - "sha512-YeuwHbh9SjRkMpaY6hXi8NzNn2yjuwEen8Vg/Wasg4hOoqiwxINwX3g7LZEc+mMCOoxQWOQfTJcaOAbU24HroQ==" - ], - - "aws-sign2": [ - "aws-sign2@0.7.0", - "", - {}, - "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==" - ], - - "aws4": [ - "aws4@1.13.2", - "", - {}, - "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==" - ], - - "axe-core": [ - "axe-core@4.11.1", - "", - {}, - "sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==" - ], - - "axios": [ - "axios@1.13.6", - "", - { - "dependencies": { - "follow-redirects": "^1.15.11", - "form-data": "^4.0.5", - "proxy-from-env": "^1.1.0" - } - }, - "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==" - ], - - "axobject-query": [ - "axobject-query@4.1.0", - "", - {}, - "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==" - ], - - "babel-plugin-macros": [ - "babel-plugin-macros@3.1.0", - "", - { - "dependencies": { - "@babel/runtime": "^7.12.5", - "cosmiconfig": "^7.0.0", - "resolve": "^1.19.0" - } - }, - "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==" - ], - - "bail": [ - "bail@2.0.2", - "", - {}, - "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==" - ], - - "balanced-match": [ - "balanced-match@1.0.2", - "", - {}, - "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - ], - - "base64-js": [ - "base64-js@1.5.1", - "", - {}, - "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - ], - - "baseline-browser-mapping": [ - "baseline-browser-mapping@2.10.0", - "", - { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, - "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==" - ], - - "bcrypt-pbkdf": [ - "bcrypt-pbkdf@1.0.2", - "", - { "dependencies": { "tweetnacl": "^0.14.3" } }, - "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==" - ], - - "bcryptjs": [ - "bcryptjs@2.4.3", - "", - {}, - "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" - ], - - "before-after-hook": [ - "before-after-hook@3.0.2", - "", - {}, - "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==" - ], - - "better-sqlite3": [ - "better-sqlite3@9.4.5", - "", - { "dependencies": { "bindings": "^1.5.0", "prebuild-install": "^7.1.1" } }, - "sha512-uFVyoyZR9BNcjSca+cp3MWCv6upAv+tbMC4SWM51NIMhoQOm4tjIkyxFO/ZsYdGAF61WJBgdzyJcz4OokJi0gQ==" - ], - - "big-integer": [ - "big-integer@1.6.52", - "", - {}, - "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==" - ], - - "binary-extensions": [ - "binary-extensions@2.3.0", - "", - {}, - "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==" - ], - - "binary-parser": [ - "binary-parser@2.3.0", - "", - {}, - "sha512-TXOlPrhvi+kZUv3vA1qZ+MBdqZdihF8gWw7j/MRINiJqXH652GtLSqFTHNPjG8kHbiMQSCATG9oat9ao6aA8dA==" - ], - - "bind-obj-methods": [ - "bind-obj-methods@3.0.0", - "", - {}, - "sha512-nLEaaz3/sEzNSyPWRsN9HNsqwk1AUyECtGj+XwGdIi3xABnEqecvXtIJ0wehQXuuER5uZ/5fTs2usONgYjG+iw==" - ], - - "bindings": [ - "bindings@1.5.0", - "", - { "dependencies": { "file-uri-to-path": "1.0.0" } }, - "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==" - ], - - "bintrees": [ - "bintrees@1.0.2", - "", - {}, - "sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==" - ], - - "bl": [ - "bl@2.2.1", - "", - { "dependencies": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" } }, - "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==" - ], - - "bms-table-loader": [ - "bms-table-loader@2.0.0", - "", - { "dependencies": { "node-fetch": "2.6.2", "zod": "^3.19.1" } }, - "sha512-CFCwo6FLVPeDTL64/xhqAVA1dTim3Qm0nbT9nGtDTEMvlLjW83bE8IswUPzX8SSE+k4UCjJ9vgLveuaQ5KbWHQ==" - ], - - "body-parser": [ - "body-parser@1.20.3", - "", - { - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - } - }, - "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==" - ], - - "boolbase": [ - "boolbase@1.0.0", - "", - {}, - "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" - ], - - "bootstrap-scss": [ - "bootstrap-scss@5.3.8", - "", - {}, - "sha512-lDjTMXl2lRwfhGJY3vmDXlWSk50gg7eW2+zzCQi9tsyeZgD6N5hcmMk3G28F7MvLniJKS9LZV+2YNCxiW8+WIw==" - ], - - "bowser": [ - "bowser@2.14.1", - "", - {}, - "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==" - ], - - "brace-expansion": [ - "brace-expansion@1.1.12", - "", - { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==" - ], - - "braces": [ - "braces@3.0.3", - "", - { "dependencies": { "fill-range": "^7.1.1" } }, - "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==" - ], - - "broadcast-channel": [ - "broadcast-channel@3.7.0", - "", - { - "dependencies": { - "@babel/runtime": "^7.7.2", - "detect-node": "^2.1.0", - "js-sha3": "0.8.0", - "microseconds": "0.2.0", - "nano-time": "1.0.0", - "oblivious-set": "1.0.0", - "rimraf": "3.0.2", - "unload": "2.2.0" - } - }, - "sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==" - ], - - "browserslist": [ - "browserslist@4.28.1", - "", - { - "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" - }, - "bin": { "browserslist": "cli.js" } - }, - "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==" - ], - - "bson": [ - "bson@1.1.6", - "", - {}, - "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==" - ], - - "btoa": [ - "btoa@1.2.1", - "", - { "bin": { "btoa": "bin/btoa.js" } }, - "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==" - ], - - "buffer": [ - "buffer@5.7.1", - "", - { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, - "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==" - ], - - "buffer-from": [ - "buffer-from@1.1.2", - "", - {}, - "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - ], - - "bullmq": [ - "bullmq@1.68.4", - "", - { - "dependencies": { - "cron-parser": "^2.18.0", - "get-port": "^5.1.1", - "glob": "^7.2.0", - "ioredis": "^4.28.2", - "lodash": "^4.17.21", - "msgpackr": "^1.4.6", - "semver": "^6.3.0", - "tslib": "^1.14.1", - "uuid": "^8.3.2" - } - }, - "sha512-I0BYxhRocWHcNpzdXX5jR8DwKG1PkGJ8KUt9SJhWCCWd4sYvsMl6KV6J35ZfigGydXuAja19tbEefTUxdVv/sw==" - ], - - "bunyan": [ - "bunyan@1.8.15", - "", - { - "optionalDependencies": { - "dtrace-provider": "~0.8", - "moment": "^2.19.3", - "mv": "~2", - "safe-json-stringify": "~1" - }, - "bin": { "bunyan": "bin/bunyan" } - }, - "sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig==" - ], - - "busboy": [ - "busboy@1.6.0", - "", - { "dependencies": { "streamsearch": "^1.1.0" } }, - "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==" - ], - - "bytes": [ - "bytes@3.1.2", - "", - {}, - "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" - ], - - "cac": [ - "cac@6.7.14", - "", - {}, - "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==" - ], - - "caching-transform": [ - "caching-transform@4.0.0", - "", - { - "dependencies": { - "hasha": "^5.0.0", - "make-dir": "^3.0.0", - "package-hash": "^4.0.0", - "write-file-atomic": "^3.0.0" - } - }, - "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==" - ], - - "call-bind": [ - "call-bind@1.0.8", - "", - { - "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.2" - } - }, - "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==" - ], - - "call-bind-apply-helpers": [ - "call-bind-apply-helpers@1.0.2", - "", - { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, - "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==" - ], - - "call-bound": [ - "call-bound@1.0.4", - "", - { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, - "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==" - ], - - "caller-callsite": [ - "caller-callsite@4.1.0", - "", - { "dependencies": { "callsites": "^3.1.0" } }, - "sha512-99nnnGlJexTc41xwQTr+mWl15OI5PPczUJzM4YRE7QjkefMKCXGa5gfQjCOuVrD+1TjI/fevIDHg2nz3iYN5Ig==" - ], - - "caller-path": [ - "caller-path@3.0.1", - "", - { "dependencies": { "caller-callsite": "^4.1.0" } }, - "sha512-fhmztL4wURO/BzwJUJ4aVRdnKEFskPBbrJ8fNgl7XdUiD1ygzzlt+nhPgUBSRq2ciEVubo6x+W8vJQzm55QLLQ==" - ], - - "callsites": [ - "callsites@3.1.0", - "", - {}, - "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" - ], - - "camel-case": [ - "camel-case@4.1.2", - "", - { "dependencies": { "pascal-case": "^3.1.2", "tslib": "^2.0.3" } }, - "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==" - ], - - "camelcase": [ - "camelcase@5.3.1", - "", - {}, - "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" - ], - - "caniuse-lite": [ - "caniuse-lite@1.0.30001777", - "", - {}, - "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==" - ], - - "cardinal": [ - "cardinal@2.1.1", - "", - { - "dependencies": { "ansicolors": "~0.3.2", "redeyed": "~2.1.0" }, - "bin": { "cdl": "./bin/cdl.js" } - }, - "sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==" - ], - - "caseless": [ - "caseless@0.12.0", - "", - {}, - "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" - ], - - "chai": [ - "chai@5.3.3", - "", - { - "dependencies": { - "assertion-error": "^2.0.1", - "check-error": "^2.1.1", - "deep-eql": "^5.0.1", - "loupe": "^3.1.0", - "pathval": "^2.0.0" - } - }, - "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==" - ], - - "chalk": [ - "chalk@4.1.2", - "", - { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, - "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==" - ], - - "character-entities": [ - "character-entities@2.0.2", - "", - {}, - "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==" - ], - - "check-error": [ - "check-error@2.1.3", - "", - {}, - "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==" - ], - - "cheerio": [ - "cheerio@1.2.0", - "", - { - "dependencies": { - "cheerio-select": "^2.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.3", - "domutils": "^3.2.2", - "encoding-sniffer": "^0.2.1", - "htmlparser2": "^10.1.0", - "parse5": "^7.3.0", - "parse5-htmlparser2-tree-adapter": "^7.1.0", - "parse5-parser-stream": "^7.1.2", - "undici": "^7.19.0", - "whatwg-mimetype": "^4.0.0" - } - }, - "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==" - ], - - "cheerio-select": [ - "cheerio-select@2.1.0", - "", - { - "dependencies": { - "boolbase": "^1.0.0", - "css-select": "^5.1.0", - "css-what": "^6.1.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1" - } - }, - "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==" - ], - - "chokidar": [ - "chokidar@3.6.0", - "", - { - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "optionalDependencies": { "fsevents": "~2.3.2" } - }, - "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==" - ], - - "chownr": [ - "chownr@1.1.4", - "", - {}, - "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - ], - - "ci-info": [ - "ci-info@2.0.0", - "", - {}, - "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" - ], - - "classnames": [ - "classnames@2.5.1", - "", - {}, - "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" - ], - - "clean-css": [ - "clean-css@5.3.3", - "", - { "dependencies": { "source-map": "~0.6.0" } }, - "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==" - ], - - "clean-stack": [ - "clean-stack@2.2.0", - "", - {}, - "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" - ], - - "cli-cursor": [ - "cli-cursor@3.1.0", - "", - { "dependencies": { "restore-cursor": "^3.1.0" } }, - "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==" - ], - - "cli-progress": [ - "cli-progress@3.12.0", - "", - { "dependencies": { "string-width": "^4.2.3" } }, - "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==" - ], - - "cli-truncate": [ - "cli-truncate@2.1.0", - "", - { "dependencies": { "slice-ansi": "^3.0.0", "string-width": "^4.2.0" } }, - "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==" - ], - - "cliui": [ - "cliui@7.0.4", - "", - { - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==" - ], - - "clone": [ - "clone@2.1.2", - "", - {}, - "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==" - ], - - "cluster-key-slot": [ - "cluster-key-slot@1.1.2", - "", - {}, - "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==" - ], - - "color": [ - "color@5.0.3", - "", - { "dependencies": { "color-convert": "^3.1.3", "color-string": "^2.1.3" } }, - "sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==" - ], - - "color-convert": [ - "color-convert@2.0.1", - "", - { "dependencies": { "color-name": "~1.1.4" } }, - "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==" - ], - - "color-name": [ - "color-name@1.1.4", - "", - {}, - "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - ], - - "color-string": [ - "color-string@2.1.4", - "", - { "dependencies": { "color-name": "^2.0.0" } }, - "sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==" - ], - - "color-support": [ - "color-support@1.1.3", - "", - { "bin": { "color-support": "bin.js" } }, - "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" - ], - - "colorette": [ - "colorette@2.0.20", - "", - {}, - "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" - ], - - "combined-stream": [ - "combined-stream@1.0.8", - "", - { "dependencies": { "delayed-stream": "~1.0.0" } }, - "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==" - ], - - "comma-separated-tokens": [ - "comma-separated-tokens@2.0.3", - "", - {}, - "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==" - ], - - "commander": [ - "commander@8.3.0", - "", - {}, - "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==" - ], - - "commist": [ - "commist@1.1.0", - "", - { "dependencies": { "leven": "^2.1.0", "minimist": "^1.1.0" } }, - "sha512-rraC8NXWOEjhADbZe9QBNzLAN5Q3fsTPQtBV+fEVj6xKIgDgNiEVE6ZNfHpZOqfQ21YUzfVNUXLOEZquYvQPPg==" - ], - - "commondir": [ - "commondir@1.0.1", - "", - {}, - "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" - ], - - "component-emitter": [ - "component-emitter@1.3.1", - "", - {}, - "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==" - ], - - "concat-map": [ - "concat-map@0.0.1", - "", - {}, - "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - ], - - "concat-stream": [ - "concat-stream@2.0.0", - "", - { - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.0.2", - "typedarray": "^0.0.6" - } - }, - "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==" - ], - - "connect-history-api-fallback": [ - "connect-history-api-fallback@1.6.0", - "", - {}, - "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==" - ], - - "connect-redis": [ - "connect-redis@6.1.1", - "", - {}, - "sha512-4on27NmUz1hVCVsrUFUOe06YkgCx88ZZ29Wi7D5mXg22alN/Xx+Y+iPrJ1Cc7coUKAe5SP3W2LF/zo6WXSJFFg==" - ], - - "consola": [ - "consola@2.15.3", - "", - {}, - "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" - ], - - "content-disposition": [ - "content-disposition@0.5.4", - "", - { "dependencies": { "safe-buffer": "5.2.1" } }, - "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==" - ], - - "content-type": [ - "content-type@1.0.5", - "", - {}, - "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" - ], - - "convert-source-map": [ - "convert-source-map@1.9.0", - "", - {}, - "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" - ], - - "cookie": [ - "cookie@0.6.0", - "", - {}, - "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" - ], - - "cookie-signature": [ - "cookie-signature@1.0.6", - "", - {}, - "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" - ], - - "cookiejar": [ - "cookiejar@2.1.4", - "", - {}, - "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==" - ], - - "core-js": [ - "core-js@1.2.7", - "", - {}, - "sha512-ZiPp9pZlgxpWRu0M+YWbm6+aQ84XEfH1JRXvfOc/fILWI0VKhLC2LX13X1NYq4fULzLMq7Hfh43CSo2/aIaUPA==" - ], - - "core-util-is": [ - "core-util-is@1.0.3", - "", - {}, - "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - ], - - "cosmiconfig": [ - "cosmiconfig@7.1.0", - "", - { - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - } - }, - "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==" - ], - - "coveralls": [ - "coveralls@3.1.1", - "", - { - "dependencies": { - "js-yaml": "^3.13.1", - "lcov-parse": "^1.0.0", - "log-driver": "^1.2.7", - "minimist": "^1.2.5", - "request": "^2.88.2" - }, - "bin": { "coveralls": "bin/coveralls.js" } - }, - "sha512-+dxnG2NHncSD1NrqbSM3dn/lE57O6Qf/koe9+I7c+wzkqRmEvcp0kgJdxKInzYzkICKkFMZsX3Vct3++tsF9ww==" - ], - - "create-require": [ - "create-require@1.1.1", - "", - {}, - "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" - ], - - "cron-parser": [ - "cron-parser@2.18.0", - "", - { "dependencies": { "is-nan": "^1.3.0", "moment-timezone": "^0.5.31" } }, - "sha512-s4odpheTyydAbTBQepsqd2rNWGa2iV3cyo8g7zbI2QQYGLVsfbhmwukayS1XHppe02Oy1fg7mg6xoaraVJeEcg==" - ], - - "cross-spawn": [ - "cross-spawn@7.0.6", - "", - { - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==" - ], - - "crypto-js": [ - "crypto-js@4.2.0", - "", - {}, - "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" - ], - - "css-select": [ - "css-select@4.3.0", - "", - { - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - } - }, - "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==" - ], - - "css-what": [ - "css-what@6.2.2", - "", - {}, - "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==" - ], - - "csstype": [ - "csstype@3.1.1", - "", - {}, - "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" - ], - - "csv-parse": [ - "csv-parse@5.6.0", - "", - {}, - "sha512-l3nz3euub2QMg5ouu5U09Ew9Wf6/wQ8I++ch1loQ0ljmzhmfZYrH9fflS22i/PQEvsPvxCwxgz5q7UB8K1JO4Q==" - ], - - "d3-array": [ - "d3-array@2.12.1", - "", - { "dependencies": { "internmap": "^1.0.0" } }, - "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==" - ], - - "d3-color": [ - "d3-color@2.0.0", - "", - {}, - "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==" - ], - - "d3-delaunay": [ - "d3-delaunay@5.3.0", - "", - { "dependencies": { "delaunator": "4" } }, - "sha512-amALSrOllWVLaHTnDLHwMIiz0d1bBu9gZXd1FiLfXf8sHcX9jrcj81TVZOqD4UX7MgBZZ07c8GxzEgBpJqc74w==" - ], - - "d3-format": [ - "d3-format@1.4.5", - "", - {}, - "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==" - ], - - "d3-interpolate": [ - "d3-interpolate@2.0.1", - "", - { "dependencies": { "d3-color": "1 - 2" } }, - "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==" - ], - - "d3-path": [ - "d3-path@1.0.9", - "", - {}, - "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" - ], - - "d3-scale": [ - "d3-scale@3.3.0", - "", - { - "dependencies": { - "d3-array": "^2.3.0", - "d3-format": "1 - 2", - "d3-interpolate": "1.2.0 - 2", - "d3-time": "^2.1.1", - "d3-time-format": "2 - 3" - } - }, - "sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==" - ], - - "d3-scale-chromatic": [ - "d3-scale-chromatic@2.0.0", - "", - { "dependencies": { "d3-color": "1 - 2", "d3-interpolate": "1 - 2" } }, - "sha512-LLqy7dJSL8yDy7NRmf6xSlsFZ6zYvJ4BcWFE4zBrOPnQERv9zj24ohnXKRbyi9YHnYV+HN1oEO3iFK971/gkzA==" - ], - - "d3-shape": [ - "d3-shape@1.3.7", - "", - { "dependencies": { "d3-path": "1" } }, - "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==" - ], - - "d3-time": [ - "d3-time@2.1.1", - "", - { "dependencies": { "d3-array": "2" } }, - "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==" - ], - - "d3-time-format": [ - "d3-time-format@3.0.0", - "", - { "dependencies": { "d3-time": "1 - 2" } }, - "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==" - ], - - "damerau-levenshtein": [ - "damerau-levenshtein@1.0.8", - "", - {}, - "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==" - ], - - "dashdash": [ - "dashdash@1.14.1", - "", - { "dependencies": { "assert-plus": "^1.0.0" } }, - "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==" - ], - - "data-view-buffer": [ - "data-view-buffer@1.0.2", - "", - { - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - } - }, - "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==" - ], - - "data-view-byte-length": [ - "data-view-byte-length@1.0.2", - "", - { - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - } - }, - "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==" - ], - - "data-view-byte-offset": [ - "data-view-byte-offset@1.0.1", - "", - { - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - } - }, - "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==" - ], - - "dateformat": [ - "dateformat@4.6.3", - "", - {}, - "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==" - ], - - "debug": [ - "debug@4.4.3", - "", - { "dependencies": { "ms": "^2.1.3" } }, - "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==" - ], - - "decamelize": [ - "decamelize@1.2.0", - "", - {}, - "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==" - ], - - "decode-named-character-reference": [ - "decode-named-character-reference@1.3.0", - "", - { "dependencies": { "character-entities": "^2.0.0" } }, - "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==" - ], - - "decompress-response": [ - "decompress-response@6.0.0", - "", - { "dependencies": { "mimic-response": "^3.1.0" } }, - "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==" - ], - - "deeks": [ - "deeks@2.5.1", - "", - {}, - "sha512-fqrBeUz7f1UqaXDRzVB5RG2EfPk15HJRrb2pMZj8mLlSTtz4tRPsK5leFOskoHFPuyZ6+7aRM9j657fvXLkJ7Q==" - ], - - "deep-eql": [ - "deep-eql@5.0.2", - "", - {}, - "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==" - ], - - "deep-extend": [ - "deep-extend@0.6.0", - "", - {}, - "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" - ], - - "deep-is": [ - "deep-is@0.1.4", - "", - {}, - "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" - ], - - "deepmerge": [ - "deepmerge@4.3.1", - "", - {}, - "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==" - ], - - "default-require-extensions": [ - "default-require-extensions@3.0.1", - "", - { "dependencies": { "strip-bom": "^4.0.0" } }, - "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==" - ], - - "defaults": [ - "defaults@1.0.4", - "", - { "dependencies": { "clone": "^1.0.2" } }, - "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==" - ], - - "define-data-property": [ - "define-data-property@1.1.4", - "", - { - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - } - }, - "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==" - ], - - "define-properties": [ - "define-properties@1.2.1", - "", - { - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - } - }, - "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==" - ], - - "delaunator": [ - "delaunator@4.0.1", - "", - {}, - "sha512-WNPWi1IRKZfCt/qIDMfERkDp93+iZEmOxN2yy4Jg+Xhv8SLk2UTqqbe1sfiipn0and9QrE914/ihdx82Y/Giag==" - ], - - "delayed-stream": [ - "delayed-stream@1.0.0", - "", - {}, - "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" - ], - - "denque": [ - "denque@1.5.1", - "", - {}, - "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==" - ], - - "depd": [ - "depd@2.0.0", - "", - {}, - "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - ], - - "dequal": [ - "dequal@2.0.3", - "", - {}, - "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==" - ], - - "destroy": [ - "destroy@1.2.0", - "", - {}, - "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" - ], - - "detect-libc": [ - "detect-libc@2.1.2", - "", - {}, - "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==" - ], - - "detect-node": [ - "detect-node@2.1.0", - "", - {}, - "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" - ], - - "dezalgo": [ - "dezalgo@1.0.4", - "", - { "dependencies": { "asap": "^2.0.0", "wrappy": "1" } }, - "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==" - ], - - "diff": [ - "diff@4.0.4", - "", - {}, - "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==" - ], - - "dir-glob": [ - "dir-glob@3.0.1", - "", - { "dependencies": { "path-type": "^4.0.0" } }, - "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==" - ], - - "discord-api-types": [ - "discord-api-types@0.22.0", - "", - {}, - "sha512-l8yD/2zRbZItUQpy7ZxBJwaLX/Bs2TGaCthRppk8Sw24LOIWg12t9JEreezPoYD0SQcC2htNNo27kYEpYW/Srg==" - ], - - "discord.js": [ - "discord.js@13.6.0", - "", - { - "dependencies": { - "@discordjs/builders": "^0.11.0", - "@discordjs/collection": "^0.4.0", - "@sapphire/async-queue": "^1.1.9", - "@types/node-fetch": "^2.5.12", - "@types/ws": "^8.2.2", - "discord-api-types": "^0.26.0", - "form-data": "^4.0.0", - "node-fetch": "^2.6.1", - "ws": "^8.4.0" - } - }, - "sha512-tXNR8zgsEPxPBvGk3AQjJ9ljIIC6/LOPjzKwpwz8Y1Q2X66Vi3ZqFgRHYwnHKC0jC0F+l4LzxlhmOJsBZDNg9g==" - ], - - "doc-path": [ - "doc-path@3.0.2", - "", - {}, - "sha512-VRlA2OKSjTbHWj6wmSanxJ338fE/YN8pqmZ0FIWK5JWkIJMFRc4KmD35JtOrnjvVG0WrzOtDDNHx1lN1tkb+lA==" - ], - - "doctrine": [ - "doctrine@2.1.0", - "", - { "dependencies": { "esutils": "^2.0.2" } }, - "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==" - ], - - "dom-helpers": [ - "dom-helpers@5.2.1", - "", - { "dependencies": { "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" } }, - "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==" - ], - - "dom-serializer": [ - "dom-serializer@2.0.0", - "", - { - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - } - }, - "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==" - ], - - "domelementtype": [ - "domelementtype@2.3.0", - "", - {}, - "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" - ], - - "domhandler": [ - "domhandler@5.0.3", - "", - { "dependencies": { "domelementtype": "^2.3.0" } }, - "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==" - ], - - "domutils": [ - "domutils@3.2.2", - "", - { - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - } - }, - "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==" - ], - - "dot-case": [ - "dot-case@3.0.4", - "", - { "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" } }, - "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==" - ], - - "dot-prop": [ - "dot-prop@6.0.1", - "", - { "dependencies": { "is-obj": "^2.0.0" } }, - "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==" - ], - - "dotenv": [ - "dotenv@16.0.0", - "", - {}, - "sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==" - ], - - "dotenv-expand": [ - "dotenv-expand@8.0.3", - "", - {}, - "sha512-SErOMvge0ZUyWd5B0NXMQlDkN+8r+HhVUsxgOO7IoPDOdDRD2JjExpN6y3KnFR66jsJMwSn1pqIivhU5rcJiNg==" - ], - - "dtrace-provider": [ - "dtrace-provider@0.8.8", - "", - { "dependencies": { "nan": "^2.14.0" } }, - "sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==" - ], - - "dunder-proto": [ - "dunder-proto@1.0.1", - "", - { - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - } - }, - "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==" - ], - - "duplexify": [ - "duplexify@3.7.1", - "", - { - "dependencies": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==" - ], - - "eastasianwidth": [ - "eastasianwidth@0.2.0", - "", - {}, - "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" - ], - - "ecc-jsbn": [ - "ecc-jsbn@0.1.2", - "", - { "dependencies": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" } }, - "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==" - ], - - "ee-first": [ - "ee-first@1.1.1", - "", - {}, - "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" - ], - - "ejs": [ - "ejs@3.1.10", - "", - { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, - "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==" - ], - - "electron-to-chromium": [ - "electron-to-chromium@1.5.307", - "", - {}, - "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==" - ], - - "emoji-regex": [ - "emoji-regex@9.2.2", - "", - {}, - "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" - ], - - "enabled": [ - "enabled@2.0.0", - "", - {}, - "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" - ], - - "encodeurl": [ - "encodeurl@2.0.0", - "", - {}, - "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" - ], - - "encoding": [ - "encoding@0.1.13", - "", - { "dependencies": { "iconv-lite": "^0.6.2" } }, - "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==" - ], - - "encoding-japanese": [ - "encoding-japanese@1.0.30", - "", - {}, - "sha512-bd/DFLAoJetvv7ar/KIpE3CNO8wEuyrt9Xuw6nSMiZ+Vrz/Q21BPsMHvARL2Wz6IKHKXgb+DWZqtRg1vql9cBg==" - ], - - "encoding-sniffer": [ - "encoding-sniffer@0.2.1", - "", - { "dependencies": { "iconv-lite": "^0.6.3", "whatwg-encoding": "^3.1.1" } }, - "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==" - ], - - "end-of-stream": [ - "end-of-stream@1.4.5", - "", - { "dependencies": { "once": "^1.4.0" } }, - "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==" - ], - - "entities": [ - "entities@2.2.0", - "", - {}, - "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" - ], - - "error-ex": [ - "error-ex@1.3.4", - "", - { "dependencies": { "is-arrayish": "^0.2.1" } }, - "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==" - ], - - "es-abstract": [ - "es-abstract@1.24.1", - "", - { - "dependencies": { - "array-buffer-byte-length": "^1.0.2", - "arraybuffer.prototype.slice": "^1.0.4", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "data-view-buffer": "^1.0.2", - "data-view-byte-length": "^1.0.2", - "data-view-byte-offset": "^1.0.1", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-set-tostringtag": "^2.1.0", - "es-to-primitive": "^1.3.0", - "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.3.0", - "get-proto": "^1.0.1", - "get-symbol-description": "^1.1.0", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "internal-slot": "^1.1.0", - "is-array-buffer": "^3.0.5", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.2", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.2.1", - "is-set": "^2.0.3", - "is-shared-array-buffer": "^1.0.4", - "is-string": "^1.1.1", - "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.1", - "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.4", - "object-keys": "^1.1.1", - "object.assign": "^4.1.7", - "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.4", - "safe-array-concat": "^1.1.3", - "safe-push-apply": "^1.0.0", - "safe-regex-test": "^1.1.0", - "set-proto": "^1.0.0", - "stop-iteration-iterator": "^1.1.0", - "string.prototype.trim": "^1.2.10", - "string.prototype.trimend": "^1.0.9", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.3", - "typed-array-byte-length": "^1.0.3", - "typed-array-byte-offset": "^1.0.4", - "typed-array-length": "^1.0.7", - "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.19" - } - }, - "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==" - ], - - "es-define-property": [ - "es-define-property@1.0.1", - "", - {}, - "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==" - ], - - "es-errors": [ - "es-errors@1.3.0", - "", - {}, - "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" - ], - - "es-iterator-helpers": [ - "es-iterator-helpers@1.2.2", - "", - { - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.24.1", - "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.1.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.3.0", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "internal-slot": "^1.1.0", - "iterator.prototype": "^1.1.5", - "safe-array-concat": "^1.1.3" - } - }, - "sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w==" - ], - - "es-module-lexer": [ - "es-module-lexer@1.7.0", - "", - {}, - "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==" - ], - - "es-object-atoms": [ - "es-object-atoms@1.1.1", - "", - { "dependencies": { "es-errors": "^1.3.0" } }, - "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==" - ], - - "es-set-tostringtag": [ - "es-set-tostringtag@2.1.0", - "", - { - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - } - }, - "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==" - ], - - "es-shim-unscopables": [ - "es-shim-unscopables@1.1.0", - "", - { "dependencies": { "hasown": "^2.0.2" } }, - "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==" - ], - - "es-to-primitive": [ - "es-to-primitive@1.3.0", - "", - { - "dependencies": { - "is-callable": "^1.2.7", - "is-date-object": "^1.0.5", - "is-symbol": "^1.0.4" - } - }, - "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==" - ], - - "es6-error": [ - "es6-error@4.1.1", - "", - {}, - "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==" - ], - - "esbuild": [ - "esbuild@0.27.3", - "", - { - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", - "@esbuild/darwin-arm64": "0.27.3", - "@esbuild/darwin-x64": "0.27.3", - "@esbuild/freebsd-arm64": "0.27.3", - "@esbuild/freebsd-x64": "0.27.3", - "@esbuild/linux-arm": "0.27.3", - "@esbuild/linux-arm64": "0.27.3", - "@esbuild/linux-ia32": "0.27.3", - "@esbuild/linux-loong64": "0.27.3", - "@esbuild/linux-mips64el": "0.27.3", - "@esbuild/linux-ppc64": "0.27.3", - "@esbuild/linux-riscv64": "0.27.3", - "@esbuild/linux-s390x": "0.27.3", - "@esbuild/linux-x64": "0.27.3", - "@esbuild/netbsd-arm64": "0.27.3", - "@esbuild/netbsd-x64": "0.27.3", - "@esbuild/openbsd-arm64": "0.27.3", - "@esbuild/openbsd-x64": "0.27.3", - "@esbuild/openharmony-arm64": "0.27.3", - "@esbuild/sunos-x64": "0.27.3", - "@esbuild/win32-arm64": "0.27.3", - "@esbuild/win32-ia32": "0.27.3", - "@esbuild/win32-x64": "0.27.3" - }, - "bin": { "esbuild": "bin/esbuild" } - }, - "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==" - ], - - "esbuild-android-64": [ - "esbuild-android-64@0.15.18", - "", - { "os": "android", "cpu": "x64" }, - "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==" - ], - - "esbuild-android-arm64": [ - "esbuild-android-arm64@0.15.18", - "", - { "os": "android", "cpu": "arm64" }, - "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==" - ], - - "esbuild-darwin-64": [ - "esbuild-darwin-64@0.15.18", - "", - { "os": "darwin", "cpu": "x64" }, - "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==" - ], - - "esbuild-darwin-arm64": [ - "esbuild-darwin-arm64@0.15.18", - "", - { "os": "darwin", "cpu": "arm64" }, - "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==" - ], - - "esbuild-freebsd-64": [ - "esbuild-freebsd-64@0.15.18", - "", - { "os": "freebsd", "cpu": "x64" }, - "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==" - ], - - "esbuild-freebsd-arm64": [ - "esbuild-freebsd-arm64@0.15.18", - "", - { "os": "freebsd", "cpu": "arm64" }, - "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==" - ], - - "esbuild-linux-32": [ - "esbuild-linux-32@0.15.18", - "", - { "os": "linux", "cpu": "ia32" }, - "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==" - ], - - "esbuild-linux-64": [ - "esbuild-linux-64@0.15.18", - "", - { "os": "linux", "cpu": "x64" }, - "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==" - ], - - "esbuild-linux-arm": [ - "esbuild-linux-arm@0.15.18", - "", - { "os": "linux", "cpu": "arm" }, - "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==" - ], - - "esbuild-linux-arm64": [ - "esbuild-linux-arm64@0.15.18", - "", - { "os": "linux", "cpu": "arm64" }, - "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==" - ], - - "esbuild-linux-mips64le": [ - "esbuild-linux-mips64le@0.15.18", - "", - { "os": "linux", "cpu": "none" }, - "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==" - ], - - "esbuild-linux-ppc64le": [ - "esbuild-linux-ppc64le@0.15.18", - "", - { "os": "linux", "cpu": "ppc64" }, - "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==" - ], - - "esbuild-linux-riscv64": [ - "esbuild-linux-riscv64@0.15.18", - "", - { "os": "linux", "cpu": "none" }, - "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==" - ], - - "esbuild-linux-s390x": [ - "esbuild-linux-s390x@0.15.18", - "", - { "os": "linux", "cpu": "s390x" }, - "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==" - ], - - "esbuild-netbsd-64": [ - "esbuild-netbsd-64@0.15.18", - "", - { "os": "none", "cpu": "x64" }, - "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==" - ], - - "esbuild-openbsd-64": [ - "esbuild-openbsd-64@0.15.18", - "", - { "os": "openbsd", "cpu": "x64" }, - "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==" - ], - - "esbuild-sunos-64": [ - "esbuild-sunos-64@0.15.18", - "", - { "os": "sunos", "cpu": "x64" }, - "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==" - ], - - "esbuild-windows-32": [ - "esbuild-windows-32@0.15.18", - "", - { "os": "win32", "cpu": "ia32" }, - "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==" - ], - - "esbuild-windows-64": [ - "esbuild-windows-64@0.15.18", - "", - { "os": "win32", "cpu": "x64" }, - "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==" - ], - - "esbuild-windows-arm64": [ - "esbuild-windows-arm64@0.15.18", - "", - { "os": "win32", "cpu": "arm64" }, - "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==" - ], - - "escalade": [ - "escalade@3.2.0", - "", - {}, - "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==" - ], - - "escape-html": [ - "escape-html@1.0.3", - "", - {}, - "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - ], - - "escape-string-regexp": [ - "escape-string-regexp@4.0.0", - "", - {}, - "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" - ], - - "eslint": [ - "eslint@9.39.4", - "", - { - "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.2", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.5", - "@eslint/js": "9.39.4", - "@eslint/plugin-kit": "^0.4.1", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.14.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.5", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "peerDependencies": { "jiti": "*" }, - "optionalPeers": ["jiti"], - "bin": { "eslint": "bin/eslint.js" } - }, - "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==" - ], - - "eslint-config-prettier": [ - "eslint-config-prettier@9.1.2", - "", - { - "peerDependencies": { "eslint": ">=7.0.0" }, - "bin": { "eslint-config-prettier": "bin/cli.js" } - }, - "sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==" - ], - - "eslint-config-tachi": ["eslint-config-tachi@workspace:typescript/eslint-config"], - - "eslint-import-resolver-node": [ - "eslint-import-resolver-node@0.3.9", - "", - { - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - } - }, - "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==" - ], - - "eslint-import-resolver-typescript": [ - "eslint-import-resolver-typescript@3.10.1", - "", - { - "dependencies": { - "@nolyfill/is-core-module": "1.0.39", - "debug": "^4.4.0", - "get-tsconfig": "^4.10.0", - "is-bun-module": "^2.0.0", - "stable-hash": "^0.0.5", - "tinyglobby": "^0.2.13", - "unrs-resolver": "^1.6.2" - }, - "peerDependencies": { - "eslint": "*", - "eslint-plugin-import": "*", - "eslint-plugin-import-x": "*" - }, - "optionalPeers": ["eslint-plugin-import", "eslint-plugin-import-x"] - }, - "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==" - ], - - "eslint-module-utils": [ - "eslint-module-utils@2.12.1", - "", - { "dependencies": { "debug": "^3.2.7" } }, - "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==" - ], - - "eslint-plugin-import": [ - "eslint-plugin-import@2.32.0", - "", - { - "dependencies": { - "@rtsao/scc": "^1.1.0", - "array-includes": "^3.1.9", - "array.prototype.findlastindex": "^1.2.6", - "array.prototype.flat": "^1.3.3", - "array.prototype.flatmap": "^1.3.3", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.12.1", - "hasown": "^2.0.2", - "is-core-module": "^2.16.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "object.groupby": "^1.0.3", - "object.values": "^1.2.1", - "semver": "^6.3.1", - "string.prototype.trimend": "^1.0.9", - "tsconfig-paths": "^3.15.0" - }, - "peerDependencies": { "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } - }, - "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==" - ], - - "eslint-plugin-jsx-a11y": [ - "eslint-plugin-jsx-a11y@6.10.2", - "", - { - "dependencies": { - "aria-query": "^5.3.2", - "array-includes": "^3.1.8", - "array.prototype.flatmap": "^1.3.2", - "ast-types-flow": "^0.0.8", - "axe-core": "^4.10.0", - "axobject-query": "^4.1.0", - "damerau-levenshtein": "^1.0.8", - "emoji-regex": "^9.2.2", - "hasown": "^2.0.2", - "jsx-ast-utils": "^3.3.5", - "language-tags": "^1.0.9", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "safe-regex-test": "^1.0.3", - "string.prototype.includes": "^2.0.1" - }, - "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" } - }, - "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==" - ], - - "eslint-plugin-perfectionist": [ - "eslint-plugin-perfectionist@3.9.1", - "", - { - "dependencies": { - "@typescript-eslint/types": "^8.9.0", - "@typescript-eslint/utils": "^8.9.0", - "minimatch": "^9.0.5", - "natural-compare-lite": "^1.4.0" - }, - "peerDependencies": { - "astro-eslint-parser": "^1.0.2", - "eslint": ">=8.0.0", - "svelte": ">=3.0.0", - "svelte-eslint-parser": "^0.41.1", - "vue-eslint-parser": ">=9.0.0" - }, - "optionalPeers": [ - "astro-eslint-parser", - "svelte", - "svelte-eslint-parser", - "vue-eslint-parser" - ] - }, - "sha512-9WRzf6XaAxF4Oi5t/3TqKP5zUjERhasHmLFHin2Yw6ZAp/EP/EVA2dr3BhQrrHWCm5SzTMZf0FcjDnBkO2xFkA==" - ], - - "eslint-plugin-react": [ - "eslint-plugin-react@7.37.5", - "", - { - "dependencies": { - "array-includes": "^3.1.8", - "array.prototype.findlast": "^1.2.5", - "array.prototype.flatmap": "^1.3.3", - "array.prototype.tosorted": "^1.1.4", - "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.2.1", - "estraverse": "^5.3.0", - "hasown": "^2.0.2", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.9", - "object.fromentries": "^2.0.8", - "object.values": "^1.2.1", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.5", - "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.12", - "string.prototype.repeat": "^1.0.0" - }, - "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } - }, - "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==" - ], - - "eslint-plugin-react-hooks": [ - "eslint-plugin-react-hooks@5.2.0", - "", - { - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" - } - }, - "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==" - ], - - "eslint-plugin-react-refresh": [ - "eslint-plugin-react-refresh@0.4.26", - "", - { "peerDependencies": { "eslint": ">=8.40" } }, - "sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==" - ], - - "eslint-scope": [ - "eslint-scope@8.4.0", - "", - { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, - "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==" - ], - - "eslint-utils": [ - "eslint-utils@3.0.0", - "", - { - "dependencies": { "eslint-visitor-keys": "^2.0.0" }, - "peerDependencies": { "eslint": ">=5" } - }, - "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==" - ], - - "eslint-visitor-keys": [ - "eslint-visitor-keys@4.2.1", - "", - {}, - "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==" - ], - - "esm": [ - "esm@3.2.25", - "", - {}, - "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==" - ], - - "espree": [ - "espree@10.4.0", - "", - { - "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" - } - }, - "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==" - ], - - "esprima": [ - "esprima@4.0.1", - "", - { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, - "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" - ], - - "esquery": [ - "esquery@1.7.0", - "", - { "dependencies": { "estraverse": "^5.1.0" } }, - "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==" - ], - - "esrecurse": [ - "esrecurse@4.3.0", - "", - { "dependencies": { "estraverse": "^5.2.0" } }, - "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==" - ], - - "estraverse": [ - "estraverse@5.3.0", - "", - {}, - "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" - ], - - "estree-walker": [ - "estree-walker@3.0.3", - "", - { "dependencies": { "@types/estree": "^1.0.0" } }, - "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==" - ], - - "esutils": [ - "esutils@2.0.3", - "", - {}, - "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" - ], - - "etag": [ - "etag@1.8.1", - "", - {}, - "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" - ], - - "event-target-shim": [ - "event-target-shim@5.0.1", - "", - {}, - "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" - ], - - "events-to-array": [ - "events-to-array@1.1.2", - "", - {}, - "sha512-inRWzRY7nG+aXZxBzEqYKB3HPgwflZRopAjDCHv0whhRx+MTUr1ei0ICZUypdyE0HRm4L2d5VEcIqLD6yl+BFA==" - ], - - "expand-template": [ - "expand-template@2.0.3", - "", - {}, - "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" - ], - - "expect-type": [ - "expect-type@1.3.0", - "", - {}, - "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==" - ], - - "express": [ - "express@4.20.0", - "", - { - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.6.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - } - }, - "sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==" - ], - - "express-async-errors": [ - "express-async-errors@3.1.1", - "", - { "peerDependencies": { "express": "^4.16.2" } }, - "sha512-h6aK1da4tpqWSbyCa3FxB/V6Ehd4EEB15zyQq9qe75OZBp0krinNKuH4rAY+S/U/2I36vdLAUFSjQJ+TFmODng==" - ], - - "express-prom-bundle": [ - "express-prom-bundle@7.0.2", - "", - { - "dependencies": { - "@types/express": "^4.17.21", - "express": "^4.18.2", - "on-finished": "^2.3.0", - "url-value-parser": "^2.0.0" - }, - "peerDependencies": { "prom-client": ">=15.0.0" } - }, - "sha512-ffFV4HGHvCKnkNJFqm42sYztRJE5mLgOj8MpGey1HOatuFhtcwXoBD2m5gca7ZbcyjkIf7lOH5ZdrhlrBf0sGw==" - ], - - "express-rate-limit": [ - "express-rate-limit@5.5.1", - "", - {}, - "sha512-MTjE2eIbHv5DyfuFz4zLYWxpqVhEhkTiwFGuB74Q9CSou2WHO52nlE5y3Zlg6SIsiYUIPj6ifFxnkPz6O3sIUg==" - ], - - "express-session": [ - "express-session@1.17.2", - "", - { - "dependencies": { - "cookie": "0.4.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~2.0.0", - "on-headers": "~1.0.2", - "parseurl": "~1.3.3", - "safe-buffer": "5.2.1", - "uid-safe": "~2.1.5" - } - }, - "sha512-mPcYcLA0lvh7D4Oqr5aNJFMtBMKPLl++OKKxkHzZ0U0oDq1rpKBnkR5f5vCHR26VeArlTOEF9td4x5IjICksRQ==" - ], - - "extend": [ - "extend@3.0.2", - "", - {}, - "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - ], - - "extract-pg-schema": [ - "extract-pg-schema@5.8.1", - "", - { - "dependencies": { - "knex": "3.1.0", - "knex-pglite": "^0.12.0", - "pg": "8.17.2", - "pg-query-emscripten": "^5.1.0", - "ramda": "^0.31.0" - }, - "bin": { "extract-pg-schema": "bin/extract-pg-schema" } - }, - "sha512-rNotRBXxWQnvjcErsX3k9cZwY4KQbVniEp+KAd6RghfDvt29kOtnDdfO7S+Y6b/5tge6caovbJq8s9cgsUtBUA==" - ], - - "extsprintf": [ - "extsprintf@1.3.0", - "", - {}, - "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==" - ], - - "fast-content-type-parse": [ - "fast-content-type-parse@2.0.1", - "", - {}, - "sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q==" - ], - - "fast-copy": [ - "fast-copy@4.0.2", - "", - {}, - "sha512-ybA6PDXIXOXivLJK/z9e+Otk7ve13I4ckBvGO5I2RRmBU1gMHLVDJYEuJYhGwez7YNlYji2M2DvVU+a9mSFDlw==" - ], - - "fast-deep-equal": [ - "fast-deep-equal@3.1.3", - "", - {}, - "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - ], - - "fast-glob": [ - "fast-glob@3.3.3", - "", - { - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - } - }, - "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==" - ], - - "fast-json-stable-hash": [ - "fast-json-stable-hash@1.0.3", - "", - {}, - "sha512-iLK3Tq2J/KbiUn/5OHyhxikHqzwFXSM2e803Dp2JtBdQjsCVuZwWvL+WqWXPPRUEuDX4c0kqID1SU84RCfxs3A==" - ], - - "fast-json-stable-stringify": [ - "fast-json-stable-stringify@2.1.0", - "", - {}, - "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - ], - - "fast-levenshtein": [ - "fast-levenshtein@2.0.6", - "", - {}, - "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" - ], - - "fast-safe-stringify": [ - "fast-safe-stringify@2.1.1", - "", - {}, - "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" - ], - - "fast-xml-parser": [ - "fast-xml-parser@4.5.4", - "", - { "dependencies": { "strnum": "^1.0.5" }, "bin": { "fxparser": "src/cli/cli.js" } }, - "sha512-jE8ugADnYOBsu1uaoayVl1tVKAMNOXyjwvv2U6udEA2ORBhDooJDWoGxTkhd4Qn4yh59JVVt/pKXtjPwx9OguQ==" - ], - - "fastq": [ - "fastq@1.20.1", - "", - { "dependencies": { "reusify": "^1.0.4" } }, - "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==" - ], - - "fbjs": [ - "fbjs@0.8.18", - "", - { - "dependencies": { - "core-js": "^1.0.0", - "isomorphic-fetch": "^2.1.1", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.30" - } - }, - "sha512-EQaWFK+fEPSoibjNy8IxUtaFOMXcWsY0JaVrQoZR9zC8N2Ygf9iDITPWjUTVIax95b6I742JFLqASHfsag/vKA==" - ], - - "fdir": [ - "fdir@6.5.0", - "", - { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, - "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==" - ], - - "fecha": [ - "fecha@4.2.3", - "", - {}, - "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" - ], - - "file-entry-cache": [ - "file-entry-cache@8.0.0", - "", - { "dependencies": { "flat-cache": "^4.0.0" } }, - "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==" - ], - - "file-uri-to-path": [ - "file-uri-to-path@1.0.0", - "", - {}, - "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" - ], - - "filelist": [ - "filelist@1.0.6", - "", - { "dependencies": { "minimatch": "^5.0.1" } }, - "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==" - ], - - "fill-range": [ - "fill-range@7.1.1", - "", - { "dependencies": { "to-regex-range": "^5.0.1" } }, - "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==" - ], - - "finalhandler": [ - "finalhandler@1.2.0", - "", - { - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - } - }, - "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==" - ], - - "find-cache-dir": [ - "find-cache-dir@3.3.2", - "", - { - "dependencies": { "commondir": "^1.0.1", "make-dir": "^3.0.2", "pkg-dir": "^4.1.0" } - }, - "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==" - ], - - "find-root": [ - "find-root@1.1.0", - "", - {}, - "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" - ], - - "find-up": [ - "find-up@5.0.0", - "", - { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, - "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==" - ], - - "findit": [ - "findit@2.0.0", - "", - {}, - "sha512-ENZS237/Hr8bjczn5eKuBohLgaD0JyUd0arxretR1f9RO46vZHA1b2y0VorgGV3WaOT3c+78P8h7v4JGJ1i/rg==" - ], - - "flat-cache": [ - "flat-cache@4.0.1", - "", - { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, - "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==" - ], - - "flatted": [ - "flatted@3.4.0", - "", - {}, - "sha512-kC6Bb+ooptOIvWj5B63EQWkF0FEnNjV2ZNkLMLZRDDduIiWeFF4iKnslwhiWxjAdbg4NzTNo6h0qLuvFrcx+Sw==" - ], - - "flow-remove-types": [ - "flow-remove-types@2.304.0", - "", - { - "dependencies": { "hermes-parser": "0.33.3", "pirates": "^3.0.2", "vlq": "^0.2.1" }, - "bin": { "flow-remove-types": "flow-remove-types", "flow-node": "flow-node" } - }, - "sha512-3/c6h0ELxBY5I4MEDig6c0gjlT6GYGfxH0VlpgPOF2/78VaI01RPPnVoVyaixJs8uexsAeycxlxd4feIHPYPrQ==" - ], - - "fn.name": [ - "fn.name@1.1.0", - "", - {}, - "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" - ], - - "follow-redirects": [ - "follow-redirects@1.15.11", - "", - {}, - "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==" - ], - - "for-each": [ - "for-each@0.3.5", - "", - { "dependencies": { "is-callable": "^1.2.7" } }, - "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==" - ], - - "foreground-child": [ - "foreground-child@2.0.0", - "", - { "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^3.0.2" } }, - "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==" - ], - - "forever-agent": [ - "forever-agent@0.6.1", - "", - {}, - "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==" - ], - - "form-data": [ - "form-data@3.0.4", - "", - { - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.35" - } - }, - "sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ==" - ], - - "formidable": [ - "formidable@2.1.5", - "", - { - "dependencies": { - "@paralleldrive/cuid2": "^2.2.2", - "dezalgo": "^1.0.4", - "once": "^1.4.0", - "qs": "^6.11.0" - } - }, - "sha512-Oz5Hwvwak/DCaXVVUtPn4oLMLLy1CdclLKO1LFgU7XzDpVMUU5UjlSLpGMocyQNNk8F6IJW9M/YdooSn2MRI+Q==" - ], - - "formik": [ - "formik@2.2.9", - "", - { - "dependencies": { - "deepmerge": "^2.1.1", - "hoist-non-react-statics": "^3.3.0", - "lodash": "^4.17.21", - "lodash-es": "^4.17.21", - "react-fast-compare": "^2.0.1", - "tiny-warning": "^1.0.2", - "tslib": "^1.10.0" - }, - "peerDependencies": { "react": ">=16.8.0" } - }, - "sha512-LQLcISMmf1r5at4/gyJigGn0gOwFbeEAlji+N9InZF6LIMXnFNkO42sCI8Jt84YZggpD4cPWObAZaxpEFtSzNA==" - ], - - "forwarded": [ - "forwarded@0.2.0", - "", - {}, - "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" - ], - - "fresh": [ - "fresh@0.5.2", - "", - {}, - "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" - ], - - "fromentries": [ - "fromentries@1.3.2", - "", - {}, - "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==" - ], - - "fs-constants": [ - "fs-constants@1.0.0", - "", - {}, - "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" - ], - - "fs-exists-cached": [ - "fs-exists-cached@1.0.0", - "", - {}, - "sha512-kSxoARUDn4F2RPXX48UXnaFKwVU7Ivd/6qpzZL29MCDmr9sTvybv4gFCp+qaI4fM9m0z9fgz/yJvi56GAz+BZg==" - ], - - "fs-extra": [ - "fs-extra@7.0.1", - "", - { - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==" - ], - - "fs.realpath": [ - "fs.realpath@1.0.0", - "", - {}, - "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - ], - - "fsevents": [ - "fsevents@2.3.3", - "", - { "os": "darwin" }, - "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==" - ], - - "function-bind": [ - "function-bind@1.1.2", - "", - {}, - "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" - ], - - "function-loop": [ - "function-loop@2.0.1", - "", - {}, - "sha512-ktIR+O6i/4h+j/ZhZJNdzeI4i9lEPeEK6UPR2EVyTVBqOwcU3Za9xYKLH64ZR9HmcROyRrOkizNyjjtWJzDDkQ==" - ], - - "function.prototype.name": [ - "function.prototype.name@1.1.8", - "", - { - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "functions-have-names": "^1.2.3", - "hasown": "^2.0.2", - "is-callable": "^1.2.7" - } - }, - "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==" - ], - - "functional-red-black-tree": [ - "functional-red-black-tree@1.0.1", - "", - {}, - "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==" - ], - - "functions-have-names": [ - "functions-have-names@1.2.3", - "", - {}, - "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" - ], - - "generator-function": [ - "generator-function@2.0.1", - "", - {}, - "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==" - ], - - "gensync": [ - "gensync@1.0.0-beta.2", - "", - {}, - "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" - ], - - "get-caller-file": [ - "get-caller-file@2.0.5", - "", - {}, - "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" - ], - - "get-intrinsic": [ - "get-intrinsic@1.3.0", - "", - { - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - } - }, - "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==" - ], - - "get-package-type": [ - "get-package-type@0.1.0", - "", - {}, - "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==" - ], - - "get-port": [ - "get-port@5.1.1", - "", - {}, - "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==" - ], - - "get-proto": [ - "get-proto@1.0.1", - "", - { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, - "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==" - ], - - "get-symbol-description": [ - "get-symbol-description@1.1.0", - "", - { - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6" - } - }, - "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==" - ], - - "get-tsconfig": [ - "get-tsconfig@4.13.6", - "", - { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, - "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==" - ], - - "getopts": [ - "getopts@2.3.0", - "", - {}, - "sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA==" - ], - - "getpass": [ - "getpass@0.1.7", - "", - { "dependencies": { "assert-plus": "^1.0.0" } }, - "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==" - ], - - "github-from-package": [ - "github-from-package@0.0.0", - "", - {}, - "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" - ], - - "glob": [ - "glob@7.2.3", - "", - { - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==" - ], - - "glob-parent": [ - "glob-parent@6.0.2", - "", - { "dependencies": { "is-glob": "^4.0.3" } }, - "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==" - ], - - "globals": [ - "globals@15.15.0", - "", - {}, - "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==" - ], - - "globalthis": [ - "globalthis@1.0.4", - "", - { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, - "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==" - ], - - "globby": [ - "globby@11.1.0", - "", - { - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==" - ], - - "goober": [ - "goober@2.1.18", - "", - { "peerDependencies": { "csstype": "^3.0.10" } }, - "sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw==" - ], - - "google-protobuf": [ - "google-protobuf@3.21.4", - "", - {}, - "sha512-MnG7N936zcKTco4Jd2PX2U96Kf9PxygAPKBug+74LHzmHXmceN16MmRcdgZv+DGef/S9YvQAfRsNCn4cjf9yyQ==" - ], - - "gopd": [ - "gopd@1.2.0", - "", - {}, - "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" - ], - - "graceful-fs": [ - "graceful-fs@4.2.11", - "", - {}, - "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" - ], - - "grpc-tools": [ - "grpc-tools@1.13.1", - "", - { - "dependencies": { "@mapbox/node-pre-gyp": "^2.0.0" }, - "bin": { - "grpc_tools_node_protoc": "bin/protoc.js", - "grpc_tools_node_protoc_plugin": "bin/protoc_plugin.js" - } - }, - "sha512-0sttMUxThNIkCTJq5qI0xXMz5zWqV2u3yG1kR3Sj9OokGIoyRBFjoInK9NyW7x5fH7knj48Roh1gq5xbl0VoDQ==" - ], - - "har-schema": [ - "har-schema@2.0.0", - "", - {}, - "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==" - ], - - "har-validator": [ - "har-validator@5.1.5", - "", - { "dependencies": { "ajv": "^6.12.3", "har-schema": "^2.0.0" } }, - "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==" - ], - - "has-bigints": [ - "has-bigints@1.1.0", - "", - {}, - "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==" - ], - - "has-flag": [ - "has-flag@4.0.0", - "", - {}, - "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - ], - - "has-property-descriptors": [ - "has-property-descriptors@1.0.2", - "", - { "dependencies": { "es-define-property": "^1.0.0" } }, - "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==" - ], - - "has-proto": [ - "has-proto@1.2.0", - "", - { "dependencies": { "dunder-proto": "^1.0.0" } }, - "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==" - ], - - "has-symbols": [ - "has-symbols@1.1.0", - "", - {}, - "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==" - ], - - "has-tostringtag": [ - "has-tostringtag@1.0.2", - "", - { "dependencies": { "has-symbols": "^1.0.3" } }, - "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==" - ], - - "hash.js": [ - "hash.js@1.1.7", - "", - { "dependencies": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" } }, - "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==" - ], - - "hasha": [ - "hasha@5.2.2", - "", - { "dependencies": { "is-stream": "^2.0.0", "type-fest": "^0.8.0" } }, - "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==" - ], - - "hasown": [ - "hasown@2.0.2", - "", - { "dependencies": { "function-bind": "^1.1.2" } }, - "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==" - ], - - "he": [ - "he@1.2.0", - "", - { "bin": { "he": "bin/he" } }, - "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" - ], - - "helmet": [ - "helmet@5.0.2", - "", - {}, - "sha512-QWlwUZZ8BtlvwYVTSDTBChGf8EOcQ2LkGMnQJxSzD1mUu8CCjXJZq/BXP8eWw4kikRnzlhtYo3lCk0ucmYA3Vg==" - ], - - "help-me": [ - "help-me@5.0.0", - "", - {}, - "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==" - ], - - "hermes-estree": [ - "hermes-estree@0.33.3", - "", - {}, - "sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg==" - ], - - "hermes-parser": [ - "hermes-parser@0.33.3", - "", - { "dependencies": { "hermes-estree": "0.33.3" } }, - "sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA==" - ], - - "history": [ - "history@4.10.1", - "", - { - "dependencies": { - "@babel/runtime": "^7.1.2", - "loose-envify": "^1.2.0", - "resolve-pathname": "^3.0.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0", - "value-equal": "^1.0.1" - } - }, - "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==" - ], - - "hoist-non-react-statics": [ - "hoist-non-react-statics@3.3.2", - "", - { "dependencies": { "react-is": "^16.7.0" } }, - "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==" - ], - - "html-entities": [ - "html-entities@2.6.0", - "", - {}, - "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==" - ], - - "html-escaper": [ - "html-escaper@2.0.2", - "", - {}, - "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" - ], - - "html-minifier-terser": [ - "html-minifier-terser@6.1.0", - "", - { - "dependencies": { - "camel-case": "^4.1.2", - "clean-css": "^5.2.2", - "commander": "^8.3.0", - "he": "^1.2.0", - "param-case": "^3.0.4", - "relateurl": "^0.2.7", - "terser": "^5.10.0" - }, - "bin": { "html-minifier-terser": "cli.js" } - }, - "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==" - ], - - "htmlparser2": [ - "htmlparser2@10.1.0", - "", - { - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.2.2", - "entities": "^7.0.1" - } - }, - "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==" - ], - - "http-errors": [ - "http-errors@2.0.0", - "", - { - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - } - }, - "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==" - ], - - "http-signature": [ - "http-signature@1.2.0", - "", - { "dependencies": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", "sshpk": "^1.7.0" } }, - "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==" - ], - - "https-proxy-agent": [ - "https-proxy-agent@7.0.6", - "", - { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, - "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==" - ], - - "humanize-duration": [ - "humanize-duration@3.33.2", - "", - {}, - "sha512-K7Ny/ULO1hDm2nnhvAY+SJV1skxFb61fd073SG1IWJl+D44ULrruCuTyjHKjBVVcSuTlnY99DKtgEG39CM5QOQ==" - ], - - "iconv-lite": [ - "iconv-lite@0.6.3", - "", - { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, - "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==" - ], - - "ieee754": [ - "ieee754@1.2.1", - "", - {}, - "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - ], - - "ignore": [ - "ignore@5.3.2", - "", - {}, - "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==" - ], - - "ignore-by-default": [ - "ignore-by-default@1.0.1", - "", - {}, - "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==" - ], - - "immutable": [ - "immutable@4.3.8", - "", - {}, - "sha512-d/Ld9aLbKpNwyl0KiM2CT1WYvkitQ1TSvmRtkcV8FKStiDoA7Slzgjmb/1G2yhKM1p0XeNOieaTbFZmU1d3Xuw==" - ], - - "import-fresh": [ - "import-fresh@3.3.1", - "", - { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, - "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==" - ], - - "import-jsx": [ - "import-jsx@4.0.1", - "", - { - "dependencies": { - "@babel/core": "^7.5.5", - "@babel/plugin-proposal-object-rest-spread": "^7.5.5", - "@babel/plugin-transform-destructuring": "^7.5.0", - "@babel/plugin-transform-react-jsx": "^7.3.0", - "caller-path": "^3.0.1", - "find-cache-dir": "^3.2.0", - "make-dir": "^3.0.2", - "resolve-from": "^3.0.0", - "rimraf": "^3.0.0" - } - }, - "sha512-2Cj4nWRuAmvokFRU6UNo3xgzXKh+4nq/LBtD6mTp3V9c9nYV7O+dRvPChPOM34Qcj1+Ijz3oK6HqkixG0GP9Rg==" - ], - - "imurmurhash": [ - "imurmurhash@0.1.4", - "", - {}, - "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" - ], - - "indent-string": [ - "indent-string@4.0.0", - "", - {}, - "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" - ], - - "inflight": [ - "inflight@1.0.6", - "", - { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, - "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==" - ], - - "inherits": [ - "inherits@2.0.4", - "", - {}, - "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - ], - - "ini": [ - "ini@1.3.8", - "", - {}, - "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - ], - - "ink": [ - "ink@2.7.1", - "", - { - "dependencies": { - "ansi-escapes": "^4.2.1", - "arrify": "^2.0.1", - "auto-bind": "^4.0.0", - "chalk": "^3.0.0", - "cli-cursor": "^3.1.0", - "cli-truncate": "^2.1.0", - "is-ci": "^2.0.0", - "lodash.throttle": "^4.1.1", - "log-update": "^3.0.0", - "prop-types": "^15.6.2", - "react-reconciler": "^0.24.0", - "scheduler": "^0.18.0", - "signal-exit": "^3.0.2", - "slice-ansi": "^3.0.0", - "string-length": "^3.1.0", - "widest-line": "^3.1.0", - "wrap-ansi": "^6.2.0", - "yoga-layout-prebuilt": "^1.9.3" - }, - "peerDependencies": { "@types/react": ">=16.8.0", "react": ">=16.8.0" }, - "optionalPeers": ["@types/react"] - }, - "sha512-s7lJuQDJEdjqtaIWhp3KYHl6WV3J04U9zoQ6wVc+Xoa06XM27SXUY57qC5DO46xkF0CfgXMKkKNcgvSu/SAEpA==" - ], - - "inline-style-parser": [ - "inline-style-parser@0.1.1", - "", - {}, - "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" - ], - - "internal-slot": [ - "internal-slot@1.1.0", - "", - { - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.2", - "side-channel": "^1.1.0" - } - }, - "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==" - ], - - "internmap": [ - "internmap@1.0.1", - "", - {}, - "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==" - ], - - "interpret": [ - "interpret@2.2.0", - "", - {}, - "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==" - ], - - "invariant": [ - "invariant@2.2.4", - "", - { "dependencies": { "loose-envify": "^1.0.0" } }, - "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==" - ], - - "ioredis": [ - "ioredis@4.31.0", - "", - { - "dependencies": { - "@ioredis/commands": "^1.0.2", - "cluster-key-slot": "^1.1.0", - "debug": "^4.3.1", - "denque": "^1.1.0", - "lodash.defaults": "^4.2.0", - "lodash.flatten": "^4.4.0", - "lodash.isarguments": "^3.1.0", - "p-map": "^2.1.0", - "redis-errors": "^1.2.0", - "redis-parser": "^3.0.0", - "standard-as-callback": "^2.1.0" - } - }, - "sha512-tVrCrc4LWJwX82GD79dZ0teZQGq+5KJEGpXJRgzHOrhHtLgF9ME6rTwDV5+HN5bjnvmtrnS8ioXhflY16sy2HQ==" - ], - - "ipaddr.js": [ - "ipaddr.js@1.9.1", - "", - {}, - "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" - ], - - "is-array-buffer": [ - "is-array-buffer@3.0.5", - "", - { - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - } - }, - "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==" - ], - - "is-arrayish": [ - "is-arrayish@0.2.1", - "", - {}, - "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" - ], - - "is-async-function": [ - "is-async-function@2.1.1", - "", - { - "dependencies": { - "async-function": "^1.0.0", - "call-bound": "^1.0.3", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - } - }, - "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==" - ], - - "is-bigint": [ - "is-bigint@1.1.0", - "", - { "dependencies": { "has-bigints": "^1.0.2" } }, - "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==" - ], - - "is-binary-path": [ - "is-binary-path@2.1.0", - "", - { "dependencies": { "binary-extensions": "^2.0.0" } }, - "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==" - ], - - "is-boolean-object": [ - "is-boolean-object@1.2.2", - "", - { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, - "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==" - ], - - "is-buffer": [ - "is-buffer@2.0.5", - "", - {}, - "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" - ], - - "is-bun-module": [ - "is-bun-module@2.0.0", - "", - { "dependencies": { "semver": "^7.7.1" } }, - "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==" - ], - - "is-callable": [ - "is-callable@1.2.7", - "", - {}, - "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" - ], - - "is-ci": [ - "is-ci@2.0.0", - "", - { "dependencies": { "ci-info": "^2.0.0" }, "bin": { "is-ci": "bin.js" } }, - "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==" - ], - - "is-core-module": [ - "is-core-module@2.16.1", - "", - { "dependencies": { "hasown": "^2.0.2" } }, - "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==" - ], - - "is-data-view": [ - "is-data-view@1.0.2", - "", - { - "dependencies": { - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "is-typed-array": "^1.1.13" - } - }, - "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==" - ], - - "is-date-object": [ - "is-date-object@1.1.0", - "", - { "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" } }, - "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==" - ], - - "is-extglob": [ - "is-extglob@2.1.1", - "", - {}, - "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" - ], - - "is-finalizationregistry": [ - "is-finalizationregistry@1.1.1", - "", - { "dependencies": { "call-bound": "^1.0.3" } }, - "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==" - ], - - "is-fullwidth-code-point": [ - "is-fullwidth-code-point@3.0.0", - "", - {}, - "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - ], - - "is-generator-function": [ - "is-generator-function@1.1.2", - "", - { - "dependencies": { - "call-bound": "^1.0.4", - "generator-function": "^2.0.0", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - } - }, - "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==" - ], - - "is-glob": [ - "is-glob@4.0.3", - "", - { "dependencies": { "is-extglob": "^2.1.1" } }, - "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==" - ], - - "is-map": [ - "is-map@2.0.3", - "", - {}, - "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==" - ], - - "is-nan": [ - "is-nan@1.3.2", - "", - { "dependencies": { "call-bind": "^1.0.0", "define-properties": "^1.1.3" } }, - "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==" - ], - - "is-negative-zero": [ - "is-negative-zero@2.0.3", - "", - {}, - "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==" - ], - - "is-number": [ - "is-number@7.0.0", - "", - {}, - "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" - ], - - "is-number-object": [ - "is-number-object@1.1.1", - "", - { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, - "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==" - ], - - "is-obj": [ - "is-obj@2.0.0", - "", - {}, - "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" - ], - - "is-plain-obj": [ - "is-plain-obj@4.1.0", - "", - {}, - "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==" - ], - - "is-regex": [ - "is-regex@1.2.1", - "", - { - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - } - }, - "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==" - ], - - "is-set": [ - "is-set@2.0.3", - "", - {}, - "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==" - ], - - "is-shared-array-buffer": [ - "is-shared-array-buffer@1.0.4", - "", - { "dependencies": { "call-bound": "^1.0.3" } }, - "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==" - ], - - "is-stream": [ - "is-stream@2.0.1", - "", - {}, - "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" - ], - - "is-string": [ - "is-string@1.1.1", - "", - { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, - "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==" - ], - - "is-symbol": [ - "is-symbol@1.1.1", - "", - { - "dependencies": { - "call-bound": "^1.0.2", - "has-symbols": "^1.1.0", - "safe-regex-test": "^1.1.0" - } - }, - "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==" - ], - - "is-typed-array": [ - "is-typed-array@1.1.15", - "", - { "dependencies": { "which-typed-array": "^1.1.16" } }, - "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==" - ], - - "is-typedarray": [ - "is-typedarray@1.0.0", - "", - {}, - "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" - ], - - "is-weakmap": [ - "is-weakmap@2.0.2", - "", - {}, - "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==" - ], - - "is-weakref": [ - "is-weakref@1.1.1", - "", - { "dependencies": { "call-bound": "^1.0.3" } }, - "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==" - ], - - "is-weakset": [ - "is-weakset@2.0.4", - "", - { "dependencies": { "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, - "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==" - ], - - "is-windows": [ - "is-windows@1.0.2", - "", - {}, - "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" - ], - - "isarray": [ - "isarray@1.0.0", - "", - {}, - "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - ], - - "isexe": [ - "isexe@2.0.0", - "", - {}, - "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - ], - - "isomorphic-fetch": [ - "isomorphic-fetch@2.2.1", - "", - { "dependencies": { "node-fetch": "^1.0.1", "whatwg-fetch": ">=0.10.0" } }, - "sha512-9c4TNAKYXM5PRyVcwUZrF3W09nQ+sO7+jydgs4ZGW9dhsLG2VOlISJABombdQqQRXCwuYG3sYV/puGf5rp0qmA==" - ], - - "isomorphic-ws": [ - "isomorphic-ws@4.0.1", - "", - { "peerDependencies": { "ws": "*" } }, - "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==" - ], - - "isstream": [ - "isstream@0.1.2", - "", - {}, - "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" - ], - - "istanbul-lib-coverage": [ - "istanbul-lib-coverage@3.2.2", - "", - {}, - "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==" - ], - - "istanbul-lib-hook": [ - "istanbul-lib-hook@3.0.0", - "", - { "dependencies": { "append-transform": "^2.0.0" } }, - "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==" - ], - - "istanbul-lib-instrument": [ - "istanbul-lib-instrument@4.0.3", - "", - { - "dependencies": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - } - }, - "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==" - ], - - "istanbul-lib-processinfo": [ - "istanbul-lib-processinfo@2.0.3", - "", - { - "dependencies": { - "archy": "^1.0.0", - "cross-spawn": "^7.0.3", - "istanbul-lib-coverage": "^3.2.0", - "p-map": "^3.0.0", - "rimraf": "^3.0.0", - "uuid": "^8.3.2" - } - }, - "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==" - ], - - "istanbul-lib-report": [ - "istanbul-lib-report@3.0.1", - "", - { - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - } - }, - "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==" - ], - - "istanbul-lib-source-maps": [ - "istanbul-lib-source-maps@5.0.6", - "", - { - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.23", - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0" - } - }, - "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==" - ], - - "istanbul-reports": [ - "istanbul-reports@3.2.0", - "", - { "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" } }, - "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==" - ], - - "iterator.prototype": [ - "iterator.prototype@1.1.5", - "", - { - "dependencies": { - "define-data-property": "^1.1.4", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.6", - "get-proto": "^1.0.0", - "has-symbols": "^1.1.0", - "set-function-name": "^2.0.2" - } - }, - "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==" - ], - - "jackspeak": [ - "jackspeak@1.4.2", - "", - { "dependencies": { "cliui": "^7.0.4" } }, - "sha512-GHeGTmnuaHnvS+ZctRB01bfxARuu9wW83ENbuiweu07SFcVlZrJpcshSre/keGT7YGBhLHg/+rXCNSrsEHKU4Q==" - ], - - "jake": [ - "jake@10.9.4", - "", - { - "dependencies": { "async": "^3.2.6", "filelist": "^1.0.4", "picocolors": "^1.1.1" }, - "bin": { "jake": "bin/cli.js" } - }, - "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==" - ], - - "joycon": [ - "joycon@3.1.1", - "", - {}, - "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==" - ], - - "js-sdsl": [ - "js-sdsl@4.3.0", - "", - {}, - "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==" - ], - - "js-sha3": [ - "js-sha3@0.8.0", - "", - {}, - "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" - ], - - "js-tokens": [ - "js-tokens@10.0.0", - "", - {}, - "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==" - ], - - "js-yaml": [ - "js-yaml@3.14.2", - "", - { - "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, - "bin": { "js-yaml": "bin/js-yaml.js" } - }, - "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==" - ], - - "jsbn": [ - "jsbn@0.1.1", - "", - {}, - "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" - ], - - "jsesc": [ - "jsesc@3.1.0", - "", - { "bin": { "jsesc": "bin/jsesc" } }, - "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==" - ], - - "json-2-csv": [ - "json-2-csv@3.14.4", - "", - { "dependencies": { "deeks": "2.5.1", "doc-path": "3.0.2" } }, - "sha512-6Dg4ZJb5g1Lu6gVM2jJGpu1WUo0/b3xS1b35+dXAWmYzlu2AqTXSFrUzA3l5/aYptjhoiGxCN7CZbxBwrUmhig==" - ], - - "json-buffer": [ - "json-buffer@3.0.1", - "", - {}, - "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" - ], - - "json-parse-even-better-errors": [ - "json-parse-even-better-errors@2.3.1", - "", - {}, - "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" - ], - - "json-schema": [ - "json-schema@0.4.0", - "", - {}, - "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" - ], - - "json-schema-traverse": [ - "json-schema-traverse@0.4.1", - "", - {}, - "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - ], - - "json-stable-stringify-without-jsonify": [ - "json-stable-stringify-without-jsonify@1.0.1", - "", - {}, - "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" - ], - - "json-stringify-safe": [ - "json-stringify-safe@5.0.1", - "", - {}, - "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" - ], - - "json5": [ - "json5@2.2.0", - "", - { "dependencies": { "minimist": "^1.2.5" }, "bin": { "json5": "lib/cli.js" } }, - "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==" - ], - - "jsonfile": [ - "jsonfile@4.0.0", - "", - { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, - "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==" - ], - - "jsprim": [ - "jsprim@1.4.2", - "", - { - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } - }, - "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==" - ], - - "jsx-ast-utils": [ - "jsx-ast-utils@3.3.5", - "", - { - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "object.assign": "^4.1.4", - "object.values": "^1.1.6" - } - }, - "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==" - ], - - "kanel": [ - "kanel@3.16.1", - "", - { - "dependencies": { - "@kristiandupont/recase": "^1.2.1", - "chalk": "4.1.2", - "cli-progress": "^3.11.2", - "extract-pg-schema": "^5.8.1", - "optionator": "^0.9.1", - "pg": "^8.10.0", - "ramda": "^0.32.0", - "rimraf": "^6.0.0", - "tagged-comment-parser": "^1.3.5" - }, - "bin": { "kanel": "bin/kanel" } - }, - "sha512-DDc0dTrsdBWpq15Q9dw8DB2pKYOHl23QDHI6vrB01v1Fy4TGv2LZoLUi4eE9iBarEWE3DAQ3GTWq5arsDG2nSQ==" - ], - - "kanel-kysely": [ - "kanel-kysely@0.8.0", - "", - { "dependencies": { "@kristiandupont/recase": "^1.2.1" } }, - "sha512-e5iv8pkkKPV+tktNuJvVb1/iqjyYtF1WUA15B9mehYO8ceKn0+d1KYnvcuKGPyjcUCHH0bTIs87DAO8lI9GX4Q==" - ], - - "keyv": [ - "keyv@4.5.4", - "", - { "dependencies": { "json-buffer": "3.0.1" } }, - "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==" - ], - - "kleur": [ - "kleur@4.1.5", - "", - {}, - "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==" - ], - - "knex": [ - "knex@3.1.0", - "", - { - "dependencies": { - "colorette": "2.0.19", - "commander": "^10.0.0", - "debug": "4.3.4", - "escalade": "^3.1.1", - "esm": "^3.2.25", - "get-package-type": "^0.1.0", - "getopts": "2.3.0", - "interpret": "^2.2.0", - "lodash": "^4.17.21", - "pg-connection-string": "2.6.2", - "rechoir": "^0.8.0", - "resolve-from": "^5.0.0", - "tarn": "^3.0.2", - "tildify": "2.0.0" - }, - "bin": { "knex": "bin/cli.js" } - }, - "sha512-GLoII6hR0c4ti243gMs5/1Rb3B+AjwMOfjYm97pu0FOQa7JH56hgBxYf5WK2525ceSbBY1cjeZ9yk99GPMB6Kw==" - ], - - "knex-pglite": [ - "knex-pglite@0.12.1", - "", - { "peerDependencies": { "@electric-sql/pglite": "0.x", "knex": "3.x" } }, - "sha512-7aMZfDVt2f6MQEdT1ASP/rS8T2bQCIieFGxMry9AO1zEHduI1fwqsOa0D63z3qFzHHLcEGNfSCqOfoUFbXoxtg==" - ], - - "kuler": [ - "kuler@2.0.0", - "", - {}, - "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" - ], - - "kysely": [ - "kysely@0.27.6", - "", - {}, - "sha512-FIyV/64EkKhJmjgC0g2hygpBv5RNWVPyNCqSAD7eTCv6eFWNIi4PN1UvdSJGicN/o35bnevgis4Y0UDC0qi8jQ==" - ], - - "language-subtag-registry": [ - "language-subtag-registry@0.3.23", - "", - {}, - "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==" - ], - - "language-tags": [ - "language-tags@1.0.9", - "", - { "dependencies": { "language-subtag-registry": "^0.3.20" } }, - "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==" - ], - - "lcov-parse": [ - "lcov-parse@1.0.0", - "", - { "bin": { "lcov-parse": "./bin/cli.js" } }, - "sha512-aprLII/vPzuQvYZnDRU78Fns9I2Ag3gi4Ipga/hxnVMCZC8DnR2nI7XBqrPoywGfxqIx/DgarGvDJZAD3YBTgQ==" - ], - - "leven": [ - "leven@2.1.0", - "", - {}, - "sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA==" - ], - - "levn": [ - "levn@0.4.1", - "", - { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, - "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==" - ], - - "libtap": [ - "libtap@1.4.1", - "", - { - "dependencies": { - "async-hook-domain": "^2.0.4", - "bind-obj-methods": "^3.0.0", - "diff": "^4.0.2", - "function-loop": "^2.0.1", - "minipass": "^3.1.5", - "own-or": "^1.0.0", - "own-or-env": "^1.0.2", - "signal-exit": "^3.0.4", - "stack-utils": "^2.0.4", - "tap-parser": "^11.0.0", - "tap-yaml": "^1.0.0", - "tcompare": "^5.0.6", - "trivial-deferred": "^1.0.1" - } - }, - "sha512-S9v19shLTigoMn3c02V7LZ4t09zxmVP3r3RbEAwuHFYeKgF+ESFJxoQ0PMFKW4XdgQhcjVBEwDoopG6WROq/gw==" - ], - - "lightningcss": [ - "lightningcss@1.32.0", - "", - { - "dependencies": { "detect-libc": "^2.0.3" }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.32.0", - "lightningcss-darwin-arm64": "1.32.0", - "lightningcss-darwin-x64": "1.32.0", - "lightningcss-freebsd-x64": "1.32.0", - "lightningcss-linux-arm-gnueabihf": "1.32.0", - "lightningcss-linux-arm64-gnu": "1.32.0", - "lightningcss-linux-arm64-musl": "1.32.0", - "lightningcss-linux-x64-gnu": "1.32.0", - "lightningcss-linux-x64-musl": "1.32.0", - "lightningcss-win32-arm64-msvc": "1.32.0", - "lightningcss-win32-x64-msvc": "1.32.0" - } - }, - "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==" - ], - - "lightningcss-android-arm64": [ - "lightningcss-android-arm64@1.32.0", - "", - { "os": "android", "cpu": "arm64" }, - "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==" - ], - - "lightningcss-darwin-arm64": [ - "lightningcss-darwin-arm64@1.32.0", - "", - { "os": "darwin", "cpu": "arm64" }, - "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==" - ], - - "lightningcss-darwin-x64": [ - "lightningcss-darwin-x64@1.32.0", - "", - { "os": "darwin", "cpu": "x64" }, - "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==" - ], - - "lightningcss-freebsd-x64": [ - "lightningcss-freebsd-x64@1.32.0", - "", - { "os": "freebsd", "cpu": "x64" }, - "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==" - ], - - "lightningcss-linux-arm-gnueabihf": [ - "lightningcss-linux-arm-gnueabihf@1.32.0", - "", - { "os": "linux", "cpu": "arm" }, - "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==" - ], - - "lightningcss-linux-arm64-gnu": [ - "lightningcss-linux-arm64-gnu@1.32.0", - "", - { "os": "linux", "cpu": "arm64" }, - "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==" - ], - - "lightningcss-linux-arm64-musl": [ - "lightningcss-linux-arm64-musl@1.32.0", - "", - { "os": "linux", "cpu": "arm64" }, - "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==" - ], - - "lightningcss-linux-x64-gnu": [ - "lightningcss-linux-x64-gnu@1.32.0", - "", - { "os": "linux", "cpu": "x64" }, - "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==" - ], - - "lightningcss-linux-x64-musl": [ - "lightningcss-linux-x64-musl@1.32.0", - "", - { "os": "linux", "cpu": "x64" }, - "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==" - ], - - "lightningcss-win32-arm64-msvc": [ - "lightningcss-win32-arm64-msvc@1.32.0", - "", - { "os": "win32", "cpu": "arm64" }, - "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==" - ], - - "lightningcss-win32-x64-msvc": [ - "lightningcss-win32-x64-msvc@1.32.0", - "", - { "os": "win32", "cpu": "x64" }, - "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==" - ], - - "lines-and-columns": [ - "lines-and-columns@1.2.4", - "", - {}, - "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" - ], - - "locate-path": [ - "locate-path@6.0.0", - "", - { "dependencies": { "p-locate": "^5.0.0" } }, - "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==" - ], - - "lodash": [ - "lodash@4.17.21", - "", - {}, - "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - ], - - "lodash-es": [ - "lodash-es@4.17.23", - "", - {}, - "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==" - ], - - "lodash.camelcase": [ - "lodash.camelcase@4.3.0", - "", - {}, - "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" - ], - - "lodash.defaults": [ - "lodash.defaults@4.2.0", - "", - {}, - "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" - ], - - "lodash.flatten": [ - "lodash.flatten@4.4.0", - "", - {}, - "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==" - ], - - "lodash.flattendeep": [ - "lodash.flattendeep@4.4.0", - "", - {}, - "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==" - ], - - "lodash.get": [ - "lodash.get@4.4.2", - "", - {}, - "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" - ], - - "lodash.isarguments": [ - "lodash.isarguments@3.1.0", - "", - {}, - "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" - ], - - "lodash.isequal": [ - "lodash.isequal@4.5.0", - "", - {}, - "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" - ], - - "lodash.merge": [ - "lodash.merge@4.6.2", - "", - {}, - "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" - ], - - "lodash.throttle": [ - "lodash.throttle@4.1.1", - "", - {}, - "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==" - ], - - "log-driver": [ - "log-driver@1.2.7", - "", - {}, - "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==" - ], - - "log-update": [ - "log-update@3.4.0", - "", - { - "dependencies": { - "ansi-escapes": "^3.2.0", - "cli-cursor": "^2.1.0", - "wrap-ansi": "^5.0.0" - } - }, - "sha512-ILKe88NeMt4gmDvk/eb615U/IVn7K9KWGkoYbdatQ69Z65nj1ZzjM6fHXfcs0Uge+e+EGnMW7DY4T9yko8vWFg==" - ], - - "logform": [ - "logform@2.7.0", - "", - { - "dependencies": { - "@colors/colors": "1.6.0", - "@types/triple-beam": "^1.3.2", - "fecha": "^4.2.0", - "ms": "^2.1.1", - "safe-stable-stringify": "^2.3.1", - "triple-beam": "^1.3.0" - } - }, - "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==" - ], - - "long": [ - "long@5.3.2", - "", - {}, - "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==" - ], - - "loose-envify": [ - "loose-envify@1.4.0", - "", - { - "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, - "bin": { "loose-envify": "cli.js" } - }, - "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==" - ], - - "loupe": [ - "loupe@3.2.1", - "", - {}, - "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==" - ], - - "lower-case": [ - "lower-case@2.0.2", - "", - { "dependencies": { "tslib": "^2.0.3" } }, - "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==" - ], - - "lru-cache": [ - "lru-cache@6.0.0", - "", - { "dependencies": { "yallist": "^4.0.0" } }, - "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==" - ], - - "luxon": [ - "luxon@2.5.2", - "", - {}, - "sha512-Yg7/RDp4nedqmLgyH0LwgGRvMEKVzKbUdkBYyCosbHgJ+kaOUx0qzSiSatVc3DFygnirTPYnMM2P5dg2uH1WvA==" - ], - - "magic-string": [ - "magic-string@0.30.21", - "", - { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==" - ], - - "magicast": [ - "magicast@0.3.5", - "", - { - "dependencies": { - "@babel/parser": "^7.25.4", - "@babel/types": "^7.25.4", - "source-map-js": "^1.2.0" - } - }, - "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==" - ], - - "make-dir": [ - "make-dir@3.1.0", - "", - { "dependencies": { "semver": "^6.0.0" } }, - "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==" - ], - - "make-error": [ - "make-error@1.3.6", - "", - {}, - "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" - ], - - "match-sorter": [ - "match-sorter@6.4.0", - "", - { "dependencies": { "@babel/runtime": "^7.23.8", "remove-accents": "0.5.0" } }, - "sha512-d4664ahzdL1QTTvmK1iI0JsrxWeJ6gn33qkYtnPg3mcn+naBLtXSgSPOe+X2vUgtgGwaAk3eiaj7gwKjjMAq+Q==" - ], - - "math-intrinsics": [ - "math-intrinsics@1.1.0", - "", - {}, - "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" - ], - - "mdast-util-definitions": [ - "mdast-util-definitions@5.1.2", - "", - { - "dependencies": { - "@types/mdast": "^3.0.0", - "@types/unist": "^2.0.0", - "unist-util-visit": "^4.0.0" - } - }, - "sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==" - ], - - "mdast-util-from-markdown": [ - "mdast-util-from-markdown@1.3.1", - "", - { - "dependencies": { - "@types/mdast": "^3.0.0", - "@types/unist": "^2.0.0", - "decode-named-character-reference": "^1.0.0", - "mdast-util-to-string": "^3.1.0", - "micromark": "^3.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-decode-string": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "unist-util-stringify-position": "^3.0.0", - "uvu": "^0.5.0" - } - }, - "sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==" - ], - - "mdast-util-to-hast": [ - "mdast-util-to-hast@11.3.0", - "", - { - "dependencies": { - "@types/hast": "^2.0.0", - "@types/mdast": "^3.0.0", - "@types/mdurl": "^1.0.0", - "mdast-util-definitions": "^5.0.0", - "mdurl": "^1.0.0", - "unist-builder": "^3.0.0", - "unist-util-generated": "^2.0.0", - "unist-util-position": "^4.0.0", - "unist-util-visit": "^4.0.0" - } - }, - "sha512-4o3Cli3hXPmm1LhB+6rqhfsIUBjnKFlIUZvudaermXB+4/KONdd/W4saWWkC+LBLbPMqhFSSTSRgafHsT5fVJw==" - ], - - "mdast-util-to-string": [ - "mdast-util-to-string@3.2.0", - "", - { "dependencies": { "@types/mdast": "^3.0.0" } }, - "sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==" - ], - - "mdurl": [ - "mdurl@1.0.1", - "", - {}, - "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==" - ], - - "media-typer": [ - "media-typer@0.3.0", - "", - {}, - "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" - ], - - "memoize-one": [ - "memoize-one@6.0.0", - "", - {}, - "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" - ], - - "memory-pager": [ - "memory-pager@1.5.0", - "", - {}, - "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" - ], - - "merge-descriptors": [ - "merge-descriptors@1.0.3", - "", - {}, - "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==" - ], - - "merge2": [ - "merge2@1.4.1", - "", - {}, - "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" - ], - - "methods": [ - "methods@1.1.2", - "", - {}, - "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" - ], - - "micromark": [ - "micromark@3.2.0", - "", - { - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "micromark-core-commonmark": "^1.0.1", - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-chunked": "^1.0.0", - "micromark-util-combine-extensions": "^1.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-encode": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-resolve-all": "^1.0.0", - "micromark-util-sanitize-uri": "^1.0.0", - "micromark-util-subtokenize": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.1", - "uvu": "^0.5.0" - } - }, - "sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==" - ], - - "micromark-core-commonmark": [ - "micromark-core-commonmark@1.1.0", - "", - { - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-factory-destination": "^1.0.0", - "micromark-factory-label": "^1.0.0", - "micromark-factory-space": "^1.0.0", - "micromark-factory-title": "^1.0.0", - "micromark-factory-whitespace": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-chunked": "^1.0.0", - "micromark-util-classify-character": "^1.0.0", - "micromark-util-html-tag-name": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-resolve-all": "^1.0.0", - "micromark-util-subtokenize": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.1", - "uvu": "^0.5.0" - } - }, - "sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==" - ], - - "micromark-factory-destination": [ - "micromark-factory-destination@1.1.0", - "", - { - "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==" - ], - - "micromark-factory-label": [ - "micromark-factory-label@1.1.0", - "", - { - "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==" - ], - - "micromark-factory-space": [ - "micromark-factory-space@1.1.0", - "", - { - "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==" - ], - - "micromark-factory-title": [ - "micromark-factory-title@1.1.0", - "", - { - "dependencies": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==" - ], - - "micromark-factory-whitespace": [ - "micromark-factory-whitespace@1.1.0", - "", - { - "dependencies": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==" - ], - - "micromark-util-character": [ - "micromark-util-character@1.2.0", - "", - { - "dependencies": { - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==" - ], - - "micromark-util-chunked": [ - "micromark-util-chunked@1.1.0", - "", - { "dependencies": { "micromark-util-symbol": "^1.0.0" } }, - "sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==" - ], - - "micromark-util-classify-character": [ - "micromark-util-classify-character@1.1.0", - "", - { - "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==" - ], - - "micromark-util-combine-extensions": [ - "micromark-util-combine-extensions@1.1.0", - "", - { - "dependencies": { - "micromark-util-chunked": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==" - ], - - "micromark-util-decode-numeric-character-reference": [ - "micromark-util-decode-numeric-character-reference@1.1.0", - "", - { "dependencies": { "micromark-util-symbol": "^1.0.0" } }, - "sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==" - ], - - "micromark-util-decode-string": [ - "micromark-util-decode-string@1.1.0", - "", - { - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-symbol": "^1.0.0" - } - }, - "sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==" - ], - - "micromark-util-encode": [ - "micromark-util-encode@1.1.0", - "", - {}, - "sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==" - ], - - "micromark-util-html-tag-name": [ - "micromark-util-html-tag-name@1.2.0", - "", - {}, - "sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==" - ], - - "micromark-util-normalize-identifier": [ - "micromark-util-normalize-identifier@1.1.0", - "", - { "dependencies": { "micromark-util-symbol": "^1.0.0" } }, - "sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==" - ], - - "micromark-util-resolve-all": [ - "micromark-util-resolve-all@1.1.0", - "", - { "dependencies": { "micromark-util-types": "^1.0.0" } }, - "sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==" - ], - - "micromark-util-sanitize-uri": [ - "micromark-util-sanitize-uri@1.2.0", - "", - { - "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-encode": "^1.0.0", - "micromark-util-symbol": "^1.0.0" - } - }, - "sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==" - ], - - "micromark-util-subtokenize": [ - "micromark-util-subtokenize@1.1.0", - "", - { - "dependencies": { - "micromark-util-chunked": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==" - ], - - "micromark-util-symbol": [ - "micromark-util-symbol@1.1.0", - "", - {}, - "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==" - ], - - "micromark-util-types": [ - "micromark-util-types@1.1.0", - "", - {}, - "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==" - ], - - "micromatch": [ - "micromatch@4.0.8", - "", - { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, - "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==" - ], - - "microseconds": [ - "microseconds@0.2.0", - "", - {}, - "sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==" - ], - - "mime": [ - "mime@1.6.0", - "", - { "bin": { "mime": "cli.js" } }, - "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - ], - - "mime-db": [ - "mime-db@1.52.0", - "", - {}, - "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - ], - - "mime-types": [ - "mime-types@2.1.35", - "", - { "dependencies": { "mime-db": "1.52.0" } }, - "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==" - ], - - "mimic-fn": [ - "mimic-fn@2.1.0", - "", - {}, - "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" - ], - - "mimic-response": [ - "mimic-response@3.1.0", - "", - {}, - "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" - ], - - "mini-create-react-context": [ - "mini-create-react-context@0.3.3", - "", - { - "dependencies": { "@babel/runtime": "^7.12.1", "tiny-warning": "^1.0.3" }, - "peerDependencies": { - "prop-types": "^15.0.0", - "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, - "sha512-TtF6hZE59SGmS4U8529qB+jJFeW6asTLDIpPgvPLSCsooAwJS7QprHIFTqv9/Qh3NdLwQxFYgiHX5lqb6jqzPA==" - ], - - "minimalistic-assert": [ - "minimalistic-assert@1.0.1", - "", - {}, - "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - ], - - "minimatch": [ - "minimatch@3.1.5", - "", - { "dependencies": { "brace-expansion": "^1.1.7" } }, - "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==" - ], - - "minimist": [ - "minimist@1.2.8", - "", - {}, - "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" - ], - - "minipass": [ - "minipass@3.3.6", - "", - { "dependencies": { "yallist": "^4.0.0" } }, - "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==" - ], - - "minizlib": [ - "minizlib@3.1.0", - "", - { "dependencies": { "minipass": "^7.1.2" } }, - "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==" - ], - - "mkdirp": [ - "mkdirp@1.0.4", - "", - { "bin": { "mkdirp": "bin/cmd.js" } }, - "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" - ], - - "mkdirp-classic": [ - "mkdirp-classic@0.5.3", - "", - {}, - "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" - ], - - "moment": [ - "moment@2.30.1", - "", - {}, - "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==" - ], - - "moment-timezone": [ - "moment-timezone@0.5.48", - "", - { "dependencies": { "moment": "^2.29.4" } }, - "sha512-f22b8LV1gbTO2ms2j2z13MuPogNoh5UzxL3nzNAYKGraILnbGc9NEE6dyiiiLv46DGRb8A4kg8UKWLjPthxBHw==" - ], - - "mongodb": [ - "mongodb@3.6.3", - "", - { - "dependencies": { - "bl": "^2.2.1", - "bson": "^1.1.4", - "denque": "^1.4.1", - "require_optional": "^1.0.1", - "safe-buffer": "^5.1.2" - }, - "optionalDependencies": { "saslprep": "^1.0.0" } - }, - "sha512-rOZuR0QkodZiM+UbQE5kDsJykBqWi0CL4Ec2i1nrGrUI3KO11r6Fbxskqmq3JK2NH7aW4dcccBuUujAP0ERl5w==" - ], - - "monk": [ - "monk@7.3.4", - "", - { - "dependencies": { - "@types/mongodb": "^3.5.25", - "debug": "*", - "mongodb": "^3.2.3", - "monk-middleware-cast-ids": "^0.2.1", - "monk-middleware-fields": "^0.2.0", - "monk-middleware-handle-callback": "^0.2.0", - "monk-middleware-options": "^0.2.1", - "monk-middleware-query": "^0.2.0", - "monk-middleware-wait-for-connection": "^0.2.0", - "object-assign": "^4.1.1" - } - }, - "sha512-PkPNiElwroVyKQj01usyziOvwiKYBUVSq7YU1FB4KFr0J3v0GeXW0TebYsLR4u33WB8JGqPiAcuzDspfdujqQg==" - ], - - "monk-middleware-cast-ids": [ - "monk-middleware-cast-ids@0.2.1", - "", - {}, - "sha512-Hp9gwjXo+inSPhXUlsV1u3DyZh2cXT3Osij/1gSNCJQCgacAF1lfmnTj6bKmlf1Et4dvLhwUL0PquxdZRIofkA==" - ], - - "monk-middleware-fields": [ - "monk-middleware-fields@0.2.0", - "", - {}, - "sha512-pp+k0JeBX+HkIKnCisrtsW/QM2WGkOVG1Bd1qKLSanuBCf1l5khpdHrEullfko0HO6tCjCJMp//MsR16gd5tAw==" - ], - - "monk-middleware-handle-callback": [ - "monk-middleware-handle-callback@0.2.2", - "", - {}, - "sha512-5hBynb7asZ2uw9XVze7C3XH0zXT51yFDvYydk/5HnWWzh2NLglDSiKDcX0yLKPHzFgiq+5Z4Laq5fFVnFsmm8w==" - ], - - "monk-middleware-options": [ - "monk-middleware-options@0.2.1", - "", - {}, - "sha512-ypE0wGC8n5ARvOq2tlERr1uyu1edckeDRkheQLaXPRm9LoW7kr9P7xMGEjW2vmBh7IxnkpONVc7555X8x+34hQ==" - ], - - "monk-middleware-query": [ - "monk-middleware-query@0.2.0", - "", - {}, - "sha512-BApd5HBiczJl1eVy65c9/NBVLtygBePFxuoHgar/LeMWCjWP9odSJk3vsnbxTnsOT1CMJ+hFysbaosLzDsxvtA==" - ], - - "monk-middleware-wait-for-connection": [ - "monk-middleware-wait-for-connection@0.2.0", - "", - {}, - "sha512-jSTz73B/+pGTTvhu5Ym8xsG6+QqaWab53UXnXdNNlTijTdLvcHABCLJXudQiJxob5N1Mzr5EOSx5ziwn2sihPQ==" - ], - - "mqtt": [ - "mqtt@4.3.8", - "", - { - "dependencies": { - "commist": "^1.0.0", - "concat-stream": "^2.0.0", - "debug": "^4.1.1", - "duplexify": "^4.1.1", - "help-me": "^3.0.0", - "inherits": "^2.0.3", - "lru-cache": "^6.0.0", - "minimist": "^1.2.5", - "mqtt-packet": "^6.8.0", - "number-allocator": "^1.0.9", - "pump": "^3.0.0", - "readable-stream": "^3.6.0", - "reinterval": "^1.1.0", - "rfdc": "^1.3.0", - "split2": "^3.1.0", - "ws": "^7.5.5", - "xtend": "^4.0.2" - }, - "bin": { "mqtt": "bin/mqtt.js", "mqtt_pub": "bin/pub.js", "mqtt_sub": "bin/sub.js" } - }, - "sha512-2xT75uYa0kiPEF/PE0VPdavmEkoBzMT/UL9moid0rAvlCtV48qBwxD62m7Ld/4j8tSkIO1E/iqRl/S72SEOhOw==" - ], - - "mqtt-packet": [ - "mqtt-packet@6.10.0", - "", - { - "dependencies": { - "bl": "^4.0.2", - "debug": "^4.1.1", - "process-nextick-args": "^2.0.1" - } - }, - "sha512-ja8+mFKIHdB1Tpl6vac+sktqy3gA8t9Mduom1BA75cI+R9AHnZOiaBQwpGiWnaVJLDGRdNhQmFaAqd7tkKSMGA==" - ], - - "mri": [ - "mri@1.2.0", - "", - {}, - "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==" - ], - - "ms": [ - "ms@2.1.3", - "", - {}, - "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - ], - - "msgpackr": [ - "msgpackr@1.11.8", - "", - { "optionalDependencies": { "msgpackr-extract": "^3.0.2" } }, - "sha512-bC4UGzHhVvgDNS7kn9tV8fAucIYUBuGojcaLiz7v+P63Lmtm0Xeji8B/8tYKddALXxJLpwIeBmUN3u64C4YkRA==" - ], - - "msgpackr-extract": [ - "msgpackr-extract@3.0.3", - "", - { - "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, - "optionalDependencies": { - "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", - "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", - "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", - "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", - "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", - "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" - }, - "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } - }, - "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==" - ], - - "multer": [ - "multer@2.0.1", - "", - { - "dependencies": { - "append-field": "^1.0.0", - "busboy": "^1.6.0", - "concat-stream": "^2.0.0", - "mkdirp": "^0.5.6", - "object-assign": "^4.1.1", - "type-is": "^1.6.18", - "xtend": "^4.0.2" - } - }, - "sha512-Ug8bXeTIUlxurg8xLTEskKShvcKDZALo1THEX5E41pYCD2sCVub5/kIRIGqWNoqV6szyLyQKV6mD4QUrWE5GCQ==" - ], - - "mv": [ - "mv@2.1.1", - "", - { "dependencies": { "mkdirp": "~0.5.1", "ncp": "~2.0.0", "rimraf": "~2.4.0" } }, - "sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg==" - ], - - "mylas": [ - "mylas@2.1.14", - "", - {}, - "sha512-BzQguy9W9NJgoVn2mRWzbFrFWWztGCcng2QI9+41frfk+Athwgx3qhqhvStz7ExeUUu7Kzw427sNzHpEZNINog==" - ], - - "nan": [ - "nan@2.25.0", - "", - {}, - "sha512-0M90Ag7Xn5KMLLZ7zliPWP3rT90P6PN+IzVFS0VqmnPktBk3700xUVv8Ikm9EUaUE5SDWdp/BIxdENzVznpm1g==" - ], - - "nano-time": [ - "nano-time@1.0.0", - "", - { "dependencies": { "big-integer": "^1.6.16" } }, - "sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA==" - ], - - "nanoid": [ - "nanoid@3.1.23", - "", - { "bin": { "nanoid": "bin/nanoid.cjs" } }, - "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==" - ], - - "napi-build-utils": [ - "napi-build-utils@2.0.0", - "", - {}, - "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==" - ], - - "napi-postinstall": [ - "napi-postinstall@0.3.4", - "", - { "bin": { "napi-postinstall": "lib/cli.js" } }, - "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==" - ], - - "natural-compare": [ - "natural-compare@1.4.0", - "", - {}, - "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" - ], - - "natural-compare-lite": [ - "natural-compare-lite@1.4.0", - "", - {}, - "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==" - ], - - "ncp": [ - "ncp@2.0.0", - "", - { "bin": { "ncp": "./bin/ncp" } }, - "sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==" - ], - - "negotiator": [ - "negotiator@0.6.3", - "", - {}, - "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" - ], - - "no-case": [ - "no-case@3.0.4", - "", - { "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" } }, - "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==" - ], - - "node-abi": [ - "node-abi@3.87.0", - "", - { "dependencies": { "semver": "^7.3.5" } }, - "sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ==" - ], - - "node-cache": [ - "node-cache@5.1.2", - "", - { "dependencies": { "clone": "2.x" } }, - "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==" - ], - - "node-exports-info": [ - "node-exports-info@1.6.0", - "", - { - "dependencies": { - "array.prototype.flatmap": "^1.3.3", - "es-errors": "^1.3.0", - "object.entries": "^1.1.9", - "semver": "^6.3.1" - } - }, - "sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==" - ], - - "node-fetch": [ - "node-fetch@2.6.7", - "", - { - "dependencies": { "whatwg-url": "^5.0.0" }, - "peerDependencies": { "encoding": "^0.1.0" }, - "optionalPeers": ["encoding"] - }, - "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==" - ], - - "node-gyp-build-optional-packages": [ - "node-gyp-build-optional-packages@5.2.2", - "", - { - "dependencies": { "detect-libc": "^2.0.1" }, - "bin": { - "node-gyp-build-optional-packages": "bin.js", - "node-gyp-build-optional-packages-optional": "optional.js", - "node-gyp-build-optional-packages-test": "build-test.js" - } - }, - "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==" - ], - - "node-html-parser": [ - "node-html-parser@5.4.2", - "", - { "dependencies": { "css-select": "^4.2.1", "he": "1.2.0" } }, - "sha512-RaBPP3+51hPne/OolXxcz89iYvQvKOydaqoePpOgXcrOKZhjVIzmpKZz+Hd/RBO2/zN2q6CNJhQzucVz+u3Jyw==" - ], - - "node-mocks-http": [ - "node-mocks-http@1.11.0", - "", - { - "dependencies": { - "accepts": "^1.3.7", - "content-disposition": "^0.5.3", - "depd": "^1.1.0", - "fresh": "^0.5.2", - "merge-descriptors": "^1.0.1", - "methods": "^1.1.2", - "mime": "^1.3.4", - "parseurl": "^1.3.3", - "range-parser": "^1.2.0", - "type-is": "^1.6.18" - } - }, - "sha512-jS/WzSOcKbOeGrcgKbenZeNhxUNnP36Yw11+hL4TTxQXErGfqYZ+MaYNNvhaTiGIJlzNSqgQkk9j8dSu1YWSuw==" - ], - - "node-modules-regexp": [ - "node-modules-regexp@1.0.0", - "", - {}, - "sha512-JMaRS9L4wSRIR+6PTVEikTrq/lMGEZR43a48ETeilY0Q0iMwVnccMFrUM1k+tNzmYuIU0Vh710bCUqHX+/+ctQ==" - ], - - "node-preload": [ - "node-preload@0.2.1", - "", - { "dependencies": { "process-on-spawn": "^1.0.0" } }, - "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==" - ], - - "node-releases": [ - "node-releases@2.0.36", - "", - {}, - "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==" - ], - - "nodemailer": [ - "nodemailer@7.0.11", - "", - {}, - "sha512-gnXhNRE0FNhD7wPSCGhdNh46Hs6nm+uTyg+Kq0cZukNQiYdnCsoQjodNP9BQVG9XrcK/v6/MgpAPBUFyzh9pvw==" - ], - - "nodemon": [ - "nodemon@2.0.22", - "", - { - "dependencies": { - "chokidar": "^3.5.2", - "debug": "^3.2.7", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.1.2", - "pstree.remy": "^1.1.8", - "semver": "^5.7.1", - "simple-update-notifier": "^1.0.7", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5" - }, - "bin": { "nodemon": "bin/nodemon.js" } - }, - "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==" - ], - - "nopt": [ - "nopt@8.1.0", - "", - { "dependencies": { "abbrev": "^3.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, - "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==" - ], - - "normalize-path": [ - "normalize-path@3.0.0", - "", - {}, - "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" - ], - - "nth-check": [ - "nth-check@2.1.1", - "", - { "dependencies": { "boolbase": "^1.0.0" } }, - "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==" - ], - - "number-allocator": [ - "number-allocator@1.0.14", - "", - { "dependencies": { "debug": "^4.3.1", "js-sdsl": "4.3.0" } }, - "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==" - ], - - "nyc": [ - "nyc@15.1.0", - "", - { - "dependencies": { - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "caching-transform": "^4.0.0", - "convert-source-map": "^1.7.0", - "decamelize": "^1.2.0", - "find-cache-dir": "^3.2.0", - "find-up": "^4.1.0", - "foreground-child": "^2.0.0", - "get-package-type": "^0.1.0", - "glob": "^7.1.6", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-hook": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "make-dir": "^3.0.0", - "node-preload": "^0.2.1", - "p-map": "^3.0.0", - "process-on-spawn": "^1.0.0", - "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "spawn-wrap": "^2.0.0", - "test-exclude": "^6.0.0", - "yargs": "^15.0.2" - }, - "bin": { "nyc": "bin/nyc.js" } - }, - "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==" - ], - - "oauth-sign": [ - "oauth-sign@0.9.0", - "", - {}, - "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" - ], - - "object-assign": [ - "object-assign@4.1.1", - "", - {}, - "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" - ], - - "object-inspect": [ - "object-inspect@1.13.4", - "", - {}, - "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==" - ], - - "object-keys": [ - "object-keys@1.1.1", - "", - {}, - "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - ], - - "object.assign": [ - "object.assign@4.1.7", - "", - { - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0", - "has-symbols": "^1.1.0", - "object-keys": "^1.1.1" - } - }, - "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==" - ], - - "object.entries": [ - "object.entries@1.1.9", - "", - { - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.1.1" - } - }, - "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==" - ], - - "object.fromentries": [ - "object.fromentries@2.0.8", - "", - { - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - } - }, - "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==" - ], - - "object.groupby": [ - "object.groupby@1.0.3", - "", - { - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2" - } - }, - "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==" - ], - - "object.values": [ - "object.values@1.2.1", - "", - { - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - } - }, - "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==" - ], - - "oblivious-set": [ - "oblivious-set@1.0.0", - "", - {}, - "sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==" - ], - - "on-exit-leak-free": [ - "on-exit-leak-free@2.1.2", - "", - {}, - "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==" - ], - - "on-finished": [ - "on-finished@2.4.1", - "", - { "dependencies": { "ee-first": "1.1.1" } }, - "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==" - ], - - "on-headers": [ - "on-headers@1.0.2", - "", - {}, - "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" - ], - - "once": [ - "once@1.4.0", - "", - { "dependencies": { "wrappy": "1" } }, - "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==" - ], - - "one-time": [ - "one-time@1.0.0", - "", - { "dependencies": { "fn.name": "1.x.x" } }, - "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==" - ], - - "onetime": [ - "onetime@5.1.2", - "", - { "dependencies": { "mimic-fn": "^2.1.0" } }, - "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==" - ], - - "opener": [ - "opener@1.5.2", - "", - { "bin": { "opener": "bin/opener-bin.js" } }, - "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==" - ], - - "optionator": [ - "optionator@0.9.4", - "", - { - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - } - }, - "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==" - ], - - "ow": [ - "ow@0.27.0", - "", - { - "dependencies": { - "@sindresorhus/is": "^4.0.1", - "callsites": "^3.1.0", - "dot-prop": "^6.0.1", - "lodash.isequal": "^4.5.0", - "type-fest": "^1.2.1", - "vali-date": "^1.0.0" - } - }, - "sha512-SGnrGUbhn4VaUGdU0EJLMwZWSupPmF46hnTRII7aCLCrqixTAC5eKo8kI4/XXf1eaaI8YEVT+3FeGNJI9himAQ==" - ], - - "own-keys": [ - "own-keys@1.0.1", - "", - { - "dependencies": { - "get-intrinsic": "^1.2.6", - "object-keys": "^1.1.1", - "safe-push-apply": "^1.0.0" - } - }, - "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==" - ], - - "own-or": [ - "own-or@1.0.0", - "", - {}, - "sha512-NfZr5+Tdf6MB8UI9GLvKRs4cXY8/yB0w3xtt84xFdWy8hkGjn+JFc60VhzS/hFRfbyxFcGYMTjnF4Me+RbbqrA==" - ], - - "own-or-env": [ - "own-or-env@1.0.2", - "", - { "dependencies": { "own-or": "^1.0.0" } }, - "sha512-NQ7v0fliWtK7Lkb+WdFqe6ky9XAzYmlkXthQrBbzlYbmFKoAYbDDcwmOm6q8kOuwSRXW8bdL5ORksploUJmWgw==" - ], - - "p-limit": [ - "p-limit@3.1.0", - "", - { "dependencies": { "yocto-queue": "^0.1.0" } }, - "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==" - ], - - "p-locate": [ - "p-locate@5.0.0", - "", - { "dependencies": { "p-limit": "^3.0.2" } }, - "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==" - ], - - "p-map": [ - "p-map@3.0.0", - "", - { "dependencies": { "aggregate-error": "^3.0.0" } }, - "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==" - ], - - "p-try": [ - "p-try@2.2.0", - "", - {}, - "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - ], - - "package-hash": [ - "package-hash@4.0.0", - "", - { - "dependencies": { - "graceful-fs": "^4.1.15", - "hasha": "^5.0.0", - "lodash.flattendeep": "^4.4.0", - "release-zalgo": "^1.0.0" - } - }, - "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==" - ], - - "package-json-from-dist": [ - "package-json-from-dist@1.0.1", - "", - {}, - "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==" - ], - - "param-case": [ - "param-case@3.0.4", - "", - { "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" } }, - "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==" - ], - - "parent-module": [ - "parent-module@1.0.1", - "", - { "dependencies": { "callsites": "^3.0.0" } }, - "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==" - ], - - "parse-json": [ - "parse-json@5.2.0", - "", - { - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==" - ], - - "parse5": [ - "parse5@7.3.0", - "", - { "dependencies": { "entities": "^6.0.0" } }, - "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==" - ], - - "parse5-htmlparser2-tree-adapter": [ - "parse5-htmlparser2-tree-adapter@7.1.0", - "", - { "dependencies": { "domhandler": "^5.0.3", "parse5": "^7.0.0" } }, - "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==" - ], - - "parse5-parser-stream": [ - "parse5-parser-stream@7.1.2", - "", - { "dependencies": { "parse5": "^7.0.0" } }, - "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==" - ], - - "parseurl": [ - "parseurl@1.3.3", - "", - {}, - "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - ], - - "pascal-case": [ - "pascal-case@3.1.2", - "", - { "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" } }, - "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==" - ], - - "path-exists": [ - "path-exists@4.0.0", - "", - {}, - "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" - ], - - "path-is-absolute": [ - "path-is-absolute@1.0.1", - "", - {}, - "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" - ], - - "path-key": [ - "path-key@3.1.1", - "", - {}, - "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" - ], - - "path-parse": [ - "path-parse@1.0.7", - "", - {}, - "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - ], - - "path-scurry": [ - "path-scurry@2.0.2", - "", - { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, - "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==" - ], - - "path-to-regexp": [ - "path-to-regexp@0.1.10", - "", - {}, - "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" - ], - - "path-type": [ - "path-type@4.0.0", - "", - {}, - "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" - ], - - "pathe": [ - "pathe@2.0.3", - "", - {}, - "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==" - ], - - "pathval": [ - "pathval@2.0.1", - "", - {}, - "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==" - ], - - "performance-now": [ - "performance-now@2.1.0", - "", - {}, - "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" - ], - - "pg": [ - "pg@8.20.0", - "", - { - "dependencies": { - "pg-connection-string": "^2.12.0", - "pg-pool": "^3.13.0", - "pg-protocol": "^1.13.0", - "pg-types": "2.2.0", - "pgpass": "1.0.5" - }, - "optionalDependencies": { "pg-cloudflare": "^1.3.0" }, - "peerDependencies": { "pg-native": ">=3.0.1" }, - "optionalPeers": ["pg-native"] - }, - "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==" - ], - - "pg-cloudflare": [ - "pg-cloudflare@1.3.0", - "", - {}, - "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==" - ], - - "pg-connection-string": [ - "pg-connection-string@2.12.0", - "", - {}, - "sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==" - ], - - "pg-int8": [ - "pg-int8@1.0.1", - "", - {}, - "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" - ], - - "pg-pool": [ - "pg-pool@3.13.0", - "", - { "peerDependencies": { "pg": ">=8.0" } }, - "sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==" - ], - - "pg-protocol": [ - "pg-protocol@1.13.0", - "", - {}, - "sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==" - ], - - "pg-query-emscripten": [ - "pg-query-emscripten@5.1.0", - "", - {}, - "sha512-H1ZWOzLRddmHuE4GZqFjjo55hA9zMiePz/WDDGANA/EnvILCJps9pcRucyGd+MFvapeYOy6TWSYz6DbtBOaxRQ==" - ], - - "pg-types": [ - "pg-types@2.2.0", - "", - { - "dependencies": { - "pg-int8": "1.0.1", - "postgres-array": "~2.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.4", - "postgres-interval": "^1.1.0" - } - }, - "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==" - ], - - "pgpass": [ - "pgpass@1.0.5", - "", - { "dependencies": { "split2": "^4.1.0" } }, - "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==" - ], - - "picocolors": [ - "picocolors@1.1.1", - "", - {}, - "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" - ], - - "picomatch": [ - "picomatch@4.0.3", - "", - {}, - "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==" - ], - - "pino": [ - "pino@10.3.1", - "", - { - "dependencies": { - "@pinojs/redact": "^0.4.0", - "atomic-sleep": "^1.0.0", - "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "^3.0.0", - "pino-std-serializers": "^7.0.0", - "process-warning": "^5.0.0", - "quick-format-unescaped": "^4.0.3", - "real-require": "^0.2.0", - "safe-stable-stringify": "^2.3.1", - "sonic-boom": "^4.0.1", - "thread-stream": "^4.0.0" - }, - "bin": { "pino": "bin.js" } - }, - "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==" - ], - - "pino-abstract-transport": [ - "pino-abstract-transport@3.0.0", - "", - { "dependencies": { "split2": "^4.0.0" } }, - "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==" - ], - - "pino-pretty": [ - "pino-pretty@13.1.3", - "", - { - "dependencies": { - "colorette": "^2.0.7", - "dateformat": "^4.6.3", - "fast-copy": "^4.0.0", - "fast-safe-stringify": "^2.1.1", - "help-me": "^5.0.0", - "joycon": "^3.1.1", - "minimist": "^1.2.6", - "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "^3.0.0", - "pump": "^3.0.0", - "secure-json-parse": "^4.0.0", - "sonic-boom": "^4.0.1", - "strip-json-comments": "^5.0.2" - }, - "bin": { "pino-pretty": "bin.js" } - }, - "sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg==" - ], - - "pino-std-serializers": [ - "pino-std-serializers@7.1.0", - "", - {}, - "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==" - ], - - "pirates": [ - "pirates@3.0.2", - "", - { "dependencies": { "node-modules-regexp": "^1.0.0" } }, - "sha512-c5CgUJq6H2k6MJz72Ak1F5sN9n9wlSlJyEnwvpm9/y3WB4E3pHBDT2c6PEiS1vyJvq2bUxUAIu0EGf8Cx4Ic7Q==" - ], - - "pkg-dir": [ - "pkg-dir@4.2.0", - "", - { "dependencies": { "find-up": "^4.0.0" } }, - "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==" - ], - - "plimit-lit": [ - "plimit-lit@1.6.1", - "", - { "dependencies": { "queue-lit": "^1.5.1" } }, - "sha512-B7+VDyb8Tl6oMJT9oSO2CW8XC/T4UcJGrwOVoNGwOQsQYhlpfajmrMj5xeejqaASq3V/EqThyOeATEOMuSEXiA==" - ], - - "possible-typed-array-names": [ - "possible-typed-array-names@1.1.0", - "", - {}, - "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==" - ], - - "postcss": [ - "postcss@8.5.8", - "", - { - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - } - }, - "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==" - ], - - "postgres-array": [ - "postgres-array@2.0.0", - "", - {}, - "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" - ], - - "postgres-bytea": [ - "postgres-bytea@1.0.1", - "", - {}, - "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==" - ], - - "postgres-date": [ - "postgres-date@1.0.7", - "", - {}, - "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" - ], - - "postgres-interval": [ - "postgres-interval@1.2.0", - "", - { "dependencies": { "xtend": "^4.0.0" } }, - "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==" - ], - - "preact": [ - "preact@10.12.1", - "", - {}, - "sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg==" - ], - - "prebuild-install": [ - "prebuild-install@7.1.3", - "", - { - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^2.0.0", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { "prebuild-install": "bin.js" } - }, - "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==" - ], - - "prelude-ls": [ - "prelude-ls@1.2.1", - "", - {}, - "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" - ], - - "prettier": [ - "prettier@3.2.5", - "", - { "bin": { "prettier": "bin/prettier.cjs" } }, - "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==" - ], - - "pretty-bytes": [ - "pretty-bytes@5.6.0", - "", - {}, - "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==" - ], - - "process": [ - "process@0.11.10", - "", - {}, - "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==" - ], - - "process-nextick-args": [ - "process-nextick-args@2.0.1", - "", - {}, - "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - ], - - "process-on-spawn": [ - "process-on-spawn@1.1.0", - "", - { "dependencies": { "fromentries": "^1.2.0" } }, - "sha512-JOnOPQ/8TZgjs1JIH/m9ni7FfimjNa/PRx7y/Wb5qdItsnhO0jE4AT7fC0HjC28DUQWDr50dwSYZLdRMlqDq3Q==" - ], - - "process-warning": [ - "process-warning@5.0.0", - "", - {}, - "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==" - ], - - "prom-client": [ - "prom-client@15.1.3", - "", - { "dependencies": { "@opentelemetry/api": "^1.4.0", "tdigest": "^0.1.1" } }, - "sha512-6ZiOBfCywsD4k1BN9IX0uZhF+tJkV8q8llP64G5Hajs4JOeVLPCwpPVcpXy3BwYiUGgyJzsJJQeOIv7+hDSq8g==" - ], - - "promise": [ - "promise@7.3.1", - "", - { "dependencies": { "asap": "~2.0.3" } }, - "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==" - ], - - "prop-types": [ - "prop-types@15.6.0", - "", - { - "dependencies": { - "fbjs": "^0.8.16", - "loose-envify": "^1.3.1", - "object-assign": "^4.1.1" - } - }, - "sha512-H16NHdiZ8szYSKNkCpmKmS8BCogxyABjJ1AqQknIY2iTpy1xC04egoBAzjKm+WU2pbuNxFonw921dnxR0QYAdw==" - ], - - "prop-types-extra": [ - "prop-types-extra@1.1.1", - "", - { - "dependencies": { "react-is": "^16.3.2", "warning": "^4.0.0" }, - "peerDependencies": { "react": ">=0.14.0" } - }, - "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==" - ], - - "property-information": [ - "property-information@6.5.0", - "", - {}, - "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==" - ], - - "protobufjs": [ - "protobufjs@7.5.4", - "", - { - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - } - }, - "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==" - ], - - "proxy-addr": [ - "proxy-addr@2.0.7", - "", - { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, - "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==" - ], - - "proxy-from-env": [ - "proxy-from-env@1.1.0", - "", - {}, - "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - ], - - "prudence": [ - "prudence@0.10.0", - "", - {}, - "sha512-QPyNYQR4tx+9xp+GuceW55MWeZIC/nNT3qWUmU8eij0FmO90x3L08oY9bJiIW1weB7mvH63JBra1cY+GH70YKw==" - ], - - "psl": [ - "psl@1.15.0", - "", - { "dependencies": { "punycode": "^2.3.1" } }, - "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==" - ], - - "pstree.remy": [ - "pstree.remy@1.1.8", - "", - {}, - "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" - ], - - "pump": [ - "pump@3.0.4", - "", - { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, - "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==" - ], - - "punycode": [ - "punycode@2.3.1", - "", - {}, - "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==" - ], - - "qs": [ - "qs@6.11.0", - "", - { "dependencies": { "side-channel": "^1.0.4" } }, - "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==" - ], - - "queue-lit": [ - "queue-lit@1.5.2", - "", - {}, - "sha512-tLc36IOPeMAubu8BkW8YDBV+WyIgKlYU7zUNs0J5Vk9skSZ4JfGlPOqplP0aHdfv7HL0B2Pg6nwiq60Qc6M2Hw==" - ], - - "queue-microtask": [ - "queue-microtask@1.2.3", - "", - {}, - "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" - ], - - "quick-format-unescaped": [ - "quick-format-unescaped@4.0.4", - "", - {}, - "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==" - ], - - "ramda": [ - "ramda@0.32.0", - "", - {}, - "sha512-GQWAHhxhxWBWA8oIBr1XahFVjQ9Fic6MK9ikijfd4TZHfE2+urfk+irVlR5VOn48uwMgM+loRRBJd6Yjsbc0zQ==" - ], - - "random-bytes": [ - "random-bytes@1.0.0", - "", - {}, - "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==" - ], - - "range-parser": [ - "range-parser@1.2.1", - "", - {}, - "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - ], - - "rate-limit-redis": [ - "rate-limit-redis@2.1.0", - "", - { "dependencies": { "defaults": "^1.0.3", "redis": "^3.0.2" } }, - "sha512-6SAsTCzY0v6UCIKLOLLYqR2XzFmgdtF7jWXlSPq2FrNIZk8tZ7xwBvyGW7GFMCe5I4S9lYNdrSJ9E84rz3/CpA==" - ], - - "raw-body": [ - "raw-body@2.5.2", - "", - { - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==" - ], - - "rc": [ - "rc@1.2.8", - "", - { - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { "rc": "./cli.js" } - }, - "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==" - ], - - "react": [ - "react@17.0.2", - "", - { "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" } }, - "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==" - ], - - "react-async": [ - "react-async@10.0.1", - "", - { "peerDependencies": { "react": ">=16.3.1" } }, - "sha512-ORUz5ca0B57QgBIzEZM5SuhJ6xFjkvEEs0gylLNlWf06vuVcLZsjIw3wx58jJkZG38p+0nUAxRgFW2b7mnVZzA==" - ], - - "react-async-script": [ - "react-async-script@1.2.0", - "", - { - "dependencies": { "hoist-non-react-statics": "^3.3.0", "prop-types": "^15.5.0" }, - "peerDependencies": { "react": ">=16.4.1" } - }, - "sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q==" - ], - - "react-bootstrap": [ - "react-bootstrap@2.9.0-beta.0", - "", - { - "dependencies": { - "@babel/runtime": "^7.22.5", - "@restart/hooks": "^0.4.9", - "@restart/ui": "^1.6.6", - "@types/react-transition-group": "^4.4.6", - "classnames": "^2.3.2", - "dom-helpers": "^5.2.1", - "invariant": "^2.2.4", - "prop-types": "^15.8.1", - "prop-types-extra": "^1.1.0", - "react-transition-group": "^4.4.5", - "uncontrollable": "^7.2.1", - "warning": "^4.0.3" - }, - "peerDependencies": { - "@types/react": ">=16.14.8", - "react": ">=16.14.0", - "react-dom": ">=16.14.0" - }, - "optionalPeers": ["@types/react"] - }, - "sha512-atmQhuRce7g/G+eclJn1eMZ1wbG6j8yYWrtr+Hlv/fVX0bw3QOUs62Q1G3qSqbkaZ4E625w/56GFR0rXf36Fog==" - ], - - "react-dom": [ - "react-dom@17.0.2", - "", - { - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" - }, - "peerDependencies": { "react": "17.0.2" } - }, - "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==" - ], - - "react-fast-compare": [ - "react-fast-compare@2.0.4", - "", - {}, - "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==" - ], - - "react-google-recaptcha": [ - "react-google-recaptcha@2.1.0", - "", - { - "dependencies": { "prop-types": "^15.5.0", "react-async-script": "^1.1.1" }, - "peerDependencies": { "react": ">=16.4.1" } - }, - "sha512-K9jr7e0CWFigi8KxC3WPvNqZZ47df2RrMAta6KmRoE4RUi7Ys6NmNjytpXpg4HI/svmQJLKR+PncEPaNJ98DqQ==" - ], - - "react-hot-toast": [ - "react-hot-toast@2.0.0", - "", - { - "dependencies": { "goober": "^2.0.35" }, - "peerDependencies": { "react": ">=16", "react-dom": ">=16" } - }, - "sha512-J0J2rcSvKetlziVquwESgk85pV9JB0Dz3RJIZcAEv7CWU2y2z8BQqxmZHZUxjPKIBGPqXAocZch4Kj4oUdX4+w==" - ], - - "react-is": [ - "react-is@17.0.2", - "", - {}, - "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" - ], - - "react-lifecycles-compat": [ - "react-lifecycles-compat@3.0.4", - "", - {}, - "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" - ], - - "react-markdown": [ - "react-markdown@7.0.1", - "", - { - "dependencies": { - "@types/hast": "^2.0.0", - "@types/unist": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "prop-types": "^15.0.0", - "property-information": "^6.0.0", - "react-is": "^17.0.0", - "remark-parse": "^10.0.0", - "remark-rehype": "^9.0.0", - "space-separated-tokens": "^2.0.0", - "style-to-object": "^0.3.0", - "unified": "^10.0.0", - "unist-util-visit": "^4.0.0", - "vfile": "^5.0.0" - }, - "peerDependencies": { "@types/react": ">=16", "react": ">=16" } - }, - "sha512-pthNPaoiwg0q7hukoE04F2ENwSzijIlWHJ4UMs/96LUe/G/P3FnbP4qHzx3FoNqae+2SqDG8vzniTLnJDeWneg==" - ], - - "react-query": [ - "react-query@3.18.1", - "", - { - "dependencies": { - "@babel/runtime": "^7.5.5", - "broadcast-channel": "^3.4.1", - "match-sorter": "^6.0.2" - }, - "peerDependencies": { "react": "^16.8.0 || ^17.0.0" } - }, - "sha512-17lv3pQxU9n+cB5acUv0/cxNTjo9q8G+RsedC6Ax4V9D8xEM7Q5xf9xAbCPdEhDrrnzPjTls9fQEABKRSi7OJA==" - ], - - "react-reconciler": [ - "react-reconciler@0.24.0", - "", - { - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.18.0" - }, - "peerDependencies": { "react": "^16.0.0" } - }, - "sha512-gAGnwWkf+NOTig9oOowqid9O0HjTDC+XVGBCAmJYYJ2A2cN/O4gDdIuuUQjv8A4v6GDwVfJkagpBBLW5OW9HSw==" - ], - - "react-router": [ - "react-router@5.1.2", - "", - { - "dependencies": { - "@babel/runtime": "^7.1.2", - "history": "^4.9.0", - "hoist-non-react-statics": "^3.1.0", - "loose-envify": "^1.3.1", - "mini-create-react-context": "^0.3.0", - "path-to-regexp": "^1.7.0", - "prop-types": "^15.6.2", - "react-is": "^16.6.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" - }, - "peerDependencies": { "react": ">=15" } - }, - "sha512-yjEuMFy1ONK246B+rsa0cUam5OeAQ8pyclRDgpxuSCrAlJ1qN9uZ5IgyKC7gQg0w8OM50NXHEegPh/ks9YuR2A==" - ], - - "react-router-bootstrap": [ - "react-router-bootstrap@0.25.0", - "", - { - "dependencies": { "prop-types": "^15.5.10" }, - "peerDependencies": { "react": ">=0.14.0", "react-router-dom": ">=4.0.0" } - }, - "sha512-/22eqxjn6Zv5fvY2rZHn57SKmjmJfK7xzJ6/G1OgxAjLtKVfWgV5sn41W2yiqzbtV5eE4/i4LeDLBGYTqx7jbA==" - ], - - "react-router-dom": [ - "react-router-dom@5.1.2", - "", - { - "dependencies": { - "@babel/runtime": "^7.1.2", - "history": "^4.9.0", - "loose-envify": "^1.3.1", - "prop-types": "^15.6.2", - "react-router": "5.1.2", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" - }, - "peerDependencies": { "react": ">=15" } - }, - "sha512-7BPHAaIwWpZS074UKaw1FjVdZBSVWEk8IuDXdB+OkLb8vd/WRQIpA4ag9WQk61aEfQs47wHyjWUoUGGZxpQXew==" - ], - - "react-select": [ - "react-select@5.10.2", - "", - { - "dependencies": { - "@babel/runtime": "^7.12.0", - "@emotion/cache": "^11.4.0", - "@emotion/react": "^11.8.1", - "@floating-ui/dom": "^1.0.1", - "@types/react-transition-group": "^4.4.0", - "memoize-one": "^6.0.0", - "prop-types": "^15.6.0", - "react-transition-group": "^4.3.0", - "use-isomorphic-layout-effect": "^1.2.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "sha512-Z33nHdEFWq9tfnfVXaiM12rbJmk+QjFEztWLtmXqQhz6Al4UZZ9xc0wiatmGtUOCCnHN0WizL3tCMYRENX4rVQ==" - ], - - "react-transition-group": [ - "react-transition-group@4.4.5", - "", - { - "dependencies": { - "@babel/runtime": "^7.5.5", - "dom-helpers": "^5.0.1", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2" - }, - "peerDependencies": { "react": ">=16.6.0", "react-dom": ">=16.6.0" } - }, - "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==" - ], - - "readable-stream": [ - "readable-stream@3.6.2", - "", - { - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==" - ], - - "readdirp": [ - "readdirp@3.6.0", - "", - { "dependencies": { "picomatch": "^2.2.1" } }, - "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==" - ], - - "real-require": [ - "real-require@0.2.0", - "", - {}, - "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==" - ], - - "rechoir": [ - "rechoir@0.8.0", - "", - { "dependencies": { "resolve": "^1.20.0" } }, - "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==" - ], - - "redeyed": [ - "redeyed@2.1.1", - "", - { "dependencies": { "esprima": "~4.0.0" } }, - "sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==" - ], - - "redis": [ - "redis@3.1.2", - "", - { - "dependencies": { - "denque": "^1.5.0", - "redis-commands": "^1.7.0", - "redis-errors": "^1.2.0", - "redis-parser": "^3.0.0" - } - }, - "sha512-grn5KoZLr/qrRQVwoSkmzdbw6pwF+/rwODtrOr6vuBRiR/f3rjSTGupbF90Zpqm2oenix8Do6RV7pYEkGwlKkw==" - ], - - "redis-commands": [ - "redis-commands@1.7.0", - "", - {}, - "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ==" - ], - - "redis-errors": [ - "redis-errors@1.2.0", - "", - {}, - "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==" - ], - - "redis-parser": [ - "redis-parser@3.0.0", - "", - { "dependencies": { "redis-errors": "^1.0.0" } }, - "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==" - ], - - "reflect.getprototypeof": [ - "reflect.getprototypeof@1.0.10", - "", - { - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.1", - "which-builtin-type": "^1.2.1" - } - }, - "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==" - ], - - "regexp.prototype.flags": [ - "regexp.prototype.flags@1.5.4", - "", - { - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "set-function-name": "^2.0.2" - } - }, - "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==" - ], - - "regexpp": [ - "regexpp@3.2.0", - "", - {}, - "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==" - ], - - "reinterval": [ - "reinterval@1.1.0", - "", - {}, - "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ==" - ], - - "relateurl": [ - "relateurl@0.2.7", - "", - {}, - "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==" - ], - - "release-zalgo": [ - "release-zalgo@1.0.0", - "", - { "dependencies": { "es6-error": "^4.0.1" } }, - "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==" - ], - - "remark-parse": [ - "remark-parse@10.0.2", - "", - { - "dependencies": { - "@types/mdast": "^3.0.0", - "mdast-util-from-markdown": "^1.0.0", - "unified": "^10.0.0" - } - }, - "sha512-3ydxgHa/ZQzG8LvC7jTXccARYDcRld3VfcgIIFs7bI6vbRSxJJmzgLEIIoYKyrfhaY+ujuWaf/PJiMZXoiCXgw==" - ], - - "remark-rehype": [ - "remark-rehype@9.1.0", - "", - { - "dependencies": { - "@types/hast": "^2.0.0", - "@types/mdast": "^3.0.0", - "mdast-util-to-hast": "^11.0.0", - "unified": "^10.0.0" - } - }, - "sha512-oLa6YmgAYg19zb0ZrBACh40hpBLteYROaPLhBXzLgjqyHQrN+gVP9N/FJvfzuNNuzCutktkroXEZBrxAxKhh7Q==" - ], - - "remove-accents": [ - "remove-accents@0.5.0", - "", - {}, - "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==" - ], - - "request": [ - "request@2.88.2", - "", - { - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - } - }, - "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==" - ], - - "require-directory": [ - "require-directory@2.1.1", - "", - {}, - "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" - ], - - "require-main-filename": [ - "require-main-filename@2.0.0", - "", - {}, - "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" - ], - - "require_optional": [ - "require_optional@1.0.1", - "", - { "dependencies": { "resolve-from": "^2.0.0", "semver": "^5.1.0" } }, - "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==" - ], - - "resolve": [ - "resolve@2.0.0-next.6", - "", - { - "dependencies": { - "es-errors": "^1.3.0", - "is-core-module": "^2.16.1", - "node-exports-info": "^1.6.0", - "object-keys": "^1.1.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { "resolve": "bin/resolve" } - }, - "sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==" - ], - - "resolve-from": [ - "resolve-from@3.0.0", - "", - {}, - "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==" - ], - - "resolve-pathname": [ - "resolve-pathname@3.0.0", - "", - {}, - "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" - ], - - "resolve-pkg-maps": [ - "resolve-pkg-maps@1.0.0", - "", - {}, - "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==" - ], - - "restore-cursor": [ - "restore-cursor@3.1.0", - "", - { "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, - "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==" - ], - - "reusify": [ - "reusify@1.1.0", - "", - {}, - "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==" - ], - - "rfdc": [ - "rfdc@1.4.1", - "", - {}, - "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==" - ], - - "rg-stats": [ - "rg-stats@1.2.1", - "", - {}, - "sha512-mpZaD0jxf4xdWS6ddYnfnKG7Ov0okB0OiLEgxCrX4NiHH3TCFTjsCOocFBxprtP/5qiGH7x+daGGjg2L6iK+PQ==" - ], - - "rimraf": [ - "rimraf@3.0.2", - "", - { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, - "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==" - ], - - "rolldown": [ - "rolldown@1.0.0-rc.9", - "", - { - "dependencies": { - "@oxc-project/types": "=0.115.0", - "@rolldown/pluginutils": "1.0.0-rc.9" - }, - "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.9", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.9", - "@rolldown/binding-darwin-x64": "1.0.0-rc.9", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.9", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.9", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.9", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.9", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.9", - "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.9", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.9", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.9", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.9", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.9", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.9", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.9" - }, - "bin": { "rolldown": "bin/cli.mjs" } - }, - "sha512-9EbgWge7ZH+yqb4d2EnELAntgPTWbfL8ajiTW+SyhJEC4qhBbkCKbqFV4Ge4zmu5ziQuVbWxb/XwLZ+RIO7E8Q==" - ], - - "rollup": [ - "rollup@4.59.0", - "", - { - "dependencies": { "@types/estree": "1.0.8" }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.59.0", - "@rollup/rollup-android-arm64": "4.59.0", - "@rollup/rollup-darwin-arm64": "4.59.0", - "@rollup/rollup-darwin-x64": "4.59.0", - "@rollup/rollup-freebsd-arm64": "4.59.0", - "@rollup/rollup-freebsd-x64": "4.59.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", - "@rollup/rollup-linux-arm-musleabihf": "4.59.0", - "@rollup/rollup-linux-arm64-gnu": "4.59.0", - "@rollup/rollup-linux-arm64-musl": "4.59.0", - "@rollup/rollup-linux-loong64-gnu": "4.59.0", - "@rollup/rollup-linux-loong64-musl": "4.59.0", - "@rollup/rollup-linux-ppc64-gnu": "4.59.0", - "@rollup/rollup-linux-ppc64-musl": "4.59.0", - "@rollup/rollup-linux-riscv64-gnu": "4.59.0", - "@rollup/rollup-linux-riscv64-musl": "4.59.0", - "@rollup/rollup-linux-s390x-gnu": "4.59.0", - "@rollup/rollup-linux-x64-gnu": "4.59.0", - "@rollup/rollup-linux-x64-musl": "4.59.0", - "@rollup/rollup-openbsd-x64": "4.59.0", - "@rollup/rollup-openharmony-arm64": "4.59.0", - "@rollup/rollup-win32-arm64-msvc": "4.59.0", - "@rollup/rollup-win32-ia32-msvc": "4.59.0", - "@rollup/rollup-win32-x64-gnu": "4.59.0", - "@rollup/rollup-win32-x64-msvc": "4.59.0", - "fsevents": "~2.3.2" - }, - "bin": { "rollup": "dist/bin/rollup" } - }, - "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==" - ], - - "run-parallel": [ - "run-parallel@1.2.0", - "", - { "dependencies": { "queue-microtask": "^1.2.2" } }, - "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==" - ], - - "sade": [ - "sade@1.8.1", - "", - { "dependencies": { "mri": "^1.1.0" } }, - "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==" - ], - - "safe-array-concat": [ - "safe-array-concat@1.1.3", - "", - { - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "has-symbols": "^1.1.0", - "isarray": "^2.0.5" - } - }, - "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==" - ], - - "safe-buffer": [ - "safe-buffer@5.2.1", - "", - {}, - "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - ], - - "safe-json-stringify": [ - "safe-json-stringify@1.2.0", - "", - {}, - "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==" - ], - - "safe-push-apply": [ - "safe-push-apply@1.0.0", - "", - { "dependencies": { "es-errors": "^1.3.0", "isarray": "^2.0.5" } }, - "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==" - ], - - "safe-regex-test": [ - "safe-regex-test@1.1.0", - "", - { - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" - } - }, - "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==" - ], - - "safe-stable-stringify": [ - "safe-stable-stringify@2.5.0", - "", - {}, - "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==" - ], - - "safer-buffer": [ - "safer-buffer@2.1.2", - "", - {}, - "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - ], - - "saslprep": [ - "saslprep@1.0.3", - "", - { "dependencies": { "sparse-bitfield": "^3.0.3" } }, - "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==" - ], - - "sass": [ - "sass@1.64.1", - "", - { - "dependencies": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { "sass": "sass.js" } - }, - "sha512-16rRACSOFEE8VN7SCgBu1MpYCyN7urj9At898tyzdXFhC+a+yOX5dXwAR7L8/IdPJ1NB8OYoXmD55DM30B2kEQ==" - ], - - "scheduler": [ - "scheduler@0.20.2", - "", - { "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" } }, - "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==" - ], - - "secure-json-parse": [ - "secure-json-parse@4.1.0", - "", - {}, - "sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==" - ], - - "semver": [ - "semver@7.7.4", - "", - { "bin": { "semver": "bin/semver.js" } }, - "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==" - ], - - "send": [ - "send@0.19.0", - "", - { - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - } - }, - "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==" - ], - - "seq-logging": [ - "seq-logging@1.1.1", - "", - {}, - "sha512-9miWILWu22dKNCkZi2UePAnZeQEzaYsQRKbAi5eSBUbuOyyeYPyYO1bEvIvZAZRjltEwY1S0yz94hc0/f+niDg==" - ], - - "serve-static": [ - "serve-static@1.16.0", - "", - { - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - } - }, - "sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==" - ], - - "set-blocking": [ - "set-blocking@2.0.0", - "", - {}, - "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" - ], - - "set-function-length": [ - "set-function-length@1.2.2", - "", - { - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - } - }, - "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==" - ], - - "set-function-name": [ - "set-function-name@2.0.2", - "", - { - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - } - }, - "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==" - ], - - "set-proto": [ - "set-proto@1.0.0", - "", - { - "dependencies": { - "dunder-proto": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0" - } - }, - "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==" - ], - - "setimmediate": [ - "setimmediate@1.0.5", - "", - {}, - "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" - ], - - "setprototypeof": [ - "setprototypeof@1.2.0", - "", - {}, - "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - ], - - "shebang-command": [ - "shebang-command@2.0.0", - "", - { "dependencies": { "shebang-regex": "^3.0.0" } }, - "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==" - ], - - "shebang-regex": [ - "shebang-regex@3.0.0", - "", - {}, - "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" - ], - - "side-channel": [ - "side-channel@1.1.0", - "", - { - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - } - }, - "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==" - ], - - "side-channel-list": [ - "side-channel-list@1.0.0", - "", - { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, - "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==" - ], - - "side-channel-map": [ - "side-channel-map@1.0.1", - "", - { - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - } - }, - "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==" - ], - - "side-channel-weakmap": [ - "side-channel-weakmap@1.0.2", - "", - { - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - } - }, - "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==" - ], - - "siginfo": [ - "siginfo@2.0.0", - "", - {}, - "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==" - ], - - "signal-exit": [ - "signal-exit@3.0.7", - "", - {}, - "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - ], - - "simple-concat": [ - "simple-concat@1.0.1", - "", - {}, - "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" - ], - - "simple-get": [ - "simple-get@4.0.1", - "", - { - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==" - ], - - "simple-update-notifier": [ - "simple-update-notifier@1.1.0", - "", - { "dependencies": { "semver": "~7.0.0" } }, - "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==" - ], - - "slash": [ - "slash@3.0.0", - "", - {}, - "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" - ], - - "slice-ansi": [ - "slice-ansi@3.0.0", - "", - { - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - } - }, - "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==" - ], - - "snappy": [ - "snappy@7.3.3", - "", - { - "optionalDependencies": { - "@napi-rs/snappy-android-arm-eabi": "7.3.3", - "@napi-rs/snappy-android-arm64": "7.3.3", - "@napi-rs/snappy-darwin-arm64": "7.3.3", - "@napi-rs/snappy-darwin-x64": "7.3.3", - "@napi-rs/snappy-freebsd-x64": "7.3.3", - "@napi-rs/snappy-linux-arm-gnueabihf": "7.3.3", - "@napi-rs/snappy-linux-arm64-gnu": "7.3.3", - "@napi-rs/snappy-linux-arm64-musl": "7.3.3", - "@napi-rs/snappy-linux-ppc64-gnu": "7.3.3", - "@napi-rs/snappy-linux-riscv64-gnu": "7.3.3", - "@napi-rs/snappy-linux-s390x-gnu": "7.3.3", - "@napi-rs/snappy-linux-x64-gnu": "7.3.3", - "@napi-rs/snappy-linux-x64-musl": "7.3.3", - "@napi-rs/snappy-openharmony-arm64": "7.3.3", - "@napi-rs/snappy-wasm32-wasi": "7.3.3", - "@napi-rs/snappy-win32-arm64-msvc": "7.3.3", - "@napi-rs/snappy-win32-ia32-msvc": "7.3.3", - "@napi-rs/snappy-win32-x64-msvc": "7.3.3" - } - }, - "sha512-UDJVCunvgblRpfTOjo/uT7pQzfrTsSICJ4yVS4aq7SsGBaUSpJwaVP15nF//jqinSLpN7boe/BqbUmtWMTQ5MQ==" - ], - - "sonic-boom": [ - "sonic-boom@4.2.1", - "", - { "dependencies": { "atomic-sleep": "^1.0.0" } }, - "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==" - ], - - "source-map": [ - "source-map@0.6.1", - "", - {}, - "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - ], - - "source-map-js": [ - "source-map-js@1.2.1", - "", - {}, - "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==" - ], - - "source-map-support": [ - "source-map-support@0.5.21", - "", - { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, - "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==" - ], - - "space-separated-tokens": [ - "space-separated-tokens@2.0.2", - "", - {}, - "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==" - ], - - "sparse-bitfield": [ - "sparse-bitfield@3.0.3", - "", - { "dependencies": { "memory-pager": "^1.0.2" } }, - "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==" - ], - - "spawn-wrap": [ - "spawn-wrap@2.0.0", - "", - { - "dependencies": { - "foreground-child": "^2.0.0", - "is-windows": "^1.0.2", - "make-dir": "^3.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "which": "^2.0.1" - } - }, - "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==" - ], - - "split2": [ - "split2@4.2.0", - "", - {}, - "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==" - ], - - "sprintf-js": [ - "sprintf-js@1.0.3", - "", - {}, - "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" - ], - - "sshpk": [ - "sshpk@1.18.0", - "", - { - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - } - }, - "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==" - ], - - "stable-hash": [ - "stable-hash@0.0.5", - "", - {}, - "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==" - ], - - "stack-trace": [ - "stack-trace@0.0.10", - "", - {}, - "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==" - ], - - "stack-utils": [ - "stack-utils@2.0.6", - "", - { "dependencies": { "escape-string-regexp": "^2.0.0" } }, - "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==" - ], - - "stackback": [ - "stackback@0.0.2", - "", - {}, - "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==" - ], - - "standard-as-callback": [ - "standard-as-callback@2.1.0", - "", - {}, - "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" - ], - - "statuses": [ - "statuses@2.0.1", - "", - {}, - "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" - ], - - "std-env": [ - "std-env@3.10.0", - "", - {}, - "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==" - ], - - "stop-iteration-iterator": [ - "stop-iteration-iterator@1.1.0", - "", - { "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" } }, - "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==" - ], - - "stream-shift": [ - "stream-shift@1.0.3", - "", - {}, - "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==" - ], - - "streamsearch": [ - "streamsearch@1.1.0", - "", - {}, - "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" - ], - - "string-length": [ - "string-length@3.1.0", - "", - { "dependencies": { "astral-regex": "^1.0.0", "strip-ansi": "^5.2.0" } }, - "sha512-Ttp5YvkGm5v9Ijagtaz1BnN+k9ObpvS0eIBblPMp2YWL8FBmi9qblQ9fexc2k/CXFgrTIteU3jAw3payCnwSTA==" - ], - - "string-width": [ - "string-width@4.2.3", - "", - { - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==" - ], - - "string-width-cjs": [ - "string-width@4.2.3", - "", - { - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==" - ], - - "string.prototype.includes": [ - "string.prototype.includes@2.0.1", - "", - { - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3" - } - }, - "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==" - ], - - "string.prototype.matchall": [ - "string.prototype.matchall@4.0.12", - "", - { - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.6", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.6", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "internal-slot": "^1.1.0", - "regexp.prototype.flags": "^1.5.3", - "set-function-name": "^2.0.2", - "side-channel": "^1.1.0" - } - }, - "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==" - ], - - "string.prototype.repeat": [ - "string.prototype.repeat@1.0.0", - "", - { "dependencies": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" } }, - "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==" - ], - - "string.prototype.trim": [ - "string.prototype.trim@1.2.10", - "", - { - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-data-property": "^1.1.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-object-atoms": "^1.0.0", - "has-property-descriptors": "^1.0.2" - } - }, - "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==" - ], - - "string.prototype.trimend": [ - "string.prototype.trimend@1.0.9", - "", - { - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - } - }, - "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==" - ], - - "string.prototype.trimstart": [ - "string.prototype.trimstart@1.0.8", - "", - { - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - } - }, - "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==" - ], - - "string_decoder": [ - "string_decoder@1.3.0", - "", - { "dependencies": { "safe-buffer": "~5.2.0" } }, - "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==" - ], - - "strip-ansi": [ - "strip-ansi@5.2.0", - "", - { "dependencies": { "ansi-regex": "^4.1.0" } }, - "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==" - ], - - "strip-ansi-cjs": [ - "strip-ansi@6.0.1", - "", - { "dependencies": { "ansi-regex": "^5.0.1" } }, - "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==" - ], - - "strip-bom": [ - "strip-bom@3.0.0", - "", - {}, - "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==" - ], - - "strip-json-comments": [ - "strip-json-comments@5.0.3", - "", - {}, - "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==" - ], - - "strip-literal": [ - "strip-literal@3.1.0", - "", - { "dependencies": { "js-tokens": "^9.0.1" } }, - "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==" - ], - - "strnum": [ - "strnum@1.1.2", - "", - {}, - "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==" - ], - - "style-to-object": [ - "style-to-object@0.3.0", - "", - { "dependencies": { "inline-style-parser": "0.1.1" } }, - "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==" - ], - - "stylis": [ - "stylis@4.2.0", - "", - {}, - "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" - ], - - "superagent": [ - "superagent@7.1.6", - "", - { - "dependencies": { - "component-emitter": "^1.3.0", - "cookiejar": "^2.1.3", - "debug": "^4.3.4", - "fast-safe-stringify": "^2.1.1", - "form-data": "^4.0.0", - "formidable": "^2.0.1", - "methods": "^1.1.2", - "mime": "2.6.0", - "qs": "^6.10.3", - "readable-stream": "^3.6.0", - "semver": "^7.3.7" - } - }, - "sha512-gZkVCQR1gy/oUXr+kxJMLDjla434KmSOKbx5iGD30Ql+AkJQ/YlPKECJy2nhqOsHLjGHzoDTXNSjhnvWhzKk7g==" - ], - - "supertest": [ - "supertest@6.2.2", - "", - { "dependencies": { "methods": "^1.1.2", "superagent": "^7.1.0" } }, - "sha512-wCw9WhAtKJsBvh07RaS+/By91NNE0Wh0DN19/hWPlBOU8tAfOtbZoVSV4xXeoKoxgPx0rx2y+y+8660XtE7jzg==" - ], - - "supports-color": [ - "supports-color@7.2.0", - "", - { "dependencies": { "has-flag": "^4.0.0" } }, - "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==" - ], - - "supports-preserve-symlinks-flag": [ - "supports-preserve-symlinks-flag@1.0.0", - "", - {}, - "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" - ], - - "sync-fetch": [ - "sync-fetch@0.3.1", - "", - { "dependencies": { "buffer": "^5.7.0", "node-fetch": "^2.6.1" } }, - "sha512-xj5qiCDap/03kpci5a+qc5wSJjc8ZSixgG2EUmH1B8Ea2sfWclQA7eH40hiHPCtkCn6MCk4Wb+dqcXdCy2PP3g==" - ], - - "tachi-autogen-docs": ["tachi-autogen-docs@workspace:typescript/docs-autogen-scripts"], - - "tachi-bot": ["tachi-bot@workspace:typescript/bot"], - - "tachi-client": ["tachi-client@workspace:typescript/client"], - - "tachi-common": ["tachi-common@workspace:typescript/common"], - - "tachi-db": ["tachi-db@workspace:typescript/db"], - - "tachi-db-migration-engine": [ - "tachi-db-migration-engine@workspace:typescript/db-migration-engine" - ], - - "tachi-db-migration-engine-cli": [ - "tachi-db-migration-engine-cli@workspace:typescript/db-cli" - ], - - "tachi-github-bot": ["tachi-github-bot@workspace:typescript/github-bot"], - - "tachi-seeds-scripts": ["tachi-seeds-scripts@workspace:typescript/seeds-scripts"], - - "tachi-server": ["tachi-server@workspace:typescript/server"], - - "tachi-sieglinde": ["tachi-sieglinde@workspace:typescript/sieglinde"], - - "tagged-comment-parser": [ - "tagged-comment-parser@1.3.8", - "", - {}, - "sha512-HYkOQ/8ha113ln/Vp48wiDTPtbB59AWOdU44AXjhLyJLJjWWfn2kjnXUcyWLQepwbixA/mEeo1iW2Z9OwaBClQ==" - ], - - "tap": ["tap@workspace:typescript-vendor/tap"], - - "tap-mocha-reporter": [ - "tap-mocha-reporter@5.0.4", - "", - { - "dependencies": { - "color-support": "^1.1.0", - "debug": "^4.1.1", - "diff": "^4.0.1", - "escape-string-regexp": "^2.0.0", - "glob": "^7.0.5", - "tap-parser": "^11.0.0", - "tap-yaml": "^1.0.0", - "unicode-length": "^2.0.2" - }, - "bin": { "tap-mocha-reporter": "index.js" } - }, - "sha512-J+YMO8B7lq1O6Zxd/jeuG27vJ+Y4tLiRMKPSb7KR6FVh86k3Rq1TwYc2GKPyIjCbzzdMdReh3Vfz9L5cg1Z2Bw==" - ], - - "tap-parser": [ - "tap-parser@10.1.0", - "", - { - "dependencies": { - "events-to-array": "^1.0.1", - "minipass": "^3.0.0", - "tap-yaml": "^1.0.0" - }, - "bin": { "tap-parser": "bin/cmd.js" } - }, - "sha512-FujQeciDaOiOvaIVGS1Rpb0v4R6XkOjvWCWowlz5oKuhPkEJ8U6pxgqt38xuzYhPt8dWEnfHn2jqpZdJEkW7pA==" - ], - - "tap-yaml": [ - "tap-yaml@1.0.2", - "", - { "dependencies": { "yaml": "^1.10.2" } }, - "sha512-GegASpuqBnRNdT1U+yuUPZ8rEU64pL35WPBpCISWwff4dErS2/438barz7WFJl4Nzh3Y05tfPidZnH+GaV1wMg==" - ], - - "tar": [ - "tar@7.5.10", - "", - { - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.1.0", - "yallist": "^5.0.0" - } - }, - "sha512-8mOPs1//5q/rlkNSPcCegA6hiHJYDmSLEI8aMH/CdSQJNWztHC9WHNam5zdQlfpTwB9Xp7IBEsHfV5LKMJGVAw==" - ], - - "tar-fs": [ - "tar-fs@2.1.4", - "", - { - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==" - ], - - "tar-stream": [ - "tar-stream@2.2.0", - "", - { - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - } - }, - "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==" - ], - - "tarn": [ - "tarn@3.0.2", - "", - {}, - "sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==" - ], - - "tcompare": [ - "tcompare@5.0.7", - "", - { "dependencies": { "diff": "^4.0.2" } }, - "sha512-d9iddt6YYGgyxJw5bjsN7UJUO1kGOtjSlNy/4PoGYAjQS5pAT/hzIoLf1bZCw+uUxRmZJh7Yy1aA7xKVRT9B4w==" - ], - - "tdigest": [ - "tdigest@0.1.2", - "", - { "dependencies": { "bintrees": "1.0.2" } }, - "sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==" - ], - - "terser": [ - "terser@5.46.0", - "", - { - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.15.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { "terser": "bin/terser" } - }, - "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==" - ], - - "test-exclude": [ - "test-exclude@7.0.2", - "", - { - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^10.4.1", - "minimatch": "^10.2.2" - } - }, - "sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw==" - ], - - "text-hex": [ - "text-hex@1.0.0", - "", - {}, - "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" - ], - - "thread-stream": [ - "thread-stream@4.0.0", - "", - { "dependencies": { "real-require": "^0.2.0" } }, - "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==" - ], - - "tildify": [ - "tildify@2.0.0", - "", - {}, - "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==" - ], - - "tiny-invariant": [ - "tiny-invariant@1.3.3", - "", - {}, - "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==" - ], - - "tiny-warning": [ - "tiny-warning@1.0.3", - "", - {}, - "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" - ], - - "tinybench": [ - "tinybench@2.9.0", - "", - {}, - "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==" - ], - - "tinyexec": [ - "tinyexec@0.3.2", - "", - {}, - "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==" - ], - - "tinyglobby": [ - "tinyglobby@0.2.15", - "", - { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, - "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==" - ], - - "tinypool": [ - "tinypool@1.1.1", - "", - {}, - "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==" - ], - - "tinyrainbow": [ - "tinyrainbow@2.0.0", - "", - {}, - "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==" - ], - - "tinyspy": [ - "tinyspy@4.0.4", - "", - {}, - "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==" - ], - - "to-regex-range": [ - "to-regex-range@5.0.1", - "", - { "dependencies": { "is-number": "^7.0.0" } }, - "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==" - ], - - "toad-cache": [ - "toad-cache@3.7.0", - "", - {}, - "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==" - ], - - "toidentifier": [ - "toidentifier@1.0.1", - "", - {}, - "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" - ], - - "touch": [ - "touch@3.1.1", - "", - { "bin": { "nodetouch": "bin/nodetouch.js" } }, - "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==" - ], - - "tough-cookie": [ - "tough-cookie@2.5.0", - "", - { "dependencies": { "psl": "^1.1.28", "punycode": "^2.1.1" } }, - "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==" - ], - - "tr46": [ - "tr46@0.0.3", - "", - {}, - "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - ], - - "treport": [ - "treport@2.0.2", - "", - { - "dependencies": { - "cardinal": "^2.1.1", - "chalk": "^3.0.0", - "import-jsx": "^4.0.0", - "ink": "^2.6.0", - "ms": "^2.1.2", - "string-length": "^3.1.0", - "tap-parser": "^10.0.1", - "unicode-length": "^2.0.2" - }, - "peerDependencies": { "react": "^16.8.6" } - }, - "sha512-AnHKgHMy3II7Arfvf1tSHAwv9rzcvgbWrOixFJgdExVKd0mMsOp9wD2LGP9RbXy9j8AZoerBVu3OR2Uz9MpUJw==" - ], - - "triple-beam": [ - "triple-beam@1.4.1", - "", - {}, - "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==" - ], - - "trivial-deferred": [ - "trivial-deferred@1.1.2", - "", - {}, - "sha512-vDPiDBC3hyP6O4JrJYMImW3nl3c03Tsj9fEXc7Qc/XKa1O7gf5ZtFfIR/E0dun9SnDHdwjna1Z2rSzYgqpxh/g==" - ], - - "trough": [ - "trough@2.2.0", - "", - {}, - "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==" - ], - - "ts-api-utils": [ - "ts-api-utils@2.4.0", - "", - { "peerDependencies": { "typescript": ">=4.8.4" } }, - "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==" - ], - - "ts-mixer": [ - "ts-mixer@6.0.4", - "", - {}, - "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==" - ], - - "ts-node": [ - "ts-node@10.9.1", - "", - { - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "optionalPeers": ["@swc/core", "@swc/wasm"], - "bin": { - "ts-node": "dist/bin.js", - "ts-script": "dist/bin-script-deprecated.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js" - } - }, - "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==" - ], - - "ts-protoc-gen": [ - "ts-protoc-gen@0.15.0", - "", - { - "dependencies": { "google-protobuf": "^3.15.5" }, - "bin": { "protoc-gen-ts": "bin/protoc-gen-ts" } - }, - "sha512-TycnzEyrdVDlATJ3bWFTtra3SCiEP0W0vySXReAuEygXCUr1j2uaVyL0DhzjwuUdQoW5oXPwk6oZWeA0955V+g==" - ], - - "tsc-alias": [ - "tsc-alias@1.7.1", - "", - { - "dependencies": { - "chokidar": "^3.5.3", - "commander": "^9.0.0", - "globby": "^11.0.4", - "mylas": "^2.1.9", - "normalize-path": "^3.0.0", - "plimit-lit": "^1.2.6" - }, - "bin": { "tsc-alias": "dist/bin/index.js" } - }, - "sha512-P4+0i+OB0hX17Ca+U6EJ4WZZ+OSupqW32VJ34N7g7+Ch+bwSx1AqYOvDdIVYEKymBh3dfG0t1qxbxPlBbtB1lQ==" - ], - - "tsconfig-paths": [ - "tsconfig-paths@3.12.0", - "", - { - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.0", - "strip-bom": "^3.0.0" - } - }, - "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==" - ], - - "tslib": [ - "tslib@2.8.1", - "", - {}, - "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" - ], - - "tsutils": [ - "tsutils@3.21.0", - "", - { - "dependencies": { "tslib": "^1.8.1" }, - "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" - } - }, - "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==" - ], - - "tunnel-agent": [ - "tunnel-agent@0.6.0", - "", - { "dependencies": { "safe-buffer": "^5.0.1" } }, - "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==" - ], - - "tweetnacl": [ - "tweetnacl@0.14.5", - "", - {}, - "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" - ], - - "type-check": [ - "type-check@0.4.0", - "", - { "dependencies": { "prelude-ls": "^1.2.1" } }, - "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==" - ], - - "type-fest": [ - "type-fest@1.4.0", - "", - {}, - "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==" - ], - - "type-is": [ - "type-is@1.6.18", - "", - { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, - "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==" - ], - - "typed-array-buffer": [ - "typed-array-buffer@1.0.3", - "", - { - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" - } - }, - "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==" - ], - - "typed-array-byte-length": [ - "typed-array-byte-length@1.0.3", - "", - { - "dependencies": { - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.14" - } - }, - "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==" - ], - - "typed-array-byte-offset": [ - "typed-array-byte-offset@1.0.4", - "", - { - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.15", - "reflect.getprototypeof": "^1.0.9" - } - }, - "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==" - ], - - "typed-array-length": [ - "typed-array-length@1.0.7", - "", - { - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0", - "reflect.getprototypeof": "^1.0.6" - } - }, - "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==" - ], - - "typedarray": [ - "typedarray@0.0.6", - "", - {}, - "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" - ], - - "typedarray-to-buffer": [ - "typedarray-to-buffer@3.1.5", - "", - { "dependencies": { "is-typedarray": "^1.0.0" } }, - "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==" - ], - - "typescript": [ - "typescript@5.9.3", - "", - { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, - "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==" - ], - - "typescript-eslint": [ - "typescript-eslint@8.56.1", - "", - { - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.56.1", - "@typescript-eslint/parser": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1", - "@typescript-eslint/utils": "8.56.1" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==" - ], - - "ua-parser-js": [ - "ua-parser-js@0.7.41", - "", - { "bin": { "ua-parser-js": "script/cli.js" } }, - "sha512-O3oYyCMPYgNNHuO7Jjk3uacJWZF8loBgwrfd/5LE/HyZ3lUIOdniQ7DNXJcIgZbwioZxk0fLfI4EVnetdiX5jg==" - ], - - "uid-safe": [ - "uid-safe@2.1.5", - "", - { "dependencies": { "random-bytes": "~1.0.0" } }, - "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==" - ], - - "unbox-primitive": [ - "unbox-primitive@1.1.0", - "", - { - "dependencies": { - "call-bound": "^1.0.3", - "has-bigints": "^1.0.2", - "has-symbols": "^1.1.0", - "which-boxed-primitive": "^1.1.1" - } - }, - "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==" - ], - - "uncontrollable": [ - "uncontrollable@7.2.1", - "", - { - "dependencies": { - "@babel/runtime": "^7.6.3", - "@types/react": ">=16.9.11", - "invariant": "^2.2.4", - "react-lifecycles-compat": "^3.0.4" - }, - "peerDependencies": { "react": ">=15.0.0" } - }, - "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==" - ], - - "undefsafe": [ - "undefsafe@2.0.5", - "", - {}, - "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" - ], - - "undici": [ - "undici@7.22.0", - "", - {}, - "sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==" - ], - - "undici-types": [ - "undici-types@6.21.0", - "", - {}, - "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" - ], - - "unicode-length": [ - "unicode-length@2.1.0", - "", - { "dependencies": { "punycode": "^2.0.0" } }, - "sha512-4bV582zTV9Q02RXBxSUMiuN/KHo5w4aTojuKTNT96DIKps/SIawFp7cS5Mu25VuY1AioGXrmYyzKZUzh8OqoUw==" - ], - - "unified": [ - "unified@10.1.2", - "", - { - "dependencies": { - "@types/unist": "^2.0.0", - "bail": "^2.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^5.0.0" - } - }, - "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==" - ], - - "unist-builder": [ - "unist-builder@3.0.1", - "", - { "dependencies": { "@types/unist": "^2.0.0" } }, - "sha512-gnpOw7DIpCA0vpr6NqdPvTWnlPTApCTRzr+38E6hCWx3rz/cjo83SsKIlS1Z+L5ttScQ2AwutNnb8+tAvpb6qQ==" - ], - - "unist-util-generated": [ - "unist-util-generated@2.0.1", - "", - {}, - "sha512-qF72kLmPxAw0oN2fwpWIqbXAVyEqUzDHMsbtPvOudIlUzXYFIeQIuxXQCRCFh22B7cixvU0MG7m3MW8FTq/S+A==" - ], - - "unist-util-is": [ - "unist-util-is@5.2.1", - "", - { "dependencies": { "@types/unist": "^2.0.0" } }, - "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==" - ], - - "unist-util-position": [ - "unist-util-position@4.0.4", - "", - { "dependencies": { "@types/unist": "^2.0.0" } }, - "sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg==" - ], - - "unist-util-stringify-position": [ - "unist-util-stringify-position@3.0.3", - "", - { "dependencies": { "@types/unist": "^2.0.0" } }, - "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==" - ], - - "unist-util-visit": [ - "unist-util-visit@4.1.2", - "", - { - "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0", - "unist-util-visit-parents": "^5.1.1" - } - }, - "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==" - ], - - "unist-util-visit-parents": [ - "unist-util-visit-parents@5.1.3", - "", - { "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0" } }, - "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==" - ], - - "universal-github-app-jwt": [ - "universal-github-app-jwt@2.2.2", - "", - {}, - "sha512-dcmbeSrOdTnsjGjUfAlqNDJrhxXizjAz94ija9Qw8YkZ1uu0d+GoZzyH+Jb9tIIqvGsadUfwg+22k5aDqqwzbw==" - ], - - "universal-user-agent": [ - "universal-user-agent@7.0.3", - "", - {}, - "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==" - ], - - "universalify": [ - "universalify@0.1.2", - "", - {}, - "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" - ], - - "unload": [ - "unload@2.2.0", - "", - { "dependencies": { "@babel/runtime": "^7.6.2", "detect-node": "^2.0.4" } }, - "sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==" - ], - - "unpipe": [ - "unpipe@1.0.0", - "", - {}, - "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" - ], - - "unrs-resolver": [ - "unrs-resolver@1.11.1", - "", - { - "dependencies": { "napi-postinstall": "^0.3.0" }, - "optionalDependencies": { - "@unrs/resolver-binding-android-arm-eabi": "1.11.1", - "@unrs/resolver-binding-android-arm64": "1.11.1", - "@unrs/resolver-binding-darwin-arm64": "1.11.1", - "@unrs/resolver-binding-darwin-x64": "1.11.1", - "@unrs/resolver-binding-freebsd-x64": "1.11.1", - "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", - "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", - "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", - "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", - "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", - "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-x64-musl": "1.11.1", - "@unrs/resolver-binding-wasm32-wasi": "1.11.1", - "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", - "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", - "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" - } - }, - "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==" - ], - - "update-browserslist-db": [ - "update-browserslist-db@1.2.3", - "", - { - "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, - "peerDependencies": { "browserslist": ">= 4.21.0" }, - "bin": { "update-browserslist-db": "cli.js" } - }, - "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==" - ], - - "uri-js": [ - "uri-js@4.4.1", - "", - { "dependencies": { "punycode": "^2.1.0" } }, - "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==" - ], - - "url-polyfill": [ - "url-polyfill@1.1.14", - "", - {}, - "sha512-p4f3TTAG6ADVF3mwbXw7hGw+QJyw5CnNGvYh5fCuQQZIiuKUswqcznyV3pGDP9j0TSmC4UvRKm8kl1QsX1diiQ==" - ], - - "url-value-parser": [ - "url-value-parser@2.2.0", - "", - {}, - "sha512-yIQdxJpgkPamPPAPuGdS7Q548rLhny42tg8d4vyTNzFqvOnwqrgHXvgehT09U7fwrzxi3RxCiXjoNUNnNOlQ8A==" - ], - - "use-isomorphic-layout-effect": [ - "use-isomorphic-layout-effect@1.2.1", - "", - { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==" - ], - - "util-deprecate": [ - "util-deprecate@1.0.2", - "", - {}, - "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - ], - - "utils-merge": [ - "utils-merge@1.0.1", - "", - {}, - "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" - ], - - "uuid": [ - "uuid@8.3.2", - "", - { "bin": { "uuid": "dist/bin/uuid" } }, - "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" - ], - - "uuidv7": [ - "uuidv7@1.1.0", - "", - { "bin": { "uuidv7": "cli.js" } }, - "sha512-2VNnOC0+XQlwogChUDzy6pe8GQEys9QFZBGOh54l6qVfwoCUwwRvk7rDTgaIsRgsF5GFa5oiNg8LqXE3jofBBg==" - ], - - "uvu": [ - "uvu@0.5.6", - "", - { - "dependencies": { - "dequal": "^2.0.0", - "diff": "^5.0.0", - "kleur": "^4.0.3", - "sade": "^1.7.3" - }, - "bin": { "uvu": "bin.js" } - }, - "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==" - ], - - "v8-compile-cache-lib": [ - "v8-compile-cache-lib@3.0.1", - "", - {}, - "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" - ], - - "vali-date": [ - "vali-date@1.0.0", - "", - {}, - "sha512-sgECfZthyaCKW10N0fm27cg8HYTFK5qMWgypqkXMQ4Wbl/zZKx7xZICgcoxIIE+WFAP/MBL2EFwC/YvLxw3Zeg==" - ], - - "value-equal": [ - "value-equal@1.0.1", - "", - {}, - "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" - ], - - "vary": [ - "vary@1.1.2", - "", - {}, - "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" - ], - - "verror": [ - "verror@1.10.0", - "", - { - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==" - ], - - "vfile": [ - "vfile@5.3.7", - "", - { - "dependencies": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^3.0.0", - "vfile-message": "^3.0.0" - } - }, - "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==" - ], - - "vfile-message": [ - "vfile-message@3.1.4", - "", - { - "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-stringify-position": "^3.0.0" - } - }, - "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==" - ], - - "vite": [ - "vite@8.0.0", - "", - { - "dependencies": { - "@oxc-project/runtime": "0.115.0", - "lightningcss": "^1.32.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.8", - "rolldown": "1.0.0-rc.9", - "tinyglobby": "^0.2.15" - }, - "optionalDependencies": { "fsevents": "~2.3.3" }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.0.0-alpha.31", - "esbuild": "^0.27.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "optionalPeers": [ - "@types/node", - "@vitejs/devtools", - "esbuild", - "jiti", - "less", - "sass", - "sass-embedded", - "stylus", - "sugarss", - "terser", - "tsx", - "yaml" - ], - "bin": { "vite": "bin/vite.js" } - }, - "sha512-fPGaRNj9Zytaf8LEiBhY7Z6ijnFKdzU/+mL8EFBaKr7Vw1/FWcTBAMW0wLPJAGMPX38ZPVCVgLceWiEqeoqL2Q==" - ], - - "vite-node": [ - "vite-node@3.2.4", - "", - { - "dependencies": { - "cac": "^6.7.14", - "debug": "^4.4.1", - "es-module-lexer": "^1.7.0", - "pathe": "^2.0.3", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" - }, - "bin": { "vite-node": "vite-node.mjs" } - }, - "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==" - ], - - "vite-plugin-html": [ - "vite-plugin-html@3.2.2", - "", - { - "dependencies": { - "@rollup/pluginutils": "^4.2.0", - "colorette": "^2.0.16", - "connect-history-api-fallback": "^1.6.0", - "consola": "^2.15.3", - "dotenv": "^16.0.0", - "dotenv-expand": "^8.0.2", - "ejs": "^3.1.6", - "fast-glob": "^3.2.11", - "fs-extra": "^10.0.1", - "html-minifier-terser": "^6.1.0", - "node-html-parser": "^5.3.3", - "pathe": "^0.2.0" - }, - "peerDependencies": { "vite": ">=2.0.0" } - }, - "sha512-vb9C9kcdzcIo/Oc3CLZVS03dL5pDlOFuhGlZYDCJ840BhWl/0nGeZWf3Qy7NlOayscY4Cm/QRgULCQkEZige5Q==" - ], - - "vitest": [ - "vitest@3.2.4", - "", - { - "dependencies": { - "@types/chai": "^5.2.2", - "@vitest/expect": "3.2.4", - "@vitest/mocker": "3.2.4", - "@vitest/pretty-format": "^3.2.4", - "@vitest/runner": "3.2.4", - "@vitest/snapshot": "3.2.4", - "@vitest/spy": "3.2.4", - "@vitest/utils": "3.2.4", - "chai": "^5.2.0", - "debug": "^4.4.1", - "expect-type": "^1.2.1", - "magic-string": "^0.30.17", - "pathe": "^2.0.3", - "picomatch": "^4.0.2", - "std-env": "^3.9.0", - "tinybench": "^2.9.0", - "tinyexec": "^0.3.2", - "tinyglobby": "^0.2.14", - "tinypool": "^1.1.1", - "tinyrainbow": "^2.0.0", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", - "vite-node": "3.2.4", - "why-is-node-running": "^2.3.0" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@types/debug": "^4.1.12", - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "@vitest/browser": "3.2.4", - "@vitest/ui": "3.2.4", - "happy-dom": "*", - "jsdom": "*" - }, - "optionalPeers": [ - "@edge-runtime/vm", - "@types/debug", - "@types/node", - "@vitest/browser", - "@vitest/ui", - "happy-dom", - "jsdom" - ], - "bin": { "vitest": "vitest.mjs" } - }, - "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==" - ], - - "vlq": [ - "vlq@0.2.3", - "", - {}, - "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==" - ], - - "warning": [ - "warning@4.0.3", - "", - { "dependencies": { "loose-envify": "^1.0.0" } }, - "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==" - ], - - "webidl-conversions": [ - "webidl-conversions@3.0.1", - "", - {}, - "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - ], - - "whatwg-encoding": [ - "whatwg-encoding@3.1.1", - "", - { "dependencies": { "iconv-lite": "0.6.3" } }, - "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==" - ], - - "whatwg-fetch": [ - "whatwg-fetch@3.6.20", - "", - {}, - "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==" - ], - - "whatwg-mimetype": [ - "whatwg-mimetype@4.0.0", - "", - {}, - "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==" - ], - - "whatwg-url": [ - "whatwg-url@5.0.0", - "", - { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, - "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==" - ], - - "which": [ - "which@2.0.2", - "", - { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, - "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==" - ], - - "which-boxed-primitive": [ - "which-boxed-primitive@1.1.1", - "", - { - "dependencies": { - "is-bigint": "^1.1.0", - "is-boolean-object": "^1.2.1", - "is-number-object": "^1.1.1", - "is-string": "^1.1.1", - "is-symbol": "^1.1.1" - } - }, - "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==" - ], - - "which-builtin-type": [ - "which-builtin-type@1.2.1", - "", - { - "dependencies": { - "call-bound": "^1.0.2", - "function.prototype.name": "^1.1.6", - "has-tostringtag": "^1.0.2", - "is-async-function": "^2.0.0", - "is-date-object": "^1.1.0", - "is-finalizationregistry": "^1.1.0", - "is-generator-function": "^1.0.10", - "is-regex": "^1.2.1", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.1.0", - "which-collection": "^1.0.2", - "which-typed-array": "^1.1.16" - } - }, - "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==" - ], - - "which-collection": [ - "which-collection@1.0.2", - "", - { - "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" - } - }, - "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==" - ], - - "which-module": [ - "which-module@2.0.1", - "", - {}, - "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==" - ], - - "which-typed-array": [ - "which-typed-array@1.1.20", - "", - { - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "for-each": "^0.3.5", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2" - } - }, - "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==" - ], - - "why-is-node-running": [ - "why-is-node-running@2.3.0", - "", - { - "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, - "bin": { "why-is-node-running": "cli.js" } - }, - "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==" - ], - - "widest-line": [ - "widest-line@3.1.0", - "", - { "dependencies": { "string-width": "^4.0.0" } }, - "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==" - ], - - "winston": [ - "winston@3.5.1", - "", - { - "dependencies": { - "@dabh/diagnostics": "^2.0.2", - "async": "^3.2.3", - "is-stream": "^2.0.0", - "logform": "^2.3.2", - "one-time": "^1.0.0", - "readable-stream": "^3.4.0", - "safe-stable-stringify": "^2.3.1", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.4.2" - } - }, - "sha512-tbRtVy+vsSSCLcZq/8nXZaOie/S2tPXPFt4be/Q3vI/WtYwm7rrwidxVw2GRa38FIXcJ1kUM6MOZ9Jmnk3F3UA==" - ], - - "winston-loki": [ - "winston-loki@6.1.4", - "", - { - "dependencies": { - "async-exit-hook": "2.0.1", - "btoa": "^1.2.1", - "protobufjs": "^7.2.4", - "url-polyfill": "^1.1.12", - "winston-transport": "^4.3.0" - }, - "optionalDependencies": { "snappy": "^7.2.2" } - }, - "sha512-/j/Zf7TGLjgSBck29BkPnpJlEnGQr5xqlx8A0N6LZnXYYYvyK7lFk6FPpWiD+VMO8xjaxOu1KNF9SzWaRDsigA==" - ], - - "winston-transport": [ - "winston-transport@4.5.0", - "", - { - "dependencies": { - "logform": "^2.3.2", - "readable-stream": "^3.6.0", - "triple-beam": "^1.3.0" - } - }, - "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==" - ], - - "word-wrap": [ - "word-wrap@1.2.5", - "", - {}, - "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==" - ], - - "wrap-ansi": [ - "wrap-ansi@6.2.0", - "", - { - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==" - ], - - "wrap-ansi-cjs": [ - "wrap-ansi@7.0.0", - "", - { - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==" - ], - - "wrappy": [ - "wrappy@1.0.2", - "", - {}, - "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - ], - - "write-file-atomic": [ - "write-file-atomic@3.0.3", - "", - { - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==" - ], - - "ws": [ - "ws@8.19.0", - "", - { - "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, - "optionalPeers": ["bufferutil", "utf-8-validate"] - }, - "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==" - ], - - "xtend": [ - "xtend@4.0.2", - "", - {}, - "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - ], - - "y18n": [ - "y18n@4.0.3", - "", - {}, - "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" - ], - - "yallist": [ - "yallist@4.0.0", - "", - {}, - "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - ], - - "yaml": [ - "yaml@1.10.2", - "", - {}, - "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" - ], - - "yargs": [ - "yargs@15.4.1", - "", - { - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - } - }, - "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==" - ], - - "yargs-parser": [ - "yargs-parser@18.1.3", - "", - { "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } }, - "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==" - ], - - "yn": [ - "yn@3.1.1", - "", - {}, - "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" - ], - - "yocto-queue": [ - "yocto-queue@0.1.0", - "", - {}, - "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" - ], - - "yoga-layout-prebuilt": [ - "yoga-layout-prebuilt@1.10.0", - "", - { "dependencies": { "@types/yoga-layout": "1.9.2" } }, - "sha512-YnOmtSbv4MTf7RGJMK0FvZ+KD8OEe/J5BNnR0GHhD8J/XcG/Qvxgszm0Un6FTHWW4uHlTgP0IztiXQnGyIR45g==" - ], - - "zod": [ - "zod@4.3.6", - "", - {}, - "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==" - ], - - "@ampproject/remapping/@jridgewell/trace-mapping": [ - "@jridgewell/trace-mapping@0.3.31", - "", - { - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==" - ], - - "@aws-crypto/crc32/@aws-sdk/types": [ - "@aws-sdk/types@3.973.5", - "", - { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, - "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ==" - ], - - "@aws-crypto/crc32/tslib": [ - "tslib@1.14.1", - "", - {}, - "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - ], - - "@aws-crypto/ie11-detection/tslib": [ - "tslib@1.14.1", - "", - {}, - "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - ], - - "@aws-crypto/sha256-browser/tslib": [ - "tslib@1.14.1", - "", - {}, - "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - ], - - "@aws-crypto/sha256-js/tslib": [ - "tslib@1.14.1", - "", - {}, - "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - ], - - "@aws-crypto/supports-web-crypto/tslib": [ - "tslib@1.14.1", - "", - {}, - "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - ], - - "@aws-crypto/util/@aws-sdk/types": [ - "@aws-sdk/types@3.973.5", - "", - { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, - "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ==" - ], - - "@aws-crypto/util/@aws-sdk/util-utf8-browser": [ - "@aws-sdk/util-utf8-browser@3.259.0", - "", - { "dependencies": { "tslib": "^2.3.1" } }, - "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==" - ], - - "@aws-crypto/util/tslib": [ - "tslib@1.14.1", - "", - {}, - "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - ], - - "@aws-sdk/client-s3/fast-xml-parser": [ - "fast-xml-parser@3.19.0", - "", - { "bin": { "xml2js": "cli.js" } }, - "sha512-4pXwmBplsCPv8FOY1WRakF970TjNGnGnfbOnLqjlYvMiF1SR3yOHyxMR/YCXpPTOspNF5gwudqktIP4VsWkvBg==" - ], - - "@aws-sdk/client-sts/fast-xml-parser": [ - "fast-xml-parser@3.19.0", - "", - { "bin": { "xml2js": "cli.js" } }, - "sha512-4pXwmBplsCPv8FOY1WRakF970TjNGnGnfbOnLqjlYvMiF1SR3yOHyxMR/YCXpPTOspNF5gwudqktIP4VsWkvBg==" - ], - - "@babel/code-frame/js-tokens": [ - "js-tokens@4.0.0", - "", - {}, - "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - ], - - "@babel/core/convert-source-map": [ - "convert-source-map@2.0.0", - "", - {}, - "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" - ], - - "@babel/core/json5": [ - "json5@2.2.3", - "", - { "bin": { "json5": "lib/cli.js" } }, - "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" - ], - - "@babel/core/semver": [ - "semver@6.3.1", - "", - { "bin": { "semver": "bin/semver.js" } }, - "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - ], - - "@babel/generator/@jridgewell/trace-mapping": [ - "@jridgewell/trace-mapping@0.3.31", - "", - { - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==" - ], - - "@babel/helper-compilation-targets/lru-cache": [ - "lru-cache@5.1.1", - "", - { "dependencies": { "yallist": "^3.0.2" } }, - "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==" - ], - - "@babel/helper-compilation-targets/semver": [ - "semver@6.3.1", - "", - { "bin": { "semver": "bin/semver.js" } }, - "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - ], - - "@discordjs/rest/discord-api-types": [ - "discord-api-types@0.18.1", - "", - {}, - "sha512-hNC38R9ZF4uaujaZQtQfm5CdQO58uhdkoHQAVvMfIL0LgOSZeW575W8H6upngQOuoxWd8tiRII3LLJm9zuQKYg==" - ], - - "@discordjs/rest/form-data": [ - "form-data@4.0.5", - "", - { - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" - } - }, - "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==" - ], - - "@emotion/babel-plugin/source-map": [ - "source-map@0.5.7", - "", - {}, - "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" - ], - - "@eslint-community/eslint-utils/eslint-visitor-keys": [ - "eslint-visitor-keys@3.4.3", - "", - {}, - "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==" - ], - - "@eslint/eslintrc/globals": [ - "globals@14.0.0", - "", - {}, - "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==" - ], - - "@eslint/eslintrc/js-yaml": [ - "js-yaml@4.1.1", - "", - { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, - "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==" - ], - - "@eslint/eslintrc/strip-json-comments": [ - "strip-json-comments@3.1.1", - "", - {}, - "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" - ], - - "@grpc/proto-loader/yargs": [ - "yargs@17.7.2", - "", - { - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - } - }, - "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==" - ], - - "@httptoolkit/websocket-stream/readable-stream": [ - "readable-stream@2.3.8", - "", - { - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==" - ], - - "@isaacs/cliui/string-width": [ - "string-width@5.1.2", - "", - { - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - } - }, - "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==" - ], - - "@isaacs/cliui/strip-ansi": [ - "strip-ansi@7.2.0", - "", - { "dependencies": { "ansi-regex": "^6.2.2" } }, - "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==" - ], - - "@isaacs/cliui/wrap-ansi": [ - "wrap-ansi@8.1.0", - "", - { - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - } - }, - "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==" - ], - - "@isaacs/fs-minipass/minipass": [ - "minipass@7.1.3", - "", - {}, - "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==" - ], - - "@istanbuljs/load-nyc-config/find-up": [ - "find-up@4.1.0", - "", - { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, - "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==" - ], - - "@istanbuljs/load-nyc-config/resolve-from": [ - "resolve-from@5.0.0", - "", - {}, - "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" - ], - - "@jridgewell/gen-mapping/@jridgewell/trace-mapping": [ - "@jridgewell/trace-mapping@0.3.31", - "", - { - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==" - ], - - "@jridgewell/remapping/@jridgewell/trace-mapping": [ - "@jridgewell/trace-mapping@0.3.31", - "", - { - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==" - ], - - "@jridgewell/source-map/@jridgewell/trace-mapping": [ - "@jridgewell/trace-mapping@0.3.31", - "", - { - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==" - ], - - "@kristiandupont/recase/ramda": [ - "ramda@0.30.1", - "", - {}, - "sha512-tEF5I22zJnuclswcZMc8bDIrwRHRzf+NqVEmqg50ShAZMP7MWeR/RGDthfM/p+BlqvF2fXAzpn8i+SJcYD3alw==" - ], - - "@mapbox/node-pre-gyp/consola": [ - "consola@3.4.2", - "", - {}, - "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==" - ], - - "@napi-rs/snappy-wasm32-wasi/@napi-rs/wasm-runtime": [ - "@napi-rs/wasm-runtime@1.1.1", - "", - { - "dependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1", - "@tybys/wasm-util": "^0.10.1" - } - }, - "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==" - ], - - "@nivo/annotations/lodash": [ - "lodash@4.17.23", - "", - {}, - "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==" - ], - - "@nivo/bar/lodash": [ - "lodash@4.17.23", - "", - {}, - "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==" - ], - - "@nivo/colors/lodash": [ - "lodash@4.17.23", - "", - {}, - "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==" - ], - - "@nivo/core/lodash": [ - "lodash@4.17.23", - "", - {}, - "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==" - ], - - "@nivo/scales/d3-time": [ - "d3-time@1.1.0", - "", - {}, - "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==" - ], - - "@nivo/scales/lodash": [ - "lodash@4.17.23", - "", - {}, - "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==" - ], - - "@octokit/auth-app/@octokit/types": [ - "@octokit/types@14.1.0", - "", - { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, - "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==" - ], - - "@octokit/auth-oauth-app/@octokit/types": [ - "@octokit/types@14.1.0", - "", - { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, - "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==" - ], - - "@octokit/auth-oauth-device/@octokit/types": [ - "@octokit/types@14.1.0", - "", - { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, - "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==" - ], - - "@octokit/auth-oauth-user/@octokit/types": [ - "@octokit/types@14.1.0", - "", - { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, - "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==" - ], - - "@octokit/auth-unauthenticated/@octokit/types": [ - "@octokit/types@14.1.0", - "", - { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, - "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==" - ], - - "@octokit/core/@octokit/types": [ - "@octokit/types@14.1.0", - "", - { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, - "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==" - ], - - "@octokit/endpoint/@octokit/types": [ - "@octokit/types@14.1.0", - "", - { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, - "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==" - ], - - "@octokit/graphql/@octokit/types": [ - "@octokit/types@14.1.0", - "", - { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, - "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==" - ], - - "@octokit/oauth-methods/@octokit/types": [ - "@octokit/types@14.1.0", - "", - { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, - "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==" - ], - - "@octokit/request/@octokit/types": [ - "@octokit/types@14.1.0", - "", - { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, - "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==" - ], - - "@octokit/request-error/@octokit/types": [ - "@octokit/types@14.1.0", - "", - { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, - "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==" - ], - - "@restart/ui/@restart/hooks": [ - "@restart/hooks@0.5.1", - "", - { "dependencies": { "dequal": "^2.0.3" }, "peerDependencies": { "react": ">=16.8.0" } }, - "sha512-EMoH04NHS1pbn07iLTjIjgttuqb7qu4+/EyhAx27MHpoENcB2ZdSsLTNxmKD+WEPnZigo62Qc8zjGnNxoSE/5Q==" - ], - - "@restart/ui/uncontrollable": [ - "uncontrollable@8.0.4", - "", - { "peerDependencies": { "react": ">=16.14.0" } }, - "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==" - ], - - "@rolldown/binding-wasm32-wasi/@napi-rs/wasm-runtime": [ - "@napi-rs/wasm-runtime@1.1.1", - "", - { - "dependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1", - "@tybys/wasm-util": "^0.10.1" - } - }, - "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==" - ], - - "@rollup/pluginutils/estree-walker": [ - "estree-walker@2.0.2", - "", - {}, - "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" - ], - - "@rollup/pluginutils/picomatch": [ - "picomatch@2.3.1", - "", - {}, - "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" - ], - - "@types/minimatch/minimatch": [ - "minimatch@10.2.4", - "", - { "dependencies": { "brace-expansion": "^5.0.2" } }, - "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==" - ], - - "@types/rate-limit-redis/@types/express-rate-limit": [ - "@types/express-rate-limit@3.3.5", - "", - { "dependencies": { "@types/express": "*" } }, - "sha512-v6M28DcbdATYvzTN5lFJhN2EP6BgY8MbTskcKJ/m5bmGuzFKHfbEVXF3po8U8ivOyyeT5o6HV0janPlFBBN5yg==" - ], - - "@types/superagent/form-data": [ - "form-data@4.0.5", - "", - { - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" - } - }, - "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==" - ], - - "@typescript-eslint/experimental-utils/eslint-scope": [ - "eslint-scope@5.1.1", - "", - { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, - "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==" - ], - - "@typescript-eslint/project-service/@typescript-eslint/types": [ - "@typescript-eslint/types@8.56.1", - "", - {}, - "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==" - ], - - "@typescript-eslint/type-utils/@typescript-eslint/types": [ - "@typescript-eslint/types@8.56.1", - "", - {}, - "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==" - ], - - "@typescript-eslint/type-utils/@typescript-eslint/typescript-estree": [ - "@typescript-eslint/typescript-estree@8.56.1", - "", - { - "dependencies": { - "@typescript-eslint/project-service": "8.56.1", - "@typescript-eslint/tsconfig-utils": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" - }, - "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } - }, - "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==" - ], - - "@typescript-eslint/utils/@typescript-eslint/scope-manager": [ - "@typescript-eslint/scope-manager@8.56.1", - "", - { - "dependencies": { - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1" - } - }, - "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==" - ], - - "@typescript-eslint/utils/@typescript-eslint/types": [ - "@typescript-eslint/types@8.56.1", - "", - {}, - "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==" - ], - - "@typescript-eslint/utils/@typescript-eslint/typescript-estree": [ - "@typescript-eslint/typescript-estree@8.56.1", - "", - { - "dependencies": { - "@typescript-eslint/project-service": "8.56.1", - "@typescript-eslint/tsconfig-utils": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" - }, - "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } - }, - "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==" - ], - - "@typescript-eslint/visitor-keys/eslint-visitor-keys": [ - "eslint-visitor-keys@2.1.0", - "", - {}, - "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==" - ], - - "@vitest/mocker/vite": [ - "vite@3.2.11", - "", - { - "dependencies": { - "esbuild": "^0.15.9", - "postcss": "^8.4.18", - "resolve": "^1.22.1", - "rollup": "^2.79.1" - }, - "optionalDependencies": { "fsevents": "~2.3.2" }, - "peerDependencies": { - "@types/node": ">= 14", - "less": "*", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "optionalPeers": ["@types/node", "less", "sass", "stylus", "sugarss", "terser"], - "bin": { "vite": "bin/vite.js" } - }, - "sha512-K/jGKL/PgbIgKCiJo5QbASQhFiV02X9Jh+Qq0AKCRCRKZtOTVi4t6wh75FDpGf2N9rYOnzH87OEFQNaFy6pdxQ==" - ], - - "ansi-escapes/type-fest": [ - "type-fest@0.21.3", - "", - {}, - "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" - ], - - "anymatch/picomatch": [ - "picomatch@2.3.1", - "", - {}, - "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" - ], - - "ast-v8-to-istanbul/@jridgewell/trace-mapping": [ - "@jridgewell/trace-mapping@0.3.31", - "", - { - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==" - ], - - "aws-crt/@aws-sdk/util-utf8-browser": [ - "@aws-sdk/util-utf8-browser@3.259.0", - "", - { "dependencies": { "tslib": "^2.3.1" } }, - "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==" - ], - - "aws-crt/buffer": [ - "buffer@6.0.3", - "", - { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, - "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==" - ], - - "axios/form-data": [ - "form-data@4.0.5", - "", - { - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" - } - }, - "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==" - ], - - "babel-plugin-macros/resolve": [ - "resolve@1.22.11", - "", - { - "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { "resolve": "bin/resolve" } - }, - "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==" - ], - - "bl/readable-stream": [ - "readable-stream@2.3.8", - "", - { - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==" - ], - - "bms-table-loader/node-fetch": [ - "node-fetch@2.6.2", - "", - {}, - "sha512-aLoxToI6RfZ+0NOjmWAgn9+LEd30YCkJKFSyWacNZdEKTit/ZMcKjGkTRo8uWEsnIb/hfKecNPEbln02PdWbcA==" - ], - - "bms-table-loader/zod": [ - "zod@3.25.76", - "", - {}, - "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==" - ], - - "body-parser/debug": [ - "debug@2.6.9", - "", - { "dependencies": { "ms": "2.0.0" } }, - "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==" - ], - - "body-parser/iconv-lite": [ - "iconv-lite@0.4.24", - "", - { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, - "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==" - ], - - "body-parser/qs": [ - "qs@6.13.0", - "", - { "dependencies": { "side-channel": "^1.0.6" } }, - "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==" - ], - - "bullmq/lodash": [ - "lodash@4.17.23", - "", - {}, - "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==" - ], - - "bullmq/semver": [ - "semver@6.3.1", - "", - { "bin": { "semver": "bin/semver.js" } }, - "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - ], - - "bullmq/tslib": [ - "tslib@1.14.1", - "", - {}, - "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - ], - - "cheerio-select/css-select": [ - "css-select@5.2.2", - "", - { - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - } - }, - "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==" - ], - - "chokidar/glob-parent": [ - "glob-parent@5.1.2", - "", - { "dependencies": { "is-glob": "^4.0.1" } }, - "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==" - ], - - "cliui/strip-ansi": [ - "strip-ansi@6.0.1", - "", - { "dependencies": { "ansi-regex": "^5.0.1" } }, - "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==" - ], - - "cliui/wrap-ansi": [ - "wrap-ansi@7.0.0", - "", - { - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==" - ], - - "color/color-convert": [ - "color-convert@3.1.3", - "", - { "dependencies": { "color-name": "^2.0.0" } }, - "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==" - ], - - "color-string/color-name": [ - "color-name@2.1.0", - "", - {}, - "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==" - ], - - "css-select/domhandler": [ - "domhandler@4.3.1", - "", - { "dependencies": { "domelementtype": "^2.2.0" } }, - "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==" - ], - - "css-select/domutils": [ - "domutils@2.8.0", - "", - { - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - } - }, - "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==" - ], - - "default-require-extensions/strip-bom": [ - "strip-bom@4.0.0", - "", - {}, - "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==" - ], - - "defaults/clone": [ - "clone@1.0.4", - "", - {}, - "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==" - ], - - "discord.js/@discordjs/builders": [ - "@discordjs/builders@0.11.0", - "", - { - "dependencies": { - "@sindresorhus/is": "^4.2.0", - "discord-api-types": "^0.26.0", - "ts-mixer": "^6.0.0", - "tslib": "^2.3.1", - "zod": "^3.11.6" - } - }, - "sha512-ZTB8yJdJKrKlq44dpWkNUrAtEJEq0gqpb7ASdv4vmq6/mZal5kOv312hQ56I/vxwMre+VIkoHquNUAfnTbiYtg==" - ], - - "discord.js/@discordjs/collection": [ - "@discordjs/collection@0.4.0", - "", - {}, - "sha512-zmjq+l/rV35kE6zRrwe8BHqV78JvIh2ybJeZavBi5NySjWXqN3hmmAKg7kYMMXSeiWtSsMoZ/+MQi0DiQWy2lw==" - ], - - "discord.js/discord-api-types": [ - "discord-api-types@0.26.1", - "", - {}, - "sha512-T5PdMQ+Y1MEECYMV5wmyi9VEYPagEDEi4S0amgsszpWY0VB9JJ/hEvM6BgLhbdnKky4gfmZEXtEEtojN8ZKJQQ==" - ], - - "discord.js/form-data": [ - "form-data@4.0.5", - "", - { - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" - } - }, - "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==" - ], - - "dom-serializer/entities": [ - "entities@4.5.0", - "", - {}, - "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" - ], - - "duplexify/readable-stream": [ - "readable-stream@2.3.8", - "", - { - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==" - ], - - "eslint-import-resolver-node/debug": [ - "debug@3.2.7", - "", - { "dependencies": { "ms": "^2.1.1" } }, - "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==" - ], - - "eslint-import-resolver-node/resolve": [ - "resolve@1.22.11", - "", - { - "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { "resolve": "bin/resolve" } - }, - "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==" - ], - - "eslint-module-utils/debug": [ - "debug@3.2.7", - "", - { "dependencies": { "ms": "^2.1.1" } }, - "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==" - ], - - "eslint-plugin-import/debug": [ - "debug@3.2.7", - "", - { "dependencies": { "ms": "^2.1.1" } }, - "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==" - ], - - "eslint-plugin-import/semver": [ - "semver@6.3.1", - "", - { "bin": { "semver": "bin/semver.js" } }, - "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - ], - - "eslint-plugin-import/tsconfig-paths": [ - "tsconfig-paths@3.15.0", - "", - { - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==" - ], - - "eslint-plugin-perfectionist/@typescript-eslint/types": [ - "@typescript-eslint/types@8.56.1", - "", - {}, - "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==" - ], - - "eslint-plugin-perfectionist/minimatch": [ - "minimatch@9.0.9", - "", - { "dependencies": { "brace-expansion": "^2.0.2" } }, - "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==" - ], - - "eslint-plugin-react/prop-types": [ - "prop-types@15.8.1", - "", - { - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==" - ], - - "eslint-plugin-react/semver": [ - "semver@6.3.1", - "", - { "bin": { "semver": "bin/semver.js" } }, - "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - ], - - "eslint-utils/eslint-visitor-keys": [ - "eslint-visitor-keys@2.1.0", - "", - {}, - "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==" - ], - - "express/debug": [ - "debug@2.6.9", - "", - { "dependencies": { "ms": "2.0.0" } }, - "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==" - ], - - "express-session/cookie": [ - "cookie@0.4.1", - "", - {}, - "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" - ], - - "express-session/debug": [ - "debug@2.6.9", - "", - { "dependencies": { "ms": "2.0.0" } }, - "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==" - ], - - "extract-pg-schema/pg": [ - "pg@8.17.2", - "", - { - "dependencies": { - "pg-connection-string": "^2.10.1", - "pg-pool": "^3.11.0", - "pg-protocol": "^1.11.0", - "pg-types": "2.2.0", - "pgpass": "1.0.5" - }, - "optionalDependencies": { "pg-cloudflare": "^1.3.0" }, - "peerDependencies": { "pg-native": ">=3.0.1" }, - "optionalPeers": ["pg-native"] - }, - "sha512-vjbKdiBJRqzcYw1fNU5KuHyYvdJ1qpcQg1CeBrHFqV1pWgHeVR6j/+kX0E1AAXfyuLUGY1ICrN2ELKA/z2HWzw==" - ], - - "extract-pg-schema/ramda": [ - "ramda@0.31.3", - "", - {}, - "sha512-xKADKRNnqmDdX59PPKLm3gGmk1ZgNnj3k7DryqWwkamp4TJ6B36DdpyKEQ0EoEYmH2R62bV4Q+S0ym2z8N2f3Q==" - ], - - "fast-glob/glob-parent": [ - "glob-parent@5.1.2", - "", - { "dependencies": { "is-glob": "^4.0.1" } }, - "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==" - ], - - "filelist/minimatch": [ - "minimatch@5.1.9", - "", - { "dependencies": { "brace-expansion": "^2.0.1" } }, - "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==" - ], - - "finalhandler/debug": [ - "debug@2.6.9", - "", - { "dependencies": { "ms": "2.0.0" } }, - "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==" - ], - - "finalhandler/encodeurl": [ - "encodeurl@1.0.2", - "", - {}, - "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" - ], - - "formidable/qs": [ - "qs@6.13.0", - "", - { "dependencies": { "side-channel": "^1.0.6" } }, - "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==" - ], - - "formik/deepmerge": [ - "deepmerge@2.2.1", - "", - {}, - "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==" - ], - - "formik/lodash": [ - "lodash@4.17.23", - "", - {}, - "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==" - ], - - "formik/tslib": [ - "tslib@1.14.1", - "", - {}, - "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - ], - - "hasha/type-fest": [ - "type-fest@0.8.1", - "", - {}, - "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" - ], - - "hoist-non-react-statics/react-is": [ - "react-is@16.13.1", - "", - {}, - "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - ], - - "htmlparser2/entities": [ - "entities@7.0.1", - "", - {}, - "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==" - ], - - "import-fresh/resolve-from": [ - "resolve-from@4.0.0", - "", - {}, - "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" - ], - - "ink/chalk": [ - "chalk@3.0.0", - "", - { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, - "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==" - ], - - "ink/prop-types": [ - "prop-types@15.8.1", - "", - { - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==" - ], - - "ink/scheduler": [ - "scheduler@0.18.0", - "", - { "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" } }, - "sha512-agTSHR1Nbfi6ulI0kYNK0203joW2Y5W4po4l+v03tOoiJKpTBbxpNhWDvqc/4IcOw+KLmSiQLTasZ4cab2/UWQ==" - ], - - "ioredis/p-map": [ - "p-map@2.1.0", - "", - {}, - "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==" - ], - - "isomorphic-fetch/node-fetch": [ - "node-fetch@1.7.3", - "", - { "dependencies": { "encoding": "^0.1.11", "is-stream": "^1.0.1" } }, - "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==" - ], - - "istanbul-lib-instrument/semver": [ - "semver@6.3.1", - "", - { "bin": { "semver": "bin/semver.js" } }, - "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - ], - - "istanbul-lib-report/make-dir": [ - "make-dir@4.0.0", - "", - { "dependencies": { "semver": "^7.5.3" } }, - "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==" - ], - - "istanbul-lib-source-maps/@jridgewell/trace-mapping": [ - "@jridgewell/trace-mapping@0.3.31", - "", - { - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==" - ], - - "kanel/rimraf": [ - "rimraf@6.1.3", - "", - { - "dependencies": { "glob": "^13.0.3", "package-json-from-dist": "^1.0.1" }, - "bin": { "rimraf": "dist/esm/bin.mjs" } - }, - "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==" - ], - - "knex/colorette": [ - "colorette@2.0.19", - "", - {}, - "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==" - ], - - "knex/commander": [ - "commander@10.0.1", - "", - {}, - "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==" - ], - - "knex/debug": [ - "debug@4.3.4", - "", - { "dependencies": { "ms": "2.1.2" } }, - "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==" - ], - - "knex/lodash": [ - "lodash@4.17.23", - "", - {}, - "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==" - ], - - "knex/pg-connection-string": [ - "pg-connection-string@2.6.2", - "", - {}, - "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==" - ], - - "knex/resolve-from": [ - "resolve-from@5.0.0", - "", - {}, - "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" - ], - - "libtap/tap-parser": [ - "tap-parser@11.0.2", - "", - { - "dependencies": { - "events-to-array": "^1.0.1", - "minipass": "^3.1.6", - "tap-yaml": "^1.0.0" - }, - "bin": { "tap-parser": "bin/cmd.js" } - }, - "sha512-6qGlC956rcORw+fg7Fv1iCRAY8/bU9UabUAhs3mXRH6eRmVZcNPLheSXCYaVaYeSwx5xa/1HXZb1537YSvwDZg==" - ], - - "log-update/ansi-escapes": [ - "ansi-escapes@3.2.0", - "", - {}, - "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==" - ], - - "log-update/cli-cursor": [ - "cli-cursor@2.1.0", - "", - { "dependencies": { "restore-cursor": "^2.0.0" } }, - "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==" - ], - - "log-update/wrap-ansi": [ - "wrap-ansi@5.1.0", - "", - { - "dependencies": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - } - }, - "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==" - ], - - "loose-envify/js-tokens": [ - "js-tokens@4.0.0", - "", - {}, - "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - ], - - "make-dir/semver": [ - "semver@6.3.1", - "", - { "bin": { "semver": "bin/semver.js" } }, - "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - ], - - "micromatch/picomatch": [ - "picomatch@2.3.1", - "", - {}, - "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" - ], - - "minizlib/minipass": [ - "minipass@7.1.3", - "", - {}, - "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==" - ], - - "mqtt/duplexify": [ - "duplexify@4.1.3", - "", - { - "dependencies": { - "end-of-stream": "^1.4.1", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1", - "stream-shift": "^1.0.2" - } - }, - "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==" - ], - - "mqtt/help-me": [ - "help-me@3.0.0", - "", - { "dependencies": { "glob": "^7.1.6", "readable-stream": "^3.6.0" } }, - "sha512-hx73jClhyk910sidBB7ERlnhMlFsJJIBqSVMFDwPN8o2v9nmp5KgLq1Xz1Bf1fCMMZ6mPrX159iG0VLy/fPMtQ==" - ], - - "mqtt/split2": [ - "split2@3.2.2", - "", - { "dependencies": { "readable-stream": "^3.0.0" } }, - "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==" - ], - - "mqtt/ws": [ - "ws@7.5.10", - "", - { - "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, - "optionalPeers": ["bufferutil", "utf-8-validate"] - }, - "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==" - ], - - "mqtt-packet/bl": [ - "bl@4.1.0", - "", - { - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==" - ], - - "multer/mkdirp": [ - "mkdirp@0.5.6", - "", - { "dependencies": { "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" } }, - "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==" - ], - - "mv/mkdirp": [ - "mkdirp@0.5.6", - "", - { "dependencies": { "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" } }, - "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==" - ], - - "mv/rimraf": [ - "rimraf@2.4.5", - "", - { "dependencies": { "glob": "^6.0.1" }, "bin": { "rimraf": "./bin.js" } }, - "sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==" - ], - - "node-exports-info/semver": [ - "semver@6.3.1", - "", - { "bin": { "semver": "bin/semver.js" } }, - "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - ], - - "node-mocks-http/depd": [ - "depd@1.1.2", - "", - {}, - "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" - ], - - "nodemon/debug": [ - "debug@3.2.7", - "", - { "dependencies": { "ms": "^2.1.1" } }, - "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==" - ], - - "nodemon/semver": [ - "semver@5.7.2", - "", - { "bin": { "semver": "bin/semver" } }, - "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" - ], - - "nodemon/supports-color": [ - "supports-color@5.5.0", - "", - { "dependencies": { "has-flag": "^3.0.0" } }, - "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==" - ], - - "nyc/find-up": [ - "find-up@4.1.0", - "", - { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, - "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==" - ], - - "nyc/istanbul-lib-source-maps": [ - "istanbul-lib-source-maps@4.0.1", - "", - { - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - } - }, - "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==" - ], - - "nyc/resolve-from": [ - "resolve-from@5.0.0", - "", - {}, - "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" - ], - - "nyc/test-exclude": [ - "test-exclude@6.0.0", - "", - { - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, - "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==" - ], - - "parse5/entities": [ - "entities@6.0.1", - "", - {}, - "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==" - ], - - "path-scurry/lru-cache": [ - "lru-cache@11.2.6", - "", - {}, - "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==" - ], - - "path-scurry/minipass": [ - "minipass@7.1.3", - "", - {}, - "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==" - ], - - "pkg-dir/find-up": [ - "find-up@4.1.0", - "", - { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, - "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==" - ], - - "postcss/nanoid": [ - "nanoid@3.3.11", - "", - { "bin": { "nanoid": "bin/nanoid.cjs" } }, - "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==" - ], - - "prop-types-extra/react-is": [ - "react-is@16.13.1", - "", - {}, - "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - ], - - "raw-body/iconv-lite": [ - "iconv-lite@0.4.24", - "", - { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, - "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==" - ], - - "rc/strip-json-comments": [ - "strip-json-comments@2.0.1", - "", - {}, - "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==" - ], - - "react-async-script/prop-types": [ - "prop-types@15.8.1", - "", - { - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==" - ], - - "react-bootstrap/prop-types": [ - "prop-types@15.8.1", - "", - { - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==" - ], - - "react-google-recaptcha/prop-types": [ - "prop-types@15.8.1", - "", - { - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==" - ], - - "react-markdown/prop-types": [ - "prop-types@15.8.1", - "", - { - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==" - ], - - "react-reconciler/prop-types": [ - "prop-types@15.8.1", - "", - { - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==" - ], - - "react-reconciler/scheduler": [ - "scheduler@0.18.0", - "", - { "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" } }, - "sha512-agTSHR1Nbfi6ulI0kYNK0203joW2Y5W4po4l+v03tOoiJKpTBbxpNhWDvqc/4IcOw+KLmSiQLTasZ4cab2/UWQ==" - ], - - "react-router/path-to-regexp": [ - "path-to-regexp@1.9.0", - "", - { "dependencies": { "isarray": "0.0.1" } }, - "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==" - ], - - "react-router/prop-types": [ - "prop-types@15.8.1", - "", - { - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==" - ], - - "react-router/react-is": [ - "react-is@16.13.1", - "", - {}, - "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - ], - - "react-router-bootstrap/prop-types": [ - "prop-types@15.8.1", - "", - { - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==" - ], - - "react-router-dom/prop-types": [ - "prop-types@15.8.1", - "", - { - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==" - ], - - "react-select/prop-types": [ - "prop-types@15.8.1", - "", - { - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==" - ], - - "react-transition-group/prop-types": [ - "prop-types@15.8.1", - "", - { - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==" - ], - - "readdirp/picomatch": [ - "picomatch@2.3.1", - "", - {}, - "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" - ], - - "rechoir/resolve": [ - "resolve@1.22.11", - "", - { - "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { "resolve": "bin/resolve" } - }, - "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==" - ], - - "request/form-data": [ - "form-data@2.3.3", - "", - { - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==" - ], - - "request/qs": [ - "qs@6.5.5", - "", - {}, - "sha512-mzR4sElr1bfCaPJe7m8ilJ6ZXdDaGoObcYR0ZHSsktM/Lt21MVHj5De30GQH2eiZ1qGRTO7LCAzQsUeXTNexWQ==" - ], - - "request/uuid": [ - "uuid@3.4.0", - "", - { "bin": { "uuid": "./bin/uuid" } }, - "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - ], - - "require_optional/resolve-from": [ - "resolve-from@2.0.0", - "", - {}, - "sha512-qpFcKaXsq8+oRoLilkwyc7zHGF5i9Q2/25NIgLQQ/+VVv9rU4qvr6nXVAw1DsnXJyQkZsR4Ytfbtg5ehfcUssQ==" - ], - - "require_optional/semver": [ - "semver@5.7.2", - "", - { "bin": { "semver": "bin/semver" } }, - "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" - ], - - "rolldown/@rolldown/pluginutils": [ - "@rolldown/pluginutils@1.0.0-rc.9", - "", - {}, - "sha512-w6oiRWgEBl04QkFZgmW+jnU1EC9b57Oihi2ot3HNWIQRqgHp5PnYDia5iZ5FF7rpa4EQdiqMDXjlqKGXBhsoXw==" - ], - - "safe-array-concat/isarray": [ - "isarray@2.0.5", - "", - {}, - "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - ], - - "safe-push-apply/isarray": [ - "isarray@2.0.5", - "", - {}, - "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - ], - - "send/debug": [ - "debug@2.6.9", - "", - { "dependencies": { "ms": "2.0.0" } }, - "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==" - ], - - "send/encodeurl": [ - "encodeurl@1.0.2", - "", - {}, - "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" - ], - - "serve-static/encodeurl": [ - "encodeurl@1.0.2", - "", - {}, - "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" - ], - - "serve-static/send": [ - "send@0.18.0", - "", - { - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - } - }, - "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==" - ], - - "simple-update-notifier/semver": [ - "semver@7.0.0", - "", - { "bin": { "semver": "bin/semver.js" } }, - "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" - ], - - "stack-utils/escape-string-regexp": [ - "escape-string-regexp@2.0.0", - "", - {}, - "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" - ], - - "string-length/astral-regex": [ - "astral-regex@1.0.0", - "", - {}, - "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==" - ], - - "string-width/emoji-regex": [ - "emoji-regex@8.0.0", - "", - {}, - "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - ], - - "string-width/strip-ansi": [ - "strip-ansi@6.0.1", - "", - { "dependencies": { "ansi-regex": "^5.0.1" } }, - "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==" - ], - - "string-width-cjs/emoji-regex": [ - "emoji-regex@8.0.0", - "", - {}, - "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - ], - - "string-width-cjs/strip-ansi": [ - "strip-ansi@6.0.1", - "", - { "dependencies": { "ansi-regex": "^5.0.1" } }, - "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==" - ], - - "strip-ansi-cjs/ansi-regex": [ - "ansi-regex@5.0.1", - "", - {}, - "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - ], - - "strip-literal/js-tokens": [ - "js-tokens@9.0.1", - "", - {}, - "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==" - ], - - "superagent/form-data": [ - "form-data@4.0.5", - "", - { - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" - } - }, - "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==" - ], - - "superagent/mime": [ - "mime@2.6.0", - "", - { "bin": { "mime": "cli.js" } }, - "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==" - ], - - "superagent/qs": [ - "qs@6.13.0", - "", - { "dependencies": { "side-channel": "^1.0.6" } }, - "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==" - ], - - "tachi-common/@types/tap": [ - "@types/tap@15.0.5", - "", - { "dependencies": { "@types/node": "*" } }, - "sha512-MaP+EgZNFAGRvVjHWv8ldrLvYBn4PnmAlzY7IL3/RPAPkOXdggTSTgLFONbnTpdQTe8+ixYGAySKAm9ESlZm1A==" - ], - - "tachi-server/@types/tap": [ - "@types/tap@15.0.5", - "", - { "dependencies": { "@types/node": "*" } }, - "sha512-MaP+EgZNFAGRvVjHWv8ldrLvYBn4PnmAlzY7IL3/RPAPkOXdggTSTgLFONbnTpdQTe8+ixYGAySKAm9ESlZm1A==" - ], - - "tap-mocha-reporter/escape-string-regexp": [ - "escape-string-regexp@2.0.0", - "", - {}, - "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" - ], - - "tap-mocha-reporter/tap-parser": [ - "tap-parser@11.0.2", - "", - { - "dependencies": { - "events-to-array": "^1.0.1", - "minipass": "^3.1.6", - "tap-yaml": "^1.0.0" - }, - "bin": { "tap-parser": "bin/cmd.js" } - }, - "sha512-6qGlC956rcORw+fg7Fv1iCRAY8/bU9UabUAhs3mXRH6eRmVZcNPLheSXCYaVaYeSwx5xa/1HXZb1537YSvwDZg==" - ], - - "tar/chownr": [ - "chownr@3.0.0", - "", - {}, - "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==" - ], - - "tar/minipass": [ - "minipass@7.1.3", - "", - {}, - "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==" - ], - - "tar/yallist": [ - "yallist@5.0.0", - "", - {}, - "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==" - ], - - "tar-stream/bl": [ - "bl@4.1.0", - "", - { - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==" - ], - - "terser/commander": [ - "commander@2.20.3", - "", - {}, - "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - ], - - "test-exclude/glob": [ - "glob@10.5.0", - "", - { - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { "glob": "dist/esm/bin.mjs" } - }, - "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==" - ], - - "test-exclude/minimatch": [ - "minimatch@10.2.4", - "", - { "dependencies": { "brace-expansion": "^5.0.2" } }, - "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==" - ], - - "treport/chalk": [ - "chalk@3.0.0", - "", - { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, - "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==" - ], - - "tsc-alias/commander": [ - "commander@9.0.0", - "", - {}, - "sha512-JJfP2saEKbQqvW+FI93OYUB4ByV5cizMpFMiiJI8xDbBvQvSkIk0VvQdn1CZ8mqAO8Loq2h0gYTYtDFUZUeERw==" - ], - - "tsconfig-paths/@types/json5": [ - "@types/json5@0.0.29", - "", - {}, - "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" - ], - - "tsconfig-paths/json5": [ - "json5@1.0.2", - "", - { "dependencies": { "minimist": "^1.2.0" }, "bin": { "json5": "lib/cli.js" } }, - "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==" - ], - - "tsutils/tslib": [ - "tslib@1.14.1", - "", - {}, - "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - ], - - "typescript-eslint/@typescript-eslint/eslint-plugin": [ - "@typescript-eslint/eslint-plugin@8.56.1", - "", - { - "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/type-utils": "8.56.1", - "@typescript-eslint/utils": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.4.0" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.56.1", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==" - ], - - "typescript-eslint/@typescript-eslint/parser": [ - "@typescript-eslint/parser@8.56.1", - "", - { - "dependencies": { - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", - "debug": "^4.4.3" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==" - ], - - "typescript-eslint/@typescript-eslint/typescript-estree": [ - "@typescript-eslint/typescript-estree@8.56.1", - "", - { - "dependencies": { - "@typescript-eslint/project-service": "8.56.1", - "@typescript-eslint/tsconfig-utils": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" - }, - "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } - }, - "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==" - ], - - "uvu/diff": [ - "diff@5.2.2", - "", - {}, - "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==" - ], - - "verror/core-util-is": [ - "core-util-is@1.0.2", - "", - {}, - "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" - ], - - "vite-node/vite": [ - "vite@7.3.1", - "", - { - "dependencies": { - "esbuild": "^0.27.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" - }, - "optionalDependencies": { "fsevents": "~2.3.3" }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "lightningcss": "^1.21.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "optionalPeers": [ - "@types/node", - "jiti", - "less", - "lightningcss", - "sass", - "sass-embedded", - "stylus", - "sugarss", - "terser", - "tsx", - "yaml" - ], - "bin": { "vite": "bin/vite.js" } - }, - "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==" - ], - - "vite-plugin-html/fs-extra": [ - "fs-extra@10.1.0", - "", - { - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==" - ], - - "vite-plugin-html/pathe": [ - "pathe@0.2.0", - "", - {}, - "sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==" - ], - - "vitest/vite": [ - "vite@7.3.1", - "", - { - "dependencies": { - "esbuild": "^0.27.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" - }, - "optionalDependencies": { "fsevents": "~2.3.3" }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "lightningcss": "^1.21.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "optionalPeers": [ - "@types/node", - "jiti", - "less", - "lightningcss", - "sass", - "sass-embedded", - "stylus", - "sugarss", - "terser", - "tsx", - "yaml" - ], - "bin": { "vite": "bin/vite.js" } - }, - "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==" - ], - - "which-builtin-type/isarray": [ - "isarray@2.0.5", - "", - {}, - "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - ], - - "wrap-ansi/strip-ansi": [ - "strip-ansi@6.0.1", - "", - { "dependencies": { "ansi-regex": "^5.0.1" } }, - "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==" - ], - - "wrap-ansi-cjs/strip-ansi": [ - "strip-ansi@6.0.1", - "", - { "dependencies": { "ansi-regex": "^5.0.1" } }, - "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==" - ], - - "yargs/cliui": [ - "cliui@6.0.0", - "", - { - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==" - ], - - "yargs/find-up": [ - "find-up@4.1.0", - "", - { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, - "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==" - ], - - "@aws-crypto/crc32/@aws-sdk/types/tslib": [ - "tslib@2.8.1", - "", - {}, - "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" - ], - - "@aws-crypto/util/@aws-sdk/types/tslib": [ - "tslib@2.8.1", - "", - {}, - "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" - ], - - "@aws-crypto/util/@aws-sdk/util-utf8-browser/tslib": [ - "tslib@2.8.1", - "", - {}, - "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" - ], - - "@babel/helper-compilation-targets/lru-cache/yallist": [ - "yallist@3.1.1", - "", - {}, - "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - ], - - "@eslint/eslintrc/js-yaml/argparse": [ - "argparse@2.0.1", - "", - {}, - "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - ], - - "@grpc/proto-loader/yargs/cliui": [ - "cliui@8.0.1", - "", - { - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - } - }, - "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==" - ], - - "@grpc/proto-loader/yargs/y18n": [ - "y18n@5.0.8", - "", - {}, - "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" - ], - - "@grpc/proto-loader/yargs/yargs-parser": [ - "yargs-parser@21.1.1", - "", - {}, - "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" - ], - - "@httptoolkit/websocket-stream/readable-stream/safe-buffer": [ - "safe-buffer@5.1.2", - "", - {}, - "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - ], - - "@httptoolkit/websocket-stream/readable-stream/string_decoder": [ - "string_decoder@1.1.1", - "", - { "dependencies": { "safe-buffer": "~5.1.0" } }, - "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==" - ], - - "@isaacs/cliui/strip-ansi/ansi-regex": [ - "ansi-regex@6.2.2", - "", - {}, - "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==" - ], - - "@isaacs/cliui/wrap-ansi/ansi-styles": [ - "ansi-styles@6.2.3", - "", - {}, - "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==" - ], - - "@istanbuljs/load-nyc-config/find-up/locate-path": [ - "locate-path@5.0.0", - "", - { "dependencies": { "p-locate": "^4.1.0" } }, - "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==" - ], - - "@octokit/auth-app/@octokit/types/@octokit/openapi-types": [ - "@octokit/openapi-types@25.1.0", - "", - {}, - "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==" - ], - - "@octokit/auth-oauth-app/@octokit/types/@octokit/openapi-types": [ - "@octokit/openapi-types@25.1.0", - "", - {}, - "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==" - ], - - "@octokit/auth-oauth-device/@octokit/types/@octokit/openapi-types": [ - "@octokit/openapi-types@25.1.0", - "", - {}, - "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==" - ], - - "@octokit/auth-oauth-user/@octokit/types/@octokit/openapi-types": [ - "@octokit/openapi-types@25.1.0", - "", - {}, - "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==" - ], - - "@octokit/auth-unauthenticated/@octokit/types/@octokit/openapi-types": [ - "@octokit/openapi-types@25.1.0", - "", - {}, - "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==" - ], - - "@octokit/core/@octokit/types/@octokit/openapi-types": [ - "@octokit/openapi-types@25.1.0", - "", - {}, - "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==" - ], - - "@octokit/endpoint/@octokit/types/@octokit/openapi-types": [ - "@octokit/openapi-types@25.1.0", - "", - {}, - "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==" - ], - - "@octokit/graphql/@octokit/types/@octokit/openapi-types": [ - "@octokit/openapi-types@25.1.0", - "", - {}, - "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==" - ], - - "@octokit/oauth-methods/@octokit/types/@octokit/openapi-types": [ - "@octokit/openapi-types@25.1.0", - "", - {}, - "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==" - ], - - "@octokit/request-error/@octokit/types/@octokit/openapi-types": [ - "@octokit/openapi-types@25.1.0", - "", - {}, - "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==" - ], - - "@octokit/request/@octokit/types/@octokit/openapi-types": [ - "@octokit/openapi-types@25.1.0", - "", - {}, - "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==" - ], - - "@types/minimatch/minimatch/brace-expansion": [ - "brace-expansion@5.0.4", - "", - { "dependencies": { "balanced-match": "^4.0.2" } }, - "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==" - ], - - "@typescript-eslint/experimental-utils/eslint-scope/estraverse": [ - "estraverse@4.3.0", - "", - {}, - "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" - ], - - "@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys": [ - "@typescript-eslint/visitor-keys@8.56.1", - "", - { - "dependencies": { - "@typescript-eslint/types": "8.56.1", - "eslint-visitor-keys": "^5.0.0" - } - }, - "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==" - ], - - "@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/minimatch": [ - "minimatch@10.2.4", - "", - { "dependencies": { "brace-expansion": "^5.0.2" } }, - "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==" - ], - - "@typescript-eslint/utils/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys": [ - "@typescript-eslint/visitor-keys@8.56.1", - "", - { - "dependencies": { - "@typescript-eslint/types": "8.56.1", - "eslint-visitor-keys": "^5.0.0" - } - }, - "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==" - ], - - "@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys": [ - "@typescript-eslint/visitor-keys@8.56.1", - "", - { - "dependencies": { - "@typescript-eslint/types": "8.56.1", - "eslint-visitor-keys": "^5.0.0" - } - }, - "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==" - ], - - "@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch": [ - "minimatch@10.2.4", - "", - { "dependencies": { "brace-expansion": "^5.0.2" } }, - "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==" - ], - - "@vitest/mocker/vite/esbuild": [ - "esbuild@0.15.18", - "", - { - "optionalDependencies": { - "@esbuild/android-arm": "0.15.18", - "@esbuild/linux-loong64": "0.15.18", - "esbuild-android-64": "0.15.18", - "esbuild-android-arm64": "0.15.18", - "esbuild-darwin-64": "0.15.18", - "esbuild-darwin-arm64": "0.15.18", - "esbuild-freebsd-64": "0.15.18", - "esbuild-freebsd-arm64": "0.15.18", - "esbuild-linux-32": "0.15.18", - "esbuild-linux-64": "0.15.18", - "esbuild-linux-arm": "0.15.18", - "esbuild-linux-arm64": "0.15.18", - "esbuild-linux-mips64le": "0.15.18", - "esbuild-linux-ppc64le": "0.15.18", - "esbuild-linux-riscv64": "0.15.18", - "esbuild-linux-s390x": "0.15.18", - "esbuild-netbsd-64": "0.15.18", - "esbuild-openbsd-64": "0.15.18", - "esbuild-sunos-64": "0.15.18", - "esbuild-windows-32": "0.15.18", - "esbuild-windows-64": "0.15.18", - "esbuild-windows-arm64": "0.15.18" - }, - "bin": { "esbuild": "bin/esbuild" } - }, - "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==" - ], - - "@vitest/mocker/vite/resolve": [ - "resolve@1.22.11", - "", - { - "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { "resolve": "bin/resolve" } - }, - "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==" - ], - - "@vitest/mocker/vite/rollup": [ - "rollup@2.80.0", - "", - { - "optionalDependencies": { "fsevents": "~2.3.2" }, - "bin": { "rollup": "dist/bin/rollup" } - }, - "sha512-cIFJOD1DESzpjOBl763Kp1AH7UE/0fcdHe6rZXUdQ9c50uvgigvW97u3IcSeBwOkgqL/PXPBktBCh0KEu5L8XQ==" - ], - - "bl/readable-stream/safe-buffer": [ - "safe-buffer@5.1.2", - "", - {}, - "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - ], - - "bl/readable-stream/string_decoder": [ - "string_decoder@1.1.1", - "", - { "dependencies": { "safe-buffer": "~5.1.0" } }, - "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==" - ], - - "body-parser/debug/ms": [ - "ms@2.0.0", - "", - {}, - "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - ], - - "cliui/strip-ansi/ansi-regex": [ - "ansi-regex@5.0.1", - "", - {}, - "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - ], - - "color/color-convert/color-name": [ - "color-name@2.1.0", - "", - {}, - "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==" - ], - - "css-select/domutils/dom-serializer": [ - "dom-serializer@1.4.1", - "", - { - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - } - }, - "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==" - ], - - "discord.js/@discordjs/builders/zod": [ - "zod@3.25.76", - "", - {}, - "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==" - ], - - "duplexify/readable-stream/safe-buffer": [ - "safe-buffer@5.1.2", - "", - {}, - "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - ], - - "duplexify/readable-stream/string_decoder": [ - "string_decoder@1.1.1", - "", - { "dependencies": { "safe-buffer": "~5.1.0" } }, - "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==" - ], - - "eslint-plugin-import/tsconfig-paths/@types/json5": [ - "@types/json5@0.0.29", - "", - {}, - "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" - ], - - "eslint-plugin-import/tsconfig-paths/json5": [ - "json5@1.0.2", - "", - { "dependencies": { "minimist": "^1.2.0" }, "bin": { "json5": "lib/cli.js" } }, - "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==" - ], - - "eslint-plugin-perfectionist/minimatch/brace-expansion": [ - "brace-expansion@2.0.2", - "", - { "dependencies": { "balanced-match": "^1.0.0" } }, - "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==" - ], - - "eslint-plugin-react/prop-types/react-is": [ - "react-is@16.13.1", - "", - {}, - "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - ], - - "express-session/debug/ms": [ - "ms@2.0.0", - "", - {}, - "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - ], - - "express/debug/ms": [ - "ms@2.0.0", - "", - {}, - "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - ], - - "filelist/minimatch/brace-expansion": [ - "brace-expansion@2.0.2", - "", - { "dependencies": { "balanced-match": "^1.0.0" } }, - "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==" - ], - - "finalhandler/debug/ms": [ - "ms@2.0.0", - "", - {}, - "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - ], - - "ink/prop-types/react-is": [ - "react-is@16.13.1", - "", - {}, - "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - ], - - "isomorphic-fetch/node-fetch/is-stream": [ - "is-stream@1.1.0", - "", - {}, - "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==" - ], - - "kanel/rimraf/glob": [ - "glob@13.0.6", - "", - { - "dependencies": { - "minimatch": "^10.2.2", - "minipass": "^7.1.3", - "path-scurry": "^2.0.2" - } - }, - "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==" - ], - - "knex/debug/ms": [ - "ms@2.1.2", - "", - {}, - "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - ], - - "log-update/cli-cursor/restore-cursor": [ - "restore-cursor@2.0.0", - "", - { "dependencies": { "onetime": "^2.0.0", "signal-exit": "^3.0.2" } }, - "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==" - ], - - "log-update/wrap-ansi/ansi-styles": [ - "ansi-styles@3.2.1", - "", - { "dependencies": { "color-convert": "^1.9.0" } }, - "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==" - ], - - "log-update/wrap-ansi/string-width": [ - "string-width@3.1.0", - "", - { - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==" - ], - - "mv/rimraf/glob": [ - "glob@6.0.4", - "", - { - "dependencies": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==" - ], - - "nodemon/supports-color/has-flag": [ - "has-flag@3.0.0", - "", - {}, - "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" - ], - - "nyc/find-up/locate-path": [ - "locate-path@5.0.0", - "", - { "dependencies": { "p-locate": "^4.1.0" } }, - "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==" - ], - - "pkg-dir/find-up/locate-path": [ - "locate-path@5.0.0", - "", - { "dependencies": { "p-locate": "^4.1.0" } }, - "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==" - ], - - "react-async-script/prop-types/react-is": [ - "react-is@16.13.1", - "", - {}, - "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - ], - - "react-bootstrap/prop-types/react-is": [ - "react-is@16.13.1", - "", - {}, - "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - ], - - "react-google-recaptcha/prop-types/react-is": [ - "react-is@16.13.1", - "", - {}, - "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - ], - - "react-markdown/prop-types/react-is": [ - "react-is@16.13.1", - "", - {}, - "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - ], - - "react-reconciler/prop-types/react-is": [ - "react-is@16.13.1", - "", - {}, - "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - ], - - "react-router-bootstrap/prop-types/react-is": [ - "react-is@16.13.1", - "", - {}, - "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - ], - - "react-router-dom/prop-types/react-is": [ - "react-is@16.13.1", - "", - {}, - "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - ], - - "react-router/path-to-regexp/isarray": [ - "isarray@0.0.1", - "", - {}, - "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" - ], - - "react-select/prop-types/react-is": [ - "react-is@16.13.1", - "", - {}, - "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - ], - - "react-transition-group/prop-types/react-is": [ - "react-is@16.13.1", - "", - {}, - "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - ], - - "send/debug/ms": [ - "ms@2.0.0", - "", - {}, - "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - ], - - "serve-static/send/debug": [ - "debug@2.6.9", - "", - { "dependencies": { "ms": "2.0.0" } }, - "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==" - ], - - "string-width-cjs/strip-ansi/ansi-regex": [ - "ansi-regex@5.0.1", - "", - {}, - "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - ], - - "string-width/strip-ansi/ansi-regex": [ - "ansi-regex@5.0.1", - "", - {}, - "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - ], - - "test-exclude/glob/foreground-child": [ - "foreground-child@3.3.1", - "", - { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, - "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==" - ], - - "test-exclude/glob/jackspeak": [ - "jackspeak@3.4.3", - "", - { - "dependencies": { "@isaacs/cliui": "^8.0.2" }, - "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } - }, - "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==" - ], - - "test-exclude/glob/minimatch": [ - "minimatch@9.0.9", - "", - { "dependencies": { "brace-expansion": "^2.0.2" } }, - "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==" - ], - - "test-exclude/glob/minipass": [ - "minipass@7.1.3", - "", - {}, - "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==" - ], - - "test-exclude/glob/path-scurry": [ - "path-scurry@1.11.1", - "", - { - "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } - }, - "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==" - ], - - "test-exclude/minimatch/brace-expansion": [ - "brace-expansion@5.0.4", - "", - { "dependencies": { "balanced-match": "^4.0.2" } }, - "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==" - ], - - "typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager": [ - "@typescript-eslint/scope-manager@8.56.1", - "", - { - "dependencies": { - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1" - } - }, - "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==" - ], - - "typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys": [ - "@typescript-eslint/visitor-keys@8.56.1", - "", - { - "dependencies": { - "@typescript-eslint/types": "8.56.1", - "eslint-visitor-keys": "^5.0.0" - } - }, - "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==" - ], - - "typescript-eslint/@typescript-eslint/eslint-plugin/ignore": [ - "ignore@7.0.5", - "", - {}, - "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==" - ], - - "typescript-eslint/@typescript-eslint/parser/@typescript-eslint/scope-manager": [ - "@typescript-eslint/scope-manager@8.56.1", - "", - { - "dependencies": { - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1" - } - }, - "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==" - ], - - "typescript-eslint/@typescript-eslint/parser/@typescript-eslint/types": [ - "@typescript-eslint/types@8.56.1", - "", - {}, - "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==" - ], - - "typescript-eslint/@typescript-eslint/parser/@typescript-eslint/visitor-keys": [ - "@typescript-eslint/visitor-keys@8.56.1", - "", - { - "dependencies": { - "@typescript-eslint/types": "8.56.1", - "eslint-visitor-keys": "^5.0.0" - } - }, - "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==" - ], - - "typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/types": [ - "@typescript-eslint/types@8.56.1", - "", - {}, - "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==" - ], - - "typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys": [ - "@typescript-eslint/visitor-keys@8.56.1", - "", - { - "dependencies": { - "@typescript-eslint/types": "8.56.1", - "eslint-visitor-keys": "^5.0.0" - } - }, - "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==" - ], - - "typescript-eslint/@typescript-eslint/typescript-estree/minimatch": [ - "minimatch@10.2.4", - "", - { "dependencies": { "brace-expansion": "^5.0.2" } }, - "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==" - ], - - "vite-plugin-html/fs-extra/jsonfile": [ - "jsonfile@6.2.0", - "", - { - "dependencies": { "universalify": "^2.0.0" }, - "optionalDependencies": { "graceful-fs": "^4.1.6" } - }, - "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==" - ], - - "vite-plugin-html/fs-extra/universalify": [ - "universalify@2.0.1", - "", - {}, - "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==" - ], - - "wrap-ansi-cjs/strip-ansi/ansi-regex": [ - "ansi-regex@5.0.1", - "", - {}, - "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - ], - - "wrap-ansi/strip-ansi/ansi-regex": [ - "ansi-regex@5.0.1", - "", - {}, - "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - ], - - "yargs/cliui/strip-ansi": [ - "strip-ansi@6.0.1", - "", - { "dependencies": { "ansi-regex": "^5.0.1" } }, - "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==" - ], - - "yargs/find-up/locate-path": [ - "locate-path@5.0.0", - "", - { "dependencies": { "p-locate": "^4.1.0" } }, - "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==" - ], - - "@grpc/proto-loader/yargs/cliui/strip-ansi": [ - "strip-ansi@6.0.1", - "", - { "dependencies": { "ansi-regex": "^5.0.1" } }, - "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==" - ], - - "@grpc/proto-loader/yargs/cliui/wrap-ansi": [ - "wrap-ansi@7.0.0", - "", - { - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==" - ], - - "@istanbuljs/load-nyc-config/find-up/locate-path/p-locate": [ - "p-locate@4.1.0", - "", - { "dependencies": { "p-limit": "^2.2.0" } }, - "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==" - ], - - "@types/minimatch/minimatch/brace-expansion/balanced-match": [ - "balanced-match@4.0.4", - "", - {}, - "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==" - ], - - "@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys/eslint-visitor-keys": [ - "eslint-visitor-keys@5.0.1", - "", - {}, - "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==" - ], - - "@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": [ - "brace-expansion@5.0.4", - "", - { "dependencies": { "balanced-match": "^4.0.2" } }, - "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==" - ], - - "@typescript-eslint/utils/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys/eslint-visitor-keys": [ - "eslint-visitor-keys@5.0.1", - "", - {}, - "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==" - ], - - "@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys/eslint-visitor-keys": [ - "eslint-visitor-keys@5.0.1", - "", - {}, - "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==" - ], - - "@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": [ - "brace-expansion@5.0.4", - "", - { "dependencies": { "balanced-match": "^4.0.2" } }, - "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==" - ], - - "@vitest/mocker/vite/esbuild/@esbuild/android-arm": [ - "@esbuild/android-arm@0.15.18", - "", - { "os": "android", "cpu": "arm" }, - "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==" - ], - - "@vitest/mocker/vite/esbuild/@esbuild/linux-loong64": [ - "@esbuild/linux-loong64@0.15.18", - "", - { "os": "linux", "cpu": "none" }, - "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==" - ], - - "kanel/rimraf/glob/minimatch": [ - "minimatch@10.2.4", - "", - { "dependencies": { "brace-expansion": "^5.0.2" } }, - "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==" - ], - - "kanel/rimraf/glob/minipass": [ - "minipass@7.1.3", - "", - {}, - "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==" - ], - - "log-update/cli-cursor/restore-cursor/onetime": [ - "onetime@2.0.1", - "", - { "dependencies": { "mimic-fn": "^1.0.0" } }, - "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==" - ], - - "log-update/wrap-ansi/ansi-styles/color-convert": [ - "color-convert@1.9.3", - "", - { "dependencies": { "color-name": "1.1.3" } }, - "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==" - ], - - "log-update/wrap-ansi/string-width/emoji-regex": [ - "emoji-regex@7.0.3", - "", - {}, - "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - ], - - "log-update/wrap-ansi/string-width/is-fullwidth-code-point": [ - "is-fullwidth-code-point@2.0.0", - "", - {}, - "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" - ], - - "nyc/find-up/locate-path/p-locate": [ - "p-locate@4.1.0", - "", - { "dependencies": { "p-limit": "^2.2.0" } }, - "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==" - ], - - "pkg-dir/find-up/locate-path/p-locate": [ - "p-locate@4.1.0", - "", - { "dependencies": { "p-limit": "^2.2.0" } }, - "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==" - ], - - "serve-static/send/debug/ms": [ - "ms@2.0.0", - "", - {}, - "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - ], - - "test-exclude/glob/foreground-child/signal-exit": [ - "signal-exit@4.1.0", - "", - {}, - "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==" - ], - - "test-exclude/glob/minimatch/brace-expansion": [ - "brace-expansion@2.0.2", - "", - { "dependencies": { "balanced-match": "^1.0.0" } }, - "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==" - ], - - "test-exclude/glob/path-scurry/lru-cache": [ - "lru-cache@10.4.3", - "", - {}, - "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" - ], - - "test-exclude/minimatch/brace-expansion/balanced-match": [ - "balanced-match@4.0.4", - "", - {}, - "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==" - ], - - "typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager/@typescript-eslint/types": [ - "@typescript-eslint/types@8.56.1", - "", - {}, - "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==" - ], - - "typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys/@typescript-eslint/types": [ - "@typescript-eslint/types@8.56.1", - "", - {}, - "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==" - ], - - "typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys/eslint-visitor-keys": [ - "eslint-visitor-keys@5.0.1", - "", - {}, - "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==" - ], - - "typescript-eslint/@typescript-eslint/parser/@typescript-eslint/visitor-keys/eslint-visitor-keys": [ - "eslint-visitor-keys@5.0.1", - "", - {}, - "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==" - ], - - "typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys/eslint-visitor-keys": [ - "eslint-visitor-keys@5.0.1", - "", - {}, - "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==" - ], - - "typescript-eslint/@typescript-eslint/typescript-estree/minimatch/brace-expansion": [ - "brace-expansion@5.0.4", - "", - { "dependencies": { "balanced-match": "^4.0.2" } }, - "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==" - ], - - "yargs/cliui/strip-ansi/ansi-regex": [ - "ansi-regex@5.0.1", - "", - {}, - "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - ], - - "yargs/find-up/locate-path/p-locate": [ - "p-locate@4.1.0", - "", - { "dependencies": { "p-limit": "^2.2.0" } }, - "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==" - ], - - "@grpc/proto-loader/yargs/cliui/strip-ansi/ansi-regex": [ - "ansi-regex@5.0.1", - "", - {}, - "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - ], - - "@istanbuljs/load-nyc-config/find-up/locate-path/p-locate/p-limit": [ - "p-limit@2.3.0", - "", - { "dependencies": { "p-try": "^2.0.0" } }, - "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==" - ], - - "@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": [ - "balanced-match@4.0.4", - "", - {}, - "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==" - ], - - "@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": [ - "balanced-match@4.0.4", - "", - {}, - "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==" - ], - - "kanel/rimraf/glob/minimatch/brace-expansion": [ - "brace-expansion@5.0.4", - "", - { "dependencies": { "balanced-match": "^4.0.2" } }, - "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==" - ], - - "log-update/cli-cursor/restore-cursor/onetime/mimic-fn": [ - "mimic-fn@1.2.0", - "", - {}, - "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" - ], - - "log-update/wrap-ansi/ansi-styles/color-convert/color-name": [ - "color-name@1.1.3", - "", - {}, - "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - ], - - "nyc/find-up/locate-path/p-locate/p-limit": [ - "p-limit@2.3.0", - "", - { "dependencies": { "p-try": "^2.0.0" } }, - "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==" - ], - - "pkg-dir/find-up/locate-path/p-locate/p-limit": [ - "p-limit@2.3.0", - "", - { "dependencies": { "p-try": "^2.0.0" } }, - "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==" - ], - - "typescript-eslint/@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": [ - "balanced-match@4.0.4", - "", - {}, - "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==" - ], - - "yargs/find-up/locate-path/p-locate/p-limit": [ - "p-limit@2.3.0", - "", - { "dependencies": { "p-try": "^2.0.0" } }, - "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==" - ], - - "kanel/rimraf/glob/minimatch/brace-expansion/balanced-match": [ - "balanced-match@4.0.4", - "", - {}, - "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==" - ] - } + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "tachi", + "devDependencies": { + "@biomejs/biome": "^2.0.6", + "@types/node": "20.19.37", + "@types/tap": "15.0.3", + "eslint": "^9.20.1", + "kanel": "^3.16.1", + "kanel-kysely": "^0.8.0", + "tap": "workspace:*", + "ts-node": "10.9.1", + "tsc-alias": "1.7.1", + "typescript": "5.9.3", + }, + "peerDependencies": { + "@types/bson": "1.0.11", + "@types/mongodb": "3.6.20", + "@types/node": "20.19.37", + "mongodb": "3.6.3", + }, + }, + "typescript-vendor/tap": { + "name": "tap", + "version": "15.0.9", + "bin": { + "tap": "bin/run.js", + }, + "dependencies": { + "chokidar": "catalog:", + "coveralls": "catalog:", + "findit": "catalog:", + "foreground-child": "catalog:", + "fs-exists-cached": "catalog:", + "glob": "catalog:", + "import-jsx": "catalog:", + "ink": "catalog:", + "isexe": "catalog:", + "istanbul-lib-processinfo": "catalog:", + "jackspeak": "catalog:", + "libtap": "catalog:", + "minipass": "catalog:", + "mkdirp": "catalog:", + "nyc": "catalog:", + "opener": "catalog:", + "rimraf": "catalog:", + "signal-exit": "catalog:", + "source-map-support": "catalog:", + "tap-mocha-reporter": "catalog:", + "tap-parser": "catalog:", + "tap-yaml": "catalog:", + "tcompare": "catalog:", + "treport": "catalog:", + "which": "catalog:", + }, + "devDependencies": { + "flow-remove-types": "catalog:", + "node-preload": "catalog:", + "process-on-spawn": "catalog:", + "ts-node": "catalog:", + "typescript": "catalog:", + }, + "peerDependencies": { + "flow-remove-types": ">=2.112.0", + "ts-node": ">=8.5.2", + "typescript": ">=3.7.2", + }, + "optionalPeers": [ + "flow-remove-types", + "ts-node", + "typescript", + ], + }, + "typescript/api-parity": { + "name": "api-parity", + "version": "1.0.0", + "devDependencies": { + "@types/node": "catalog:", + "@vitest/coverage-v8": "catalog:", + "vitest": "catalog:", + }, + }, + "typescript/bliss": { + "name": "bliss", + "version": "0.0.1", + "dependencies": { + "pino": "catalog:", + "pino-pretty": "catalog:", + "zod": "^4.3.6", + }, + "devDependencies": { + "@typescript/native-preview": "catalog:", + "eslint-config-tachi": "workspace:*", + "typescript": "catalog:", + }, + }, + "typescript/bot": { + "name": "tachi-bot", + "version": "2.2.0", + "dependencies": { + "@discordjs/builders": "catalog:", + "@discordjs/rest": "catalog:", + "@types/bson": "catalog:", + "@types/humanize-duration": "catalog:", + "@valuabletouch/winston-seq": "catalog:", + "bliss": "workspace:*", + "deepmerge": "catalog:", + "discord-api-types": "catalog:", + "discord.js": "catalog:", + "dotenv": "catalog:", + "express": "catalog:", + "humanize-duration": "catalog:", + "json5": "catalog:", + "kysely": "catalog:", + "lodash": "catalog:", + "luxon": "catalog:", + "node-fetch": "catalog:", + "pg": "catalog:", + "prudence": "catalog:", + "seq-logging": "catalog:", + "tachi-common": "workspace:*", + "tachi-db": "workspace:*", + "ts-node": "catalog:", + "tsconfig-paths": "catalog:", + "typescript": "catalog:", + "winston": "catalog:", + }, + "devDependencies": { + "@types/express": "catalog:", + "@types/json5": "catalog:", + "@types/lodash": "catalog:", + "@types/luxon": "catalog:", + "@types/node": "catalog:", + "@types/node-fetch": "catalog:", + "@types/pg": "catalog:", + "@typescript/native-preview": "catalog:", + "@vitest/coverage-v8": "catalog:", + "eslint-config-tachi": "workspace:*", + "vitest": "catalog:", + }, + }, + "typescript/client": { + "name": "tachi-client", + "version": "0.1.0-see-project-root", + "dependencies": { + "@fortawesome/fontawesome-free": "catalog:", + "@fullcalendar/core": "catalog:", + "@fullcalendar/daygrid": "catalog:", + "@fullcalendar/react": "catalog:", + "@nivo/bar": "catalog:", + "@nivo/colors": "catalog:", + "@nivo/core": "catalog:", + "@nivo/line": "catalog:", + "@nivo/tooltip": "catalog:", + "@types/lodash": "catalog:", + "@types/natural-compare": "catalog:", + "@types/react-google-recaptcha": "catalog:", + "csstype": "catalog:", + "d3-scale": "catalog:", + "deepmerge": "catalog:", + "dotenv": "catalog:", + "fast-json-stable-hash": "catalog:", + "formik": "catalog:", + "fs-extra": "catalog:", + "hash.js": "catalog:", + "humanize-duration": "catalog:", + "json-2-csv": "catalog:", + "lodash": "catalog:", + "luxon": "catalog:", + "nanoid": "catalog:", + "natural-compare": "catalog:", + "pretty-bytes": "catalog:", + "prop-types": "catalog:", + "prudence": "catalog:", + "react": "catalog:", + "react-async": "catalog:", + "react-bootstrap": "catalog:", + "react-dom": "catalog:", + "react-google-recaptcha": "catalog:", + "react-hot-toast": "catalog:", + "react-markdown": "catalog:", + "react-query": "catalog:", + "react-router-bootstrap": "catalog:", + "react-router-dom": "catalog:", + "react-select": "catalog:", + "rg-stats": "catalog:", + "sync-fetch": "catalog:", + "tachi-common": "workspace:*", + "vite-plugin-html": "catalog:", + }, + "devDependencies": { + "@types/history": "catalog:", + "@types/humanize-duration": "catalog:", + "@types/luxon": "catalog:", + "@types/react": "catalog:", + "@types/react-dom": "catalog:", + "@types/react-router-bootstrap": "catalog:", + "@types/react-router-dom": "catalog:", + "@typescript/native-preview": "catalog:", + "@vitejs/plugin-react": "catalog:", + "bootstrap-scss": "catalog:", + "eslint-config-tachi": "workspace:*", + "sass": "catalog:", + "typescript": "catalog:", + "vite": "catalog:", + }, + }, + "typescript/common": { + "name": "tachi-common", + "version": "2.4.0-dev", + "dependencies": { + "@types/express-serve-static-core": "catalog:", + "@types/mongodb": "catalog:", + "deepmerge": "catalog:", + "prudence": "catalog:", + "zod": "catalog:", + }, + "devDependencies": { + "@types/tap": "catalog:", + "@typescript/native-preview": "catalog:", + "eslint-config-tachi": "workspace:*", + "tap": "workspace:*", + "typescript": "catalog:", + }, + }, + "typescript/db": { + "name": "tachi-db", + "version": "0.1.0-see-project-root", + "dependencies": { + "kysely": "catalog:", + "pg": "catalog:", + }, + "devDependencies": { + "@types/express": "catalog:", + "@types/node": "catalog:", + "@types/node-fetch": "catalog:", + "@typescript/native-preview": "catalog:", + "@vitest/coverage-v8": "catalog:", + "eslint-config-tachi": "workspace:*", + "typescript": "catalog:", + "vitest": "catalog:", + }, + }, + "typescript/db-cli": { + "name": "tachi-db-migration-engine-cli", + "version": "1.0.0", + "bin": { + "tachi-migrate": "./src/index.ts", + }, + "dependencies": { + "commander": "catalog:", + "pg": "catalog:", + "tachi-db-migration-engine": "workspace:*", + }, + "devDependencies": { + "@types/node": "catalog:", + "@types/pg": "catalog:", + "@typescript/native-preview": "catalog:", + "eslint-config-tachi": "workspace:*", + "typescript": "catalog:", + }, + }, + "typescript/db-migration-engine": { + "name": "tachi-db-migration-engine", + "version": "1.0.0", + "dependencies": { + "kysely": "catalog:", + "pg": "catalog:", + }, + "devDependencies": { + "@types/node": "catalog:", + "@types/pg": "catalog:", + "@typescript/native-preview": "catalog:", + "eslint-config-tachi": "workspace:*", + "ts-node": "catalog:", + "typescript": "catalog:", + }, + }, + "typescript/docs-autogen-scripts": { + "name": "tachi-autogen-docs", + "version": "1.0.0", + "dependencies": { + "commander": "catalog:", + "tachi-common": "workspace:*", + }, + "devDependencies": { + "@typescript/native-preview": "catalog:", + "eslint-config-tachi": "workspace:*", + }, + }, + "typescript/eslint-config": { + "name": "eslint-config-tachi", + "version": "1.0.0", + "dependencies": { + "@eslint/js": "catalog:", + "@typescript-eslint/eslint-plugin": "catalog:", + "@typescript-eslint/parser": "catalog:", + "@typescript-eslint/utils": "catalog:", + "eslint-config-prettier": "catalog:", + "eslint-import-resolver-typescript": "catalog:", + "eslint-plugin-import": "catalog:", + "eslint-plugin-jsx-a11y": "catalog:", + "eslint-plugin-perfectionist": "catalog:", + "eslint-plugin-react": "catalog:", + "eslint-plugin-react-hooks": "catalog:", + "eslint-plugin-react-refresh": "catalog:", + "globals": "catalog:", + "typescript-eslint": "catalog:", + }, + "devDependencies": { + "@types/eslint__js": "catalog:", + }, + "peerDependencies": { + "eslint": "^9.20.1", + "prettier": "^3.4.2", + }, + }, + "typescript/github-bot": { + "name": "tachi-github-bot", + "version": "0.1.0-see-project-root", + "dependencies": { + "@octokit/app": "catalog:", + "@octokit/webhooks-types": "catalog:", + "dotenv": "catalog:", + "express": "catalog:", + "node-fetch": "catalog:", + "prudence": "catalog:", + }, + "devDependencies": { + "@types/express": "catalog:", + "@types/node": "catalog:", + "@types/node-fetch": "catalog:", + "@typescript/native-preview": "catalog:", + "eslint-config-tachi": "workspace:*", + "typescript": "catalog:", + }, + }, + "typescript/seeds-scripts": { + "name": "tachi-seeds-scripts", + "version": "0.1.0-see-project-root", + "dependencies": { + "@types/lodash.get": "catalog:", + "@types/node": "catalog:", + "better-sqlite3": "catalog:", + "binary-parser": "catalog:", + "bms-table-loader": "catalog:", + "chalk": "catalog:", + "cheerio": "catalog:", + "commander": "catalog:", + "csv-parse": "catalog:", + "deepmerge": "catalog:", + "encoding-japanese": "catalog:", + "fast-json-stable-hash": "catalog:", + "fast-xml-parser": "catalog:", + "glob": "catalog:", + "html-entities": "catalog:", + "iconv-lite": "catalog:", + "lodash.get": "catalog:", + "monk": "catalog:", + "node-fetch": "catalog:", + "prudence": "catalog:", + "tachi-common": "workspace:*", + "zod": "catalog:", + }, + "devDependencies": { + "@typescript/native-preview": "catalog:", + "eslint-config-tachi": "workspace:*", + "tsconfig-paths": "catalog:", + }, + }, + "typescript/server": { + "name": "tachi-server", + "version": "2.5.1", + "dependencies": { + "@aws-sdk/client-s3": "catalog:", + "@aws-sdk/signature-v4-crt": "catalog:", + "@types/bcryptjs": "catalog:", + "@types/bson": "catalog:", + "@types/bunyan": "catalog:", + "@types/connect-redis": "catalog:", + "@types/express": "catalog:", + "@types/express-rate-limit": "catalog:", + "@types/express-serve-static-core": "catalog:", + "@types/express-session": "catalog:", + "@types/glob": "catalog:", + "@types/mkdirp": "catalog:", + "@types/mongodb": "catalog:", + "@types/multer": "catalog:", + "@types/node": "catalog:", + "@types/node-fetch": "catalog:", + "@types/nodemailer": "catalog:", + "@types/rate-limit-redis": "catalog:", + "@types/redis": "catalog:", + "@types/rimraf": "catalog:", + "@types/safe-json-stringify": "catalog:", + "@types/semver": "catalog:", + "@valuabletouch/winston-seq": "catalog:", + "bcryptjs": "catalog:", + "bliss": "workspace:*", + "bms-table-loader": "catalog:", + "bullmq": "catalog:", + "bunyan": "catalog:", + "commander": "catalog:", + "connect-redis": "catalog:", + "csv-parse": "catalog:", + "deepmerge": "catalog:", + "express": "catalog:", + "express-async-errors": "catalog:", + "express-prom-bundle": "catalog:", + "express-rate-limit": "catalog:", + "express-session": "catalog:", + "fast-json-stable-hash": "catalog:", + "fast-xml-parser": "catalog:", + "helmet": "catalog:", + "html-entities": "catalog:", + "json5": "catalog:", + "kysely": "catalog:", + "mkdirp": "catalog:", + "mongodb": "catalog:", + "monk": "catalog:", + "multer": "catalog:", + "node-cache": "catalog:", + "node-fetch": "catalog:", + "node-html-parser": "catalog:", + "nodemailer": "catalog:", + "pg": "catalog:", + "prudence": "catalog:", + "rate-limit-redis": "catalog:", + "redis": "catalog:", + "rg-stats": "catalog:", + "rimraf": "catalog:", + "safe-json-stringify": "catalog:", + "semver": "catalog:", + "tachi-common": "workspace:*", + "tachi-db": "workspace:*", + "tachi-db-migration-engine": "workspace:*", + "ts-node": "catalog:", + "typescript": "catalog:", + "uuidv7": "catalog:", + "winston": "catalog:", + "winston-loki": "catalog:", + "winston-transport": "catalog:", + "zod": "catalog:", + }, + "devDependencies": { + "@grpc/grpc-js": "catalog:", + "@types/google-protobuf": "catalog:", + "@types/pg": "catalog:", + "@types/supertest": "catalog:", + "@types/tap": "catalog:", + "@typescript/native-preview": "catalog:", + "eslint-config-tachi": "workspace:*", + "glob": "catalog:", + "google-protobuf": "catalog:", + "grpc-tools": "catalog:", + "node-mocks-http": "catalog:", + "nodemon": "catalog:", + "supertest": "catalog:", + "tap": "workspace:*", + "ts-protoc-gen": "catalog:", + "tsconfig-paths": "catalog:", + }, + }, + "typescript/sieglinde": { + "name": "tachi-sieglinde", + "version": "0.1.0-see-project-root", + "dependencies": { + "@types/node-fetch": "catalog:", + "bms-table-loader": "catalog:", + "commander": "catalog:", + "fast-xml-parser": "catalog:", + "node-fetch": "catalog:", + "tachi-common": "workspace:*", + "winston": "catalog:", + }, + "devDependencies": { + "@typescript/native-preview": "catalog:", + "eslint-config-tachi": "workspace:*", + }, + }, + }, + "patchedDependencies": { + "monk@7.3.4": "patches/monk@7.3.4.patch", + "@types/mongodb@3.6.20": "patches/@types__mongodb@3.6.20.patch", + }, + "overrides": { + "@types/bson": "1.0.11", + "@types/express": "4.17.13", + "@types/express-serve-static-core": "4.17.29", + "@types/mongodb": "3.6.20", + "@types/node": "20.19.37", + "mongodb": "3.6.3", + "ts-node": "10.9.1", + "typescript": "5.9.3", + }, + "catalog": { + "@aws-sdk/client-s3": "3.49.0", + "@aws-sdk/signature-v4-crt": "3.49.0", + "@babel/core": "7.1.0", + "@discordjs/builders": "0.5.0", + "@discordjs/rest": "0.1.0-canary.0", + "@eslint/js": "^9.20.0", + "@fortawesome/fontawesome-free": "5.13.0", + "@fullcalendar/core": "^6.0.0", + "@fullcalendar/daygrid": "^6.0.0", + "@fullcalendar/react": "^6.0.0", + "@grpc/grpc-js": "^1.10.6", + "@nivo/bar": "0.79.1", + "@nivo/colors": "0.79.1", + "@nivo/core": "0.79.0", + "@nivo/line": "0.79.1", + "@nivo/tooltip": "0.79.0", + "@octokit/app": "15.1.0", + "@octokit/webhooks-types": "7.5.1", + "@types/bcryptjs": "^2.4.2", + "@types/bson": "1.0.11", + "@types/bunyan": "^1.8.8", + "@types/connect-redis": "0.0.18", + "@types/eslint__js": "8.42.3", + "@types/express": "4.17.13", + "@types/express-rate-limit": "5.1.3", + "@types/express-serve-static-core": "4.17.29", + "@types/express-session": "1.17.4", + "@types/glob": "^7.2.0", + "@types/google-protobuf": "^3.15.12", + "@types/history": "4.7.11", + "@types/humanize-duration": "^3.27.1", + "@types/jest": "^26.0.23", + "@types/json5": "2.2.0", + "@types/lodash": "4.14.172", + "@types/lodash.get": "^4.4.7", + "@types/luxon": "^2.3.1", + "@types/mkdirp": "1.0.2", + "@types/mongodb": "3.6.20", + "@types/multer": "1.4.7", + "@types/natural-compare": "^1.4.1", + "@types/node": "*", + "@types/node-fetch": "2.5.12", + "@types/nodemailer": "^6.4.4", + "@types/pg": "^8.11.11", + "@types/rate-limit-redis": "1.7.4", + "@types/react": "17.0.13", + "@types/react-dom": "17.0.8", + "@types/react-google-recaptcha": "2.1.2", + "@types/react-router-bootstrap": "0.26.1", + "@types/react-router-dom": "5.1.7", + "@types/redis": "2.8.32", + "@types/rimraf": "3.0.2", + "@types/safe-json-stringify": "1.1.2", + "@types/semver": "^7.3.9", + "@types/supertest": "2.0.11", + "@types/tap": "15.0.5", + "@typescript-eslint/eslint-plugin": "^4.27.0", + "@typescript-eslint/parser": "^4.27.0", + "@typescript-eslint/utils": "^8.24.1", + "@typescript/native-preview": "7.0.0-dev.20260309.1", + "@valuabletouch/winston-seq": "1.3.0", + "@vitejs/plugin-react": "^6.0.1", + "@vitest/coverage-istanbul": "~3.2.0", + "@vitest/coverage-v8": "~3.2.0", + "bcryptjs": "2.4.3", + "better-sqlite3": "9.4.5", + "binary-parser": "^2.3.0", + "bms-table-loader": "2.0.0", + "bootstrap-scss": "^5.3.0", + "bullmq": "1.68.4", + "bunyan": "1.8.15", + "chalk": "4", + "cheerio": "^1.0.0-rc.12", + "chokidar": "^3.3.0", + "commander": "^8.2.0", + "connect-redis": "6.1.1", + "coveralls": "^3.0.11", + "csstype": "3.1.1", + "csv-parse": "^5.0.3", + "d3-scale": "3.3.0", + "deepmerge": "^4.2.2", + "discord-api-types": "0.22.0", + "discord.js": "13.6.0", + "dotenv": "16.0.0", + "encoding-japanese": "^1.0.30", + "eslint": "^7.29.0", + "eslint-config-prettier": "^9.1.0", + "eslint-config-standard": "^16.0.3", + "eslint-import-resolver-typescript": "^3.7.0", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jest": "^24.3.6", + "eslint-plugin-jsx-a11y": "^6.10.2", + "eslint-plugin-perfectionist": "^3.9.1", + "eslint-plugin-react": "^7.37.4", + "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-react-refresh": "^0.4.14", + "express": "4.20.0", + "express-async-errors": "3.1.1", + "express-prom-bundle": "^7.0.0", + "express-rate-limit": "5.5.1", + "express-session": "1.17.2", + "fast-json-stable-hash": "^1.0.3", + "fast-xml-parser": "^4.2.5", + "findit": "^2.0.0", + "flow-remove-types": "^2.112.0", + "foreground-child": "^2.0.0", + "formik": "2.2.9", + "fs-exists-cached": "^1.0.0", + "fs-extra": "7.0.1", + "glob": "^7.1.6", + "globals": "^15.15.0", + "google-protobuf": "^3.21.2", + "grpc-tools": "^1.12.4", + "hash.js": "1.1.7", + "helmet": "5.0.2", + "html-entities": "^2.3.2", + "humanize-duration": "^3.27.1", + "iconv-lite": "^0.6.3", + "import-jsx": "^4.0.0", + "ink": "^2.7.1", + "isexe": "^2.0.0", + "istanbul-lib-processinfo": "^2.0.2", + "jackspeak": "^1.4.0", + "jest": "^27.0.4", + "json-2-csv": "3.14.4", + "json5": "2.2.0", + "kysely": "^0.27.5", + "libtap": "^1.1.1", + "lodash": "4.17.21", + "lodash.get": "^4.4.2", + "luxon": "^2.3.1", + "minipass": "^3.1.1", + "mkdirp": "^1.0.4", + "mongodb": "3.6.3", + "monk": "^7.3.4", + "multer": "2.0.1", + "nanoid": "3.1.23", + "natural-compare": "^1.4.0", + "node-cache": "5.1.2", + "node-fetch": "2.6.7", + "node-html-parser": "^5.3.3", + "node-mocks-http": "1.11.0", + "node-preload": "^0.2.1", + "node-sass": "9.0.0", + "nodemailer": "7.0.11", + "nodemon": "^2.0.20", + "nyc": "^15.1.0", + "opener": "^1.5.1", + "pg": "^8.13.3", + "pino": "^10.3.1", + "pino-pretty": "^13.1.3", + "prettier": "3.2.5", + "pretty-bytes": "5.6.0", + "process-on-spawn": "^1.0.0", + "prop-types": "15.6.0", + "prudence": "0.10.0", + "rate-limit-redis": "2.1.0", + "react": "17.0.2", + "react-async": "10.0.1", + "react-bootstrap": "2.9.0-beta.0", + "react-dom": "17.0.2", + "react-google-recaptcha": "2.1.0", + "react-hot-toast": "2.0.0", + "react-markdown": "7.0.1", + "react-query": "3.18.1", + "react-router-bootstrap": "^0.25.0", + "react-router-dom": "5.1.2", + "react-select": "^5.6.1", + "redis": "3.1.2", + "rg-stats": "1.2.1", + "rimraf": "^3.0.0", + "safe-json-stringify": "1.2.0", + "sass": "1.64.1", + "semver": "^7.3.7", + "seq-logging": "1.1.1", + "signal-exit": "^3.0.0", + "source-map-support": "^0.5.16", + "standard": "^16.0.3", + "supertest": "6.2.2", + "sync-fetch": "^0.3.1", + "tap-mocha-reporter": "^5.0.0", + "tap-parser": "^10.0.1", + "tap-yaml": "^1.0.0", + "tcompare": "^5.0.6", + "treport": "^2.0.2", + "ts-jest": "^27.0.3", + "ts-node": "^8.5.2", + "ts-protoc-gen": "^0.15.0", + "tsconfig-paths": "3.12.0", + "tsd": "^0.17.0", + "typescript": "^4.3.4", + "typescript-eslint": "^8.24.1", + "uuidv7": "^1.1.0", + "vite": "^8.0.0", + "vite-plugin-html": "^3.2.0", + "vitest": "~3.2.0", + "which": "^2.0.2", + "winston": "3.5.1", + "winston-loki": "^6.1.0", + "winston-transport": "4.5.0", + "zod": "^4.3.6", + }, + "packages": { + "@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="], + + "@aws-crypto/crc32": ["@aws-crypto/crc32@2.0.0", "", { "dependencies": { "@aws-crypto/util": "^2.0.0", "@aws-sdk/types": "^3.1.0", "tslib": "^1.11.1" } }, "sha512-TvE1r2CUueyXOuHdEigYjIZVesInd9KN+K/TFFNfkkxRThiNxO6i4ZqqAVMoEjAamZZ1AA8WXJkjCz7YShHPQA=="], + + "@aws-crypto/ie11-detection": ["@aws-crypto/ie11-detection@2.0.2", "", { "dependencies": { "tslib": "^1.11.1" } }, "sha512-5XDMQY98gMAf/WRTic5G++jfmS/VLM0rwpiOpaainKi4L0nqWMSB1SzsrEG5rjFZGYN6ZAefO+/Yta2dFM0kMw=="], + + "@aws-crypto/sha256-browser": ["@aws-crypto/sha256-browser@2.0.0", "", { "dependencies": { "@aws-crypto/ie11-detection": "^2.0.0", "@aws-crypto/sha256-js": "^2.0.0", "@aws-crypto/supports-web-crypto": "^2.0.0", "@aws-crypto/util": "^2.0.0", "@aws-sdk/types": "^3.1.0", "@aws-sdk/util-locate-window": "^3.0.0", "@aws-sdk/util-utf8-browser": "^3.0.0", "tslib": "^1.11.1" } }, "sha512-rYXOQ8BFOaqMEHJrLHul/25ckWH6GTJtdLSajhlqGMx0PmSueAuvboCuZCTqEKlxR8CQOwRarxYMZZSYlhRA1A=="], + + "@aws-crypto/sha256-js": ["@aws-crypto/sha256-js@2.0.0", "", { "dependencies": { "@aws-crypto/util": "^2.0.0", "@aws-sdk/types": "^3.1.0", "tslib": "^1.11.1" } }, "sha512-VZY+mCY4Nmrs5WGfitmNqXzaE873fcIZDu54cbaDaaamsaTOP1DBImV9F4pICc3EHjQXujyE8jig+PFCaew9ig=="], + + "@aws-crypto/supports-web-crypto": ["@aws-crypto/supports-web-crypto@2.0.2", "", { "dependencies": { "tslib": "^1.11.1" } }, "sha512-6mbSsLHwZ99CTOOswvCRP3C+VCWnzBf+1SnbWxzzJ9lR0mA0JnY2JEAhp8rqmTE0GPFy88rrM27ffgp62oErMQ=="], + + "@aws-crypto/util": ["@aws-crypto/util@2.0.2", "", { "dependencies": { "@aws-sdk/types": "^3.110.0", "@aws-sdk/util-utf8-browser": "^3.0.0", "tslib": "^1.11.1" } }, "sha512-Lgu5v/0e/BcrZ5m/IWqzPUf3UYFTy/PpeED+uc9SWUR1iZQL8XXbGQg10UfllwwBryO3hFF5dizK+78aoXC1eA=="], + + "@aws-sdk/abort-controller": ["@aws-sdk/abort-controller@3.49.0", "", { "dependencies": { "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-1qLlgOgg3yrtm+AJEP7yoIk90o6ns3Dia8S9DRjj29jY40446etH3v/tIbHPE+em69HLXl1K6e5KD6t7EDxnlg=="], + + "@aws-sdk/chunked-blob-reader": ["@aws-sdk/chunked-blob-reader@3.49.0", "", { "dependencies": { "tslib": "^2.3.0" } }, "sha512-UI1rK4aBgwsQ6dOQs5Im1cNSb3c/RH1wKjD49zcwWyxe8e96C5G2LcshhVH3onWY5NgqQgs/ffEsXziGcNXRIg=="], + + "@aws-sdk/chunked-blob-reader-native": ["@aws-sdk/chunked-blob-reader-native@3.49.0", "", { "dependencies": { "@aws-sdk/util-base64-browser": "3.49.0", "tslib": "^2.3.0" } }, "sha512-ppjmDWyufMB41Hmq5Gixd2+/c4kk2IPKKWT9zI9spKOYbbL/vY3FmRq4beQ6n5kWOzDPxKZ6wv04yrMS9yBy1A=="], + + "@aws-sdk/client-s3": ["@aws-sdk/client-s3@3.49.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "2.0.0", "@aws-crypto/sha256-js": "2.0.0", "@aws-sdk/client-sts": "3.49.0", "@aws-sdk/config-resolver": "3.49.0", "@aws-sdk/credential-provider-node": "3.49.0", "@aws-sdk/eventstream-serde-browser": "3.49.0", "@aws-sdk/eventstream-serde-config-resolver": "3.49.0", "@aws-sdk/eventstream-serde-node": "3.49.0", "@aws-sdk/fetch-http-handler": "3.49.0", "@aws-sdk/hash-blob-browser": "3.49.0", "@aws-sdk/hash-node": "3.49.0", "@aws-sdk/hash-stream-node": "3.49.0", "@aws-sdk/invalid-dependency": "3.49.0", "@aws-sdk/md5-js": "3.49.0", "@aws-sdk/middleware-apply-body-checksum": "3.49.0", "@aws-sdk/middleware-bucket-endpoint": "3.49.0", "@aws-sdk/middleware-content-length": "3.49.0", "@aws-sdk/middleware-expect-continue": "3.49.0", "@aws-sdk/middleware-host-header": "3.49.0", "@aws-sdk/middleware-location-constraint": "3.49.0", "@aws-sdk/middleware-logger": "3.49.0", "@aws-sdk/middleware-retry": "3.49.0", "@aws-sdk/middleware-sdk-s3": "3.49.0", "@aws-sdk/middleware-serde": "3.49.0", "@aws-sdk/middleware-signing": "3.49.0", "@aws-sdk/middleware-ssec": "3.49.0", "@aws-sdk/middleware-stack": "3.49.0", "@aws-sdk/middleware-user-agent": "3.49.0", "@aws-sdk/node-config-provider": "3.49.0", "@aws-sdk/node-http-handler": "3.49.0", "@aws-sdk/protocol-http": "3.49.0", "@aws-sdk/smithy-client": "3.49.0", "@aws-sdk/types": "3.49.0", "@aws-sdk/url-parser": "3.49.0", "@aws-sdk/util-base64-browser": "3.49.0", "@aws-sdk/util-base64-node": "3.49.0", "@aws-sdk/util-body-length-browser": "3.49.0", "@aws-sdk/util-body-length-node": "3.49.0", "@aws-sdk/util-defaults-mode-browser": "3.49.0", "@aws-sdk/util-defaults-mode-node": "3.49.0", "@aws-sdk/util-user-agent-browser": "3.49.0", "@aws-sdk/util-user-agent-node": "3.49.0", "@aws-sdk/util-utf8-browser": "3.49.0", "@aws-sdk/util-utf8-node": "3.49.0", "@aws-sdk/util-waiter": "3.49.0", "@aws-sdk/xml-builder": "3.49.0", "entities": "2.2.0", "fast-xml-parser": "3.19.0", "tslib": "^2.3.0" } }, "sha512-LidddhZFxYb/jlEtHnbBpqVZmjgZNKY/jaZy3jRNcVhw8L0m1IYVigqgw5E6ta9/dma5EwLOA8Z21O/rCuDapw=="], + + "@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.49.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "2.0.0", "@aws-crypto/sha256-js": "2.0.0", "@aws-sdk/config-resolver": "3.49.0", "@aws-sdk/fetch-http-handler": "3.49.0", "@aws-sdk/hash-node": "3.49.0", "@aws-sdk/invalid-dependency": "3.49.0", "@aws-sdk/middleware-content-length": "3.49.0", "@aws-sdk/middleware-host-header": "3.49.0", "@aws-sdk/middleware-logger": "3.49.0", "@aws-sdk/middleware-retry": "3.49.0", "@aws-sdk/middleware-serde": "3.49.0", "@aws-sdk/middleware-stack": "3.49.0", "@aws-sdk/middleware-user-agent": "3.49.0", "@aws-sdk/node-config-provider": "3.49.0", "@aws-sdk/node-http-handler": "3.49.0", "@aws-sdk/protocol-http": "3.49.0", "@aws-sdk/smithy-client": "3.49.0", "@aws-sdk/types": "3.49.0", "@aws-sdk/url-parser": "3.49.0", "@aws-sdk/util-base64-browser": "3.49.0", "@aws-sdk/util-base64-node": "3.49.0", "@aws-sdk/util-body-length-browser": "3.49.0", "@aws-sdk/util-body-length-node": "3.49.0", "@aws-sdk/util-defaults-mode-browser": "3.49.0", "@aws-sdk/util-defaults-mode-node": "3.49.0", "@aws-sdk/util-user-agent-browser": "3.49.0", "@aws-sdk/util-user-agent-node": "3.49.0", "@aws-sdk/util-utf8-browser": "3.49.0", "@aws-sdk/util-utf8-node": "3.49.0", "tslib": "^2.3.0" } }, "sha512-rY8uZo4DeNwwKf+Sx0TX/5ysXJKf+0SQSCTWD9S4a0AjtiaLc6hKCX+sJY43VDHvNYieKtXLDYHBdhhqZKwG+g=="], + + "@aws-sdk/client-sts": ["@aws-sdk/client-sts@3.49.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "2.0.0", "@aws-crypto/sha256-js": "2.0.0", "@aws-sdk/config-resolver": "3.49.0", "@aws-sdk/credential-provider-node": "3.49.0", "@aws-sdk/fetch-http-handler": "3.49.0", "@aws-sdk/hash-node": "3.49.0", "@aws-sdk/invalid-dependency": "3.49.0", "@aws-sdk/middleware-content-length": "3.49.0", "@aws-sdk/middleware-host-header": "3.49.0", "@aws-sdk/middleware-logger": "3.49.0", "@aws-sdk/middleware-retry": "3.49.0", "@aws-sdk/middleware-sdk-sts": "3.49.0", "@aws-sdk/middleware-serde": "3.49.0", "@aws-sdk/middleware-signing": "3.49.0", "@aws-sdk/middleware-stack": "3.49.0", "@aws-sdk/middleware-user-agent": "3.49.0", "@aws-sdk/node-config-provider": "3.49.0", "@aws-sdk/node-http-handler": "3.49.0", "@aws-sdk/protocol-http": "3.49.0", "@aws-sdk/smithy-client": "3.49.0", "@aws-sdk/types": "3.49.0", "@aws-sdk/url-parser": "3.49.0", "@aws-sdk/util-base64-browser": "3.49.0", "@aws-sdk/util-base64-node": "3.49.0", "@aws-sdk/util-body-length-browser": "3.49.0", "@aws-sdk/util-body-length-node": "3.49.0", "@aws-sdk/util-defaults-mode-browser": "3.49.0", "@aws-sdk/util-defaults-mode-node": "3.49.0", "@aws-sdk/util-user-agent-browser": "3.49.0", "@aws-sdk/util-user-agent-node": "3.49.0", "@aws-sdk/util-utf8-browser": "3.49.0", "@aws-sdk/util-utf8-node": "3.49.0", "entities": "2.2.0", "fast-xml-parser": "3.19.0", "tslib": "^2.3.0" } }, "sha512-vqHNCuQriMZV1aeXc6cza5S9A/2zgfNiTelsmbDQdlCiZQ+YL3nTp1WFeYHap4ffYlLOAD0xv0yz/+naV4oHtQ=="], + + "@aws-sdk/config-resolver": ["@aws-sdk/config-resolver@3.49.0", "", { "dependencies": { "@aws-sdk/signature-v4": "3.49.0", "@aws-sdk/types": "3.49.0", "@aws-sdk/util-config-provider": "3.49.0", "tslib": "^2.3.0" } }, "sha512-4kYV+89E9MG+/wfPY3dmwqzquQxNd951jdfjQbSg1ii68X/owqmWda4bLulV0Z4iGUz9TXkbaJCWyRyjsFNe4w=="], + + "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.49.0", "", { "dependencies": { "@aws-sdk/property-provider": "3.49.0", "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-mx82N0un6URmmiM11X3ObK3ka5R99lEFdhwPc0jqsCPnXRVioUtK5DXkJ8FmgixbDcs5Pdij9A8MINSeBrG0bQ=="], + + "@aws-sdk/credential-provider-imds": ["@aws-sdk/credential-provider-imds@3.49.0", "", { "dependencies": { "@aws-sdk/node-config-provider": "3.49.0", "@aws-sdk/property-provider": "3.49.0", "@aws-sdk/types": "3.49.0", "@aws-sdk/url-parser": "3.49.0", "tslib": "^2.3.0" } }, "sha512-d/H5VgmRiIupQdPg9QcX16kdvuiS/YytRYCQOncVstNXHvYZM9EgeIXJLXyPNaD2W8SS7CBf4KKWYJn3V+9AZw=="], + + "@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.49.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.49.0", "@aws-sdk/credential-provider-imds": "3.49.0", "@aws-sdk/credential-provider-sso": "3.49.0", "@aws-sdk/credential-provider-web-identity": "3.49.0", "@aws-sdk/property-provider": "3.49.0", "@aws-sdk/shared-ini-file-loader": "3.49.0", "@aws-sdk/types": "3.49.0", "@aws-sdk/util-credentials": "3.49.0", "tslib": "^2.3.0" } }, "sha512-QlWfxDwZVyX36pghgkKGBR+fBmX/mjmvc0kzxUmqGhUYAkDQ0YKR11ybpGBrxBKT4lIOE+9z6Tu4nLjp3OlJIg=="], + + "@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.49.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.49.0", "@aws-sdk/credential-provider-imds": "3.49.0", "@aws-sdk/credential-provider-ini": "3.49.0", "@aws-sdk/credential-provider-process": "3.49.0", "@aws-sdk/credential-provider-sso": "3.49.0", "@aws-sdk/credential-provider-web-identity": "3.49.0", "@aws-sdk/property-provider": "3.49.0", "@aws-sdk/shared-ini-file-loader": "3.49.0", "@aws-sdk/types": "3.49.0", "@aws-sdk/util-credentials": "3.49.0", "tslib": "^2.3.0" } }, "sha512-DonoqOZHcqfNuwMG1fGJpHJTqf1QinihRKzlOoUWzmseqBCiuagGouSN7nOQgee5BrzF0X9/nao9lnPc4on2TA=="], + + "@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.49.0", "", { "dependencies": { "@aws-sdk/property-provider": "3.49.0", "@aws-sdk/shared-ini-file-loader": "3.49.0", "@aws-sdk/types": "3.49.0", "@aws-sdk/util-credentials": "3.49.0", "tslib": "^2.3.0" } }, "sha512-Zn7CJHoXln8O+yBKdTBvcwCz6GDh48s7HtIsqjoOrqoL0oZWhgy8gn8S9KQ+HIqpiO8N0lMMteXuPl5fbC2zGg=="], + + "@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.49.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.49.0", "@aws-sdk/property-provider": "3.49.0", "@aws-sdk/shared-ini-file-loader": "3.49.0", "@aws-sdk/types": "3.49.0", "@aws-sdk/util-credentials": "3.49.0", "tslib": "^2.3.0" } }, "sha512-sFTqbQOyGR88K10Y1OgauEPKDmEibxtAkLSFjkJ6Yw/Jyp+lftchoa+TxRrNvDY1zjZX+XauVI6UmD5Pi4E1NQ=="], + + "@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.49.0", "", { "dependencies": { "@aws-sdk/property-provider": "3.49.0", "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-mlIHUTn04unB0HEwEO12YIY5848uE9B+gYI+YwlNZ70KXGs3lj2horOgPgbxeIfulCVw0aRTKChUg2ActTosYg=="], + + "@aws-sdk/eventstream-marshaller": ["@aws-sdk/eventstream-marshaller@3.49.0", "", { "dependencies": { "@aws-crypto/crc32": "2.0.0", "@aws-sdk/types": "3.49.0", "@aws-sdk/util-hex-encoding": "3.49.0", "tslib": "^2.3.0" } }, "sha512-EDE7aim4c/G9vCWE+jaHQNWHzrHgF1WlUEok1tgLj+fbvqKduDK/1SNleMZbMLC7tFRARN+KKFB0Ctegyp8j4w=="], + + "@aws-sdk/eventstream-serde-browser": ["@aws-sdk/eventstream-serde-browser@3.49.0", "", { "dependencies": { "@aws-sdk/eventstream-marshaller": "3.49.0", "@aws-sdk/eventstream-serde-universal": "3.49.0", "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-XHDHVGmxzEEXzHESzXYiycE3CxHLedBQljQPCIXKJkUhmwf84oUDB/cRsgWoOwOpcRQQBZGUPTPOOOHVWQOlZA=="], + + "@aws-sdk/eventstream-serde-config-resolver": ["@aws-sdk/eventstream-serde-config-resolver@3.49.0", "", { "dependencies": { "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-7xCaQGfZD0xLpWVUsGEQ2PDAkkfnl1gc10h4jLm0xtEGzr0x3B3fLrmDiZTz+wBxRRuCqjiaBaNuPT+HocGYmA=="], + + "@aws-sdk/eventstream-serde-node": ["@aws-sdk/eventstream-serde-node@3.49.0", "", { "dependencies": { "@aws-sdk/eventstream-marshaller": "3.49.0", "@aws-sdk/eventstream-serde-universal": "3.49.0", "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-hRZa1QSCtSve3vSgOxtGRn7nlOJFGzaov6hDj+bFEWY6ukHWtG9lbit6ECALcud4BjxvaJet37kqToxnpDFMuQ=="], + + "@aws-sdk/eventstream-serde-universal": ["@aws-sdk/eventstream-serde-universal@3.49.0", "", { "dependencies": { "@aws-sdk/eventstream-marshaller": "3.49.0", "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-oW/k0QdJTEwRLbdWpakIKABYKEOokBaPd+VSOYmCNceYPzv74RTDqlzTTRVIGj51Jp+Bm1af3l0k1cpjPDnWfQ=="], + + "@aws-sdk/fetch-http-handler": ["@aws-sdk/fetch-http-handler@3.49.0", "", { "dependencies": { "@aws-sdk/protocol-http": "3.49.0", "@aws-sdk/querystring-builder": "3.49.0", "@aws-sdk/types": "3.49.0", "@aws-sdk/util-base64-browser": "3.49.0", "tslib": "^2.3.0" } }, "sha512-ougJRsvoIGP0qTgHSGVF1B5Ui95Y/SP5CpY/y6B8vMGrwJ+MmvcCUE3Qd2UJGjO1PfUneno8PHK4u5x7hc2ceA=="], + + "@aws-sdk/hash-blob-browser": ["@aws-sdk/hash-blob-browser@3.49.0", "", { "dependencies": { "@aws-sdk/chunked-blob-reader": "3.49.0", "@aws-sdk/chunked-blob-reader-native": "3.49.0", "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-DLLP8dY0eYAXefJJzAYO1QxHW567MN4D2KDxyOKkWOVR2S6ZLgtJb24MhT9RpV3AOM/x686HOv5V4r1rPbuHhw=="], + + "@aws-sdk/hash-node": ["@aws-sdk/hash-node@3.49.0", "", { "dependencies": { "@aws-sdk/types": "3.49.0", "@aws-sdk/util-buffer-from": "3.49.0", "tslib": "^2.3.0" } }, "sha512-nRNCmSkcJOzWzKU6NihlKW/6H1HxaaBjUe9ETnwWIgwPC7NZ6IWtri48Cf7Itvveu3dln3ZM2WSXN20TlQpuBw=="], + + "@aws-sdk/hash-stream-node": ["@aws-sdk/hash-stream-node@3.49.0", "", { "dependencies": { "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-ZsqGEs3yp5YH5vk1LhpIiSAzNzXHW89DvKn+BSSiDPdufPdOjLks8wKIVhAUfADcJ+S/AATTAt4SoA4mD+IHvQ=="], + + "@aws-sdk/invalid-dependency": ["@aws-sdk/invalid-dependency@3.49.0", "", { "dependencies": { "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-MXf/9l/Oiy+KGKDvInv0RT4rtS+iNftYRTlTmUn3RR74Kz8Fvw+O0RcUjzSrNn5SpjCf/UsGrF+KBTm2gFYQCA=="], + + "@aws-sdk/is-array-buffer": ["@aws-sdk/is-array-buffer@3.49.0", "", { "dependencies": { "tslib": "^2.3.0" } }, "sha512-tLba+xvlm1+aAnv+bGieVZo8DCENbqfS9kLf/hp+9hrUSiNAsxs9Pqi34JBpMKGn6h9qORp6f8ClRS+gK8yvWg=="], + + "@aws-sdk/md5-js": ["@aws-sdk/md5-js@3.49.0", "", { "dependencies": { "@aws-sdk/types": "3.49.0", "@aws-sdk/util-utf8-browser": "3.49.0", "@aws-sdk/util-utf8-node": "3.49.0", "tslib": "^2.3.0" } }, "sha512-CJJxl7FfTNseaw3RAPmihpys1cfbCyg7sLTev6PncqBhoVl+5AWOoITeZj3azE3CKevY2V7PEdmHjzKRNLmcdA=="], + + "@aws-sdk/middleware-apply-body-checksum": ["@aws-sdk/middleware-apply-body-checksum@3.49.0", "", { "dependencies": { "@aws-sdk/is-array-buffer": "3.49.0", "@aws-sdk/protocol-http": "3.49.0", "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-uNUETgYrOLCZNad+vVsTblTqzuaCVCt67o4VawsziR5QuOCxX/27Ni3x1VNtpI5pUhD8FiT/9/lBpcMTvCSIgA=="], + + "@aws-sdk/middleware-bucket-endpoint": ["@aws-sdk/middleware-bucket-endpoint@3.49.0", "", { "dependencies": { "@aws-sdk/protocol-http": "3.49.0", "@aws-sdk/types": "3.49.0", "@aws-sdk/util-arn-parser": "3.49.0", "@aws-sdk/util-config-provider": "3.49.0", "tslib": "^2.3.0" } }, "sha512-6GK6BXNRRe+JpBUomW1Wrj7HGU3gdl9XvrQekj772kmiBLx/40ntAxZnhjFjkNKLy7IM+he8yygnEUhbV/dEmg=="], + + "@aws-sdk/middleware-content-length": ["@aws-sdk/middleware-content-length@3.49.0", "", { "dependencies": { "@aws-sdk/protocol-http": "3.49.0", "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-7IaghPT7X92gNoyn9LzZj4V5YpGPDCYQTWhpzZoIlw88vOR4I0zKg7jwYeElRoNfRCI4OYhF26ajKnNHzNMlbA=="], + + "@aws-sdk/middleware-expect-continue": ["@aws-sdk/middleware-expect-continue@3.49.0", "", { "dependencies": { "@aws-sdk/middleware-header-default": "3.49.0", "@aws-sdk/protocol-http": "3.49.0", "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-i0FMywhvCdn3+gPuUgtM0ZRd3xBHozropbhvs3fu9Y6g1/YiOgTYuVVqHtObvktVWCV72i8fTvn8TEkyFHRDYQ=="], + + "@aws-sdk/middleware-header-default": ["@aws-sdk/middleware-header-default@3.49.0", "", { "dependencies": { "@aws-sdk/protocol-http": "3.49.0", "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-3xRNPwFMWQqgGKgxDWMgQXNdIr4EVq5ltrLqwsZopXKZli9/fidOrDN9z9j4AW9YAXyEAYB0fscKT7LcsvxFZg=="], + + "@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.49.0", "", { "dependencies": { "@aws-sdk/protocol-http": "3.49.0", "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-5l1ILqHs2mGqNvJb5mRe7hHbTQOO292jghE/LItpNx2tiu7BBGzP1bslHcyEVYoRBX9Oqyfou7s9Ww2yBWtImQ=="], + + "@aws-sdk/middleware-location-constraint": ["@aws-sdk/middleware-location-constraint@3.49.0", "", { "dependencies": { "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-PUQr06/9XQP0JfUY6nFvK5HHcO4aQbzn/iKvB8dl471IXcKVLnJdB2OuIjUUW6fQbKX1K4xcDEifWTSMIECIlg=="], + + "@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.49.0", "", { "dependencies": { "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-OicQ0w5sCJXgpeZ+t3XeJA2R/09YfuSe53Ma6aWZm/2/r8vG/SW0yAnwFvwJeCm3DKtBxU1qO2eWhFqvJuWRVA=="], + + "@aws-sdk/middleware-retry": ["@aws-sdk/middleware-retry@3.49.0", "", { "dependencies": { "@aws-sdk/protocol-http": "3.49.0", "@aws-sdk/service-error-classification": "3.49.0", "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0", "uuid": "^8.3.2" } }, "sha512-RSS4R4PNULHA1b1eYR50YPPfOV2jRuXgLNLVVYMEzzC23MabKEXJYPge+pI1Q9rRrbahVj7aQcOTSpT0MsiEeA=="], + + "@aws-sdk/middleware-sdk-s3": ["@aws-sdk/middleware-sdk-s3@3.49.0", "", { "dependencies": { "@aws-sdk/protocol-http": "3.49.0", "@aws-sdk/signature-v4": "3.49.0", "@aws-sdk/types": "3.49.0", "@aws-sdk/util-arn-parser": "3.49.0", "tslib": "^2.3.0" }, "peerDependencies": { "@aws-sdk/signature-v4-crt": "^3.31.0" } }, "sha512-PeQHJsecGCnXILgOPLgcoZXCa4+2bctus2krhN08ES5oh1obeQB+EOC4v1sWV0DdfyTHEZMDSVLS9qTFHl9IUA=="], + + "@aws-sdk/middleware-sdk-sts": ["@aws-sdk/middleware-sdk-sts@3.49.0", "", { "dependencies": { "@aws-sdk/middleware-signing": "3.49.0", "@aws-sdk/property-provider": "3.49.0", "@aws-sdk/protocol-http": "3.49.0", "@aws-sdk/signature-v4": "3.49.0", "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-ZnLV37HKpMdK2x+69ZNqAqKr8rmweyMc//yZQRLtUKpKyQ/XSr0/KUBZXkgIny27aaBsrkplA5g1X2GrClRRZA=="], + + "@aws-sdk/middleware-serde": ["@aws-sdk/middleware-serde@3.49.0", "", { "dependencies": { "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-bMAlwR19uFUZ4om+U+/vnPvkcyYw83HdtERF9wrjAqNUnqYsifA0xn4R7Sakg6CW8V0h82dsST6zVfmHd+E2VA=="], + + "@aws-sdk/middleware-signing": ["@aws-sdk/middleware-signing@3.49.0", "", { "dependencies": { "@aws-sdk/property-provider": "3.49.0", "@aws-sdk/protocol-http": "3.49.0", "@aws-sdk/signature-v4": "3.49.0", "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-9p0xZjxV9zEQdOpA4MtzmblPRUgchevg5Q70E23yAU/Wjwzwf/6J93cUxdcS8HnmOIl0zQjJaYMTcBsvgJF1eg=="], + + "@aws-sdk/middleware-ssec": ["@aws-sdk/middleware-ssec@3.49.0", "", { "dependencies": { "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-S7hfgOCYoqPe4YegSnwhQJ0KBVEhP6dIp7yLa1/yCJkqW2KSnLTvg6ao9vEFf/lhctZ72YZjm8v/2siXWCnDEA=="], + + "@aws-sdk/middleware-stack": ["@aws-sdk/middleware-stack@3.49.0", "", { "dependencies": { "tslib": "^2.3.0" } }, "sha512-OZxs2P7EH58gkvkTI7ESlUPGam0TkE0ZxOX35KjCOcYMuWvTMshKBzHRLX64nz3DYdaHSIGHgB1v8LKELZjltw=="], + + "@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.49.0", "", { "dependencies": { "@aws-sdk/protocol-http": "3.49.0", "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-uAcKgafZ12L8UnyeQGgSFtwOKUfiBWDLt4P2fEHvZRz/HAIcK4pu1PXPArjwteinhUiCDNFfPw8hAPvstMoG6w=="], + + "@aws-sdk/node-config-provider": ["@aws-sdk/node-config-provider@3.49.0", "", { "dependencies": { "@aws-sdk/property-provider": "3.49.0", "@aws-sdk/shared-ini-file-loader": "3.49.0", "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-OCn5c6M/RJDEO80Q+Iy4ADSYgqd/uyEsvp+7lU4di4bMND9kYT4JO2ky2SWjIuARGq/mhMOhaN2DO9MbcqV20g=="], + + "@aws-sdk/node-http-handler": ["@aws-sdk/node-http-handler@3.49.0", "", { "dependencies": { "@aws-sdk/abort-controller": "3.49.0", "@aws-sdk/protocol-http": "3.49.0", "@aws-sdk/querystring-builder": "3.49.0", "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-t7D9hoSigBihC9RRgYrkzgSER0fYzZe7192pJAaP6jk13ZOpccQRfXZoKge/cm42aHJsTy8DdQdGtLg7wLTp0g=="], + + "@aws-sdk/property-provider": ["@aws-sdk/property-provider@3.49.0", "", { "dependencies": { "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-6D48YpriOUpniezVuRI8J+MG+vgwb5C1SzBdgN4+S6DqbsEZy+kdEubXdoMICEd+Z8h7lH3p5zMr6po0icGCfA=="], + + "@aws-sdk/protocol-http": ["@aws-sdk/protocol-http@3.49.0", "", { "dependencies": { "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-lb9CO7/vm26v4UwveWb4jSapqWWP/p0b9SuHpRExq+yMuvHqwxcoGrxmvS7FsanWbepRF1895dxU/Ar6/4pviA=="], + + "@aws-sdk/querystring-builder": ["@aws-sdk/querystring-builder@3.49.0", "", { "dependencies": { "@aws-sdk/types": "3.49.0", "@aws-sdk/util-uri-escape": "3.49.0", "tslib": "^2.3.0" } }, "sha512-+NlgIYihVyUetZcrF1ADY0eg8WW1/ETD5bzTwguTiKduXVHmavSakXK1jJF5vg05mefljToZXjQnOaEs9+K9LA=="], + + "@aws-sdk/querystring-parser": ["@aws-sdk/querystring-parser@3.49.0", "", { "dependencies": { "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-4bSCHI5A8wi+JjsD1gAhMuGRGjDmlw6MoMWUiv4R2J8Ow/9mV8biKRo2ZytUPiSSu4G5JQ7mEkqFsm/VgkstDQ=="], + + "@aws-sdk/service-error-classification": ["@aws-sdk/service-error-classification@3.49.0", "", {}, "sha512-iVmf7RcrIsM/We5ip8fe14RzEpSLF5eN8oqhCMftEdmMVnOYMd/9x0f1w69fbyBJNIIpyREqM8eAKz5OWQn5/g=="], + + "@aws-sdk/shared-ini-file-loader": ["@aws-sdk/shared-ini-file-loader@3.49.0", "", { "dependencies": { "tslib": "^2.3.0" } }, "sha512-TcgKU6U/3JZpenRFhGSy5R5QsBWkYoeawTK1rTK6deu3UbxVwtOkietbfwP3kIwKZ4hz6OkNeHcOJtXX/InZKw=="], + + "@aws-sdk/signature-v4": ["@aws-sdk/signature-v4@3.49.0", "", { "dependencies": { "@aws-sdk/is-array-buffer": "3.49.0", "@aws-sdk/types": "3.49.0", "@aws-sdk/util-hex-encoding": "3.49.0", "@aws-sdk/util-uri-escape": "3.49.0", "tslib": "^2.3.0" } }, "sha512-mQSGclWmv/9/MsgthBuKMHN6nkkhGTLXspkhqJ9xSUhjhoaHQVwMoJc39PowJGbYFn1AtCvHAqJtFXTGsMRwPA=="], + + "@aws-sdk/signature-v4-crt": ["@aws-sdk/signature-v4-crt@3.49.0", "", { "dependencies": { "@aws-sdk/is-array-buffer": "3.49.0", "@aws-sdk/querystring-parser": "3.49.0", "@aws-sdk/signature-v4": "3.49.0", "@aws-sdk/util-hex-encoding": "3.49.0", "@aws-sdk/util-uri-escape": "3.49.0", "aws-crt": "^1.9.7", "tslib": "^2.3.0" } }, "sha512-jTHX6kNBV4ulj3y7klUznsmb8SsSz1IcDoorYftuVcGZsXtRsd96XSsPA9NSWHWtAj+1O7iQ28u4nRV7d04WdA=="], + + "@aws-sdk/smithy-client": ["@aws-sdk/smithy-client@3.49.0", "", { "dependencies": { "@aws-sdk/middleware-stack": "3.49.0", "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-ANh9SlEvuru1DcalVoQ7K6wSCYuw4jyeTsIDsJSa13ckrmXAg+ql9vq61ELAXTSNVmuAISuuPjbVaWvOYCtdCQ=="], + + "@aws-sdk/types": ["@aws-sdk/types@3.49.0", "", {}, "sha512-8bCqEpquTlPN6xkjaJ+s+RoEFIu5r4G8oXOsQ5HYBvBdpx62HnCqzHLFNHycL2b8sE+VysQgNvmdQYR98vdMGQ=="], + + "@aws-sdk/url-parser": ["@aws-sdk/url-parser@3.49.0", "", { "dependencies": { "@aws-sdk/querystring-parser": "3.49.0", "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-l5td6eu+sIjzNsZYVGr7Mz6vssf2j/8/QrrTYF76J2R6OoceCsKdyJgJPP/tXBdcp4HUZDdVcMqtWRbxGC4izQ=="], + + "@aws-sdk/util-arn-parser": ["@aws-sdk/util-arn-parser@3.49.0", "", { "dependencies": { "tslib": "^2.3.0" } }, "sha512-mAF4lzxqMUFMQAf+NQSxW7jC5hYXNM7mPItBFs/yI3F25MXBw88Q+wAof7iIyRnRcpJvgZ3I7P8vJriAwrSbFg=="], + + "@aws-sdk/util-base64-browser": ["@aws-sdk/util-base64-browser@3.49.0", "", { "dependencies": { "tslib": "^2.3.0" } }, "sha512-HFXJbsJC6AfrnO9M8KuFDo4ihvLbCbCFCfpWy0Gs4t8kTcvGqH8fIpfVsQKAtFHMmb8fen2LduOk+NNSA7srYw=="], + + "@aws-sdk/util-base64-node": ["@aws-sdk/util-base64-node@3.49.0", "", { "dependencies": { "@aws-sdk/util-buffer-from": "3.49.0", "tslib": "^2.3.0" } }, "sha512-xFAzOLZJOEZipG3KVLjB5z1g5PJSi6cmZOGWg2NC2/H5N0/Z+e5ObnIH8mpfO1d6kWchUuo3qJ6fTOvg/ynw7A=="], + + "@aws-sdk/util-body-length-browser": ["@aws-sdk/util-body-length-browser@3.49.0", "", { "dependencies": { "tslib": "^2.3.0" } }, "sha512-4a9Bw33JGKefaZDORlosQRMKxJGEYEiDD5kgNvwIv+KRl5yj2unePia6aFWMqXTWqidOb9WVlqc0Lh73ei5pTg=="], + + "@aws-sdk/util-body-length-node": ["@aws-sdk/util-body-length-node@3.49.0", "", { "dependencies": { "tslib": "^2.3.0" } }, "sha512-ME5Sc8jo9BzToUjWskQKZM/NqN9PpwRDTOSH6EISDBUiH5bhWfY8MLkZqIN2UZz/XOiV3yOeWAU+fMYNnGdAQQ=="], + + "@aws-sdk/util-buffer-from": ["@aws-sdk/util-buffer-from@3.49.0", "", { "dependencies": { "@aws-sdk/is-array-buffer": "3.49.0", "tslib": "^2.3.0" } }, "sha512-8JbIPYn91f+16QpDk000PdIBlBZu8/SoL1nF2fpAJ+M98jXpKUws3oiCztJ2FPIKRe/3ikKuZM4HxWrDyJa40Q=="], + + "@aws-sdk/util-config-provider": ["@aws-sdk/util-config-provider@3.49.0", "", { "dependencies": { "tslib": "^2.3.0" } }, "sha512-oVGT9q9UIGdv9Cra4B51QNciWKYQXTlfh8oD2FgLp91NbGTIkQLvK7Pah4TbBoa5+0u/obBI07UwCVn7wphWBQ=="], + + "@aws-sdk/util-credentials": ["@aws-sdk/util-credentials@3.49.0", "", { "dependencies": { "@aws-sdk/shared-ini-file-loader": "3.49.0", "tslib": "^2.3.0" } }, "sha512-RzbKeuylb56m0zPuLGl5/TkN07+c4PKhZu3hikpsvN8n8n7aFHWPUus63QEGgVaUMCZD0QV6HqJfsCVVFF7UIg=="], + + "@aws-sdk/util-defaults-mode-browser": ["@aws-sdk/util-defaults-mode-browser@3.49.0", "", { "dependencies": { "@aws-sdk/property-provider": "3.49.0", "@aws-sdk/types": "3.49.0", "bowser": "^2.11.0", "tslib": "^2.3.0" } }, "sha512-MNOvFET5TNBHgvsmfcLuxVDDUV0OIjE1lxrdbXWol7bMgLc2uL3/QOXWKCOUzcFCqTOnWCvbnwkOjs3f7Dpzmw=="], + + "@aws-sdk/util-defaults-mode-node": ["@aws-sdk/util-defaults-mode-node@3.49.0", "", { "dependencies": { "@aws-sdk/config-resolver": "3.49.0", "@aws-sdk/credential-provider-imds": "3.49.0", "@aws-sdk/node-config-provider": "3.49.0", "@aws-sdk/property-provider": "3.49.0", "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-bd5/ZJlNIX25n83mvcCh9eYQiDdf6gLHNH6ZftA/EbFfkE0o/qHrFhBhiB9HBY9ZoHhtoqrJNv5W9qKFHx1EIA=="], + + "@aws-sdk/util-hex-encoding": ["@aws-sdk/util-hex-encoding@3.49.0", "", { "dependencies": { "tslib": "^2.3.0" } }, "sha512-ZbPu8Dd3Qm0BMP71FWUH7KPpZA/6izfkDlxbvHxtHdW7XYZALuJ0cVRpWGIY2fCSuA9X8Jfn60KMyjuSAuzM1w=="], + + "@aws-sdk/util-locate-window": ["@aws-sdk/util-locate-window@3.965.5", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ=="], + + "@aws-sdk/util-uri-escape": ["@aws-sdk/util-uri-escape@3.49.0", "", { "dependencies": { "tslib": "^2.3.0" } }, "sha512-NH7iQUYvijYZEOzZkF/QQrp8kBOA9H0Z89hR/63FDCjr1M0Cdcs1bLaFO0a0qbW9NQtoYNsMBMk7pTveDrAzTw=="], + + "@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.49.0", "", { "dependencies": { "@aws-sdk/types": "3.49.0", "bowser": "^2.11.0", "tslib": "^2.3.0" } }, "sha512-RR4E6WlDSu9SivPjx/Jddo87PeVg6dhRL0XGdDBpew7i8bfwqCvxQydkbWIetxucLrt9zII9QnLDQUPBue1xUw=="], + + "@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.49.0", "", { "dependencies": { "@aws-sdk/node-config-provider": "3.49.0", "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-ixUkF6kcDfsWO0kivyOKAnBITJm7InGa04ALbgAfuuE7RU1cVkXVMFIn5vux7QkziK7+JwozM9SNPIwNukElDw=="], + + "@aws-sdk/util-utf8-browser": ["@aws-sdk/util-utf8-browser@3.49.0", "", { "dependencies": { "tslib": "^2.3.0" } }, "sha512-u9ZgAiTWX9yZFQ/ptlnVpYJ/rXF7aE2Wagar1IjhZrnxXbpVJvcX1EeRayxI1P5AAp2y2fiEKHZzX9ugTwOcEg=="], + + "@aws-sdk/util-utf8-node": ["@aws-sdk/util-utf8-node@3.49.0", "", { "dependencies": { "@aws-sdk/util-buffer-from": "3.49.0", "tslib": "^2.3.0" } }, "sha512-QTF5b5OT2y6xsQl8sDiiXqg2n/VtgqFA+tP3WMooOSFd/ZFBbT6HoiSHXHMeTjpB/L9ZT+eUaCoBz8Jq09lBDg=="], + + "@aws-sdk/util-waiter": ["@aws-sdk/util-waiter@3.49.0", "", { "dependencies": { "@aws-sdk/abort-controller": "3.49.0", "@aws-sdk/types": "3.49.0", "tslib": "^2.3.0" } }, "sha512-eKrKOLcIhjA/MyjIfwgLL6ZUfGYf6VxBXryuRf8CmJKAo71ZO6ipAsy1X3uYrfwQQBMKV4VZu48BJx5PUBM7GA=="], + + "@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.49.0", "", { "dependencies": { "tslib": "^2.3.0" } }, "sha512-eU5sIZRWq8pNmw++RfpFI8396UtDW8JxYLcKfJLGQC/qDhwCo+sNPKydXFmDrXTIt/khs3K0qx/vZ5V76irc2Q=="], + + "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], + + "@babel/compat-data": ["@babel/compat-data@7.29.0", "", {}, "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg=="], + + "@babel/core": ["@babel/core@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA=="], + + "@babel/generator": ["@babel/generator@7.29.1", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw=="], + + "@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="], + + "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.28.6", "", { "dependencies": { "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA=="], + + "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], + + "@babel/helper-module-imports": ["@babel/helper-module-imports@7.28.6", "", { "dependencies": { "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw=="], + + "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.6", "", { "dependencies": { "@babel/helper-module-imports": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA=="], + + "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="], + + "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], + + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], + + "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], + + "@babel/helpers": ["@babel/helpers@7.28.6", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw=="], + + "@babel/parser": ["@babel/parser@7.29.0", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="], + + "@babel/plugin-proposal-object-rest-spread": ["@babel/plugin-proposal-object-rest-spread@7.20.7", "", { "dependencies": { "@babel/compat-data": "^7.20.5", "@babel/helper-compilation-targets": "^7.20.7", "@babel/helper-plugin-utils": "^7.20.2", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-transform-parameters": "^7.20.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg=="], + + "@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w=="], + + "@babel/plugin-syntax-object-rest-spread": ["@babel/plugin-syntax-object-rest-spread@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA=="], + + "@babel/plugin-transform-destructuring": ["@babel/plugin-transform-destructuring@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw=="], + + "@babel/plugin-transform-parameters": ["@babel/plugin-transform-parameters@7.27.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg=="], + + "@babel/plugin-transform-react-jsx": ["@babel/plugin-transform-react-jsx@7.28.6", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-module-imports": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6", "@babel/plugin-syntax-jsx": "^7.28.6", "@babel/types": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow=="], + + "@babel/runtime": ["@babel/runtime@7.28.6", "", {}, "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA=="], + + "@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="], + + "@babel/traverse": ["@babel/traverse@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/types": "^7.29.0", "debug": "^4.3.1" } }, "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA=="], + + "@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="], + + "@bcoe/v8-coverage": ["@bcoe/v8-coverage@1.0.2", "", {}, "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA=="], + + "@biomejs/biome": ["@biomejs/biome@2.4.6", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.6", "@biomejs/cli-darwin-x64": "2.4.6", "@biomejs/cli-linux-arm64": "2.4.6", "@biomejs/cli-linux-arm64-musl": "2.4.6", "@biomejs/cli-linux-x64": "2.4.6", "@biomejs/cli-linux-x64-musl": "2.4.6", "@biomejs/cli-win32-arm64": "2.4.6", "@biomejs/cli-win32-x64": "2.4.6" }, "bin": { "biome": "bin/biome" } }, "sha512-QnHe81PMslpy3mnpL8DnO2M4S4ZnYPkjlGCLWBZT/3R9M6b5daArWMMtEfP52/n174RKnwRIf3oT8+wc9ihSfQ=="], + + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-NW18GSyxr+8sJIqgoGwVp5Zqm4SALH4b4gftIA0n62PTuBs6G2tHlwNAOj0Vq0KKSs7Sf88VjjmHh0O36EnzrQ=="], + + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-4uiE/9tuI7cnjtY9b07RgS7gGyYOAfIAGeVJWEfeCnAarOAS7qVmuRyX6d7JTKw28/mt+rUzMasYeZ+0R/U1Mw=="], + + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-kMLaI7OF5GN1Q8Doymjro1P8rVEoy7BKQALNz6fiR8IC1WKduoNyteBtJlHT7ASIL0Cx2jR6VUOBIbcB1B8pew=="], + + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-F/JdB7eN22txiTqHM5KhIVt0jVkzZwVYrdTR1O3Y4auBOQcXxHK4dxULf4z43QyZI5tsnQJrRBHZy7wwtL+B3A=="], + + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.6", "", { "os": "linux", "cpu": "x64" }, "sha512-oHXmUFEoH8Lql1xfc3QkFLiC1hGR7qedv5eKNlC185or+o4/4HiaU7vYODAH3peRCfsuLr1g6v2fK9dFFOYdyw=="], + + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.6", "", { "os": "linux", "cpu": "x64" }, "sha512-C9s98IPDu7DYarjlZNuzJKTjVHN03RUnmHV5htvqsx6vEUXCDSJ59DNwjKVD5XYoSS4N+BYhq3RTBAL8X6svEg=="], + + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-xzThn87Pf3YrOGTEODFGONmqXpTwUNxovQb72iaUOdcw8sBSY3+3WD8Hm9IhMYLnPi0n32s3L3NWU6+eSjfqFg=="], + + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.6", "", { "os": "win32", "cpu": "x64" }, "sha512-7++XhnsPlr1HDbor5amovPjOH6vsrFOCdp93iKXhFn6bcMUI6soodj3WWKfgEO6JosKU1W5n3uky3WW9RlRjTg=="], + + "@colors/colors": ["@colors/colors@1.6.0", "", {}, "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA=="], + + "@cspotcode/source-map-support": ["@cspotcode/source-map-support@0.8.1", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="], + + "@dabh/diagnostics": ["@dabh/diagnostics@2.0.8", "", { "dependencies": { "@so-ric/colorspace": "^1.1.6", "enabled": "2.0.x", "kuler": "^2.0.0" } }, "sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q=="], + + "@discordjs/builders": ["@discordjs/builders@0.5.0", "", { "dependencies": { "@sindresorhus/is": "^4.0.1", "discord-api-types": "^0.22.0", "ow": "^0.27.0", "ts-mixer": "^6.0.0", "tslib": "^2.3.0" } }, "sha512-HP5y4Rqw68o61Qv4qM5tVmDbWi4mdTFftqIOGRo33SNPpLJ1Ga3KEIR2ibKofkmsoQhEpLmopD1AZDs3cKpHuw=="], + + "@discordjs/collection": ["@discordjs/collection@0.1.6", "", {}, "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ=="], + + "@discordjs/rest": ["@discordjs/rest@0.1.0-canary.0", "", { "dependencies": { "@discordjs/collection": "^0.1.6", "@sapphire/async-queue": "^1.1.4", "@sapphire/snowflake": "^1.3.5", "abort-controller": "^3.0.0", "discord-api-types": "^0.18.1", "form-data": "^4.0.0", "node-fetch": "^2.6.1", "tslib": "^2.3.0" } }, "sha512-d+s//ISYVV+e0w/926wMEeO7vju+Pn11x1JM4tcmVMCHSDgpi6pnFCNAXF1TEdnDcy7xf9tq5cf2pQkb/7ySTQ=="], + + "@electric-sql/pglite": ["@electric-sql/pglite@0.3.15", "", {}, "sha512-Cj++n1Mekf9ETfdc16TlDi+cDDQF0W7EcbyRHYOAeZdsAe8M/FJg18itDTSwyHfar2WIezawM9o0EKaRGVKygQ=="], + + "@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="], + + "@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], + + "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], + + "@emotion/babel-plugin": ["@emotion/babel-plugin@11.13.5", "", { "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/runtime": "^7.18.3", "@emotion/hash": "^0.9.2", "@emotion/memoize": "^0.9.0", "@emotion/serialize": "^1.3.3", "babel-plugin-macros": "^3.1.0", "convert-source-map": "^1.5.0", "escape-string-regexp": "^4.0.0", "find-root": "^1.1.0", "source-map": "^0.5.7", "stylis": "4.2.0" } }, "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ=="], + + "@emotion/cache": ["@emotion/cache@11.14.0", "", { "dependencies": { "@emotion/memoize": "^0.9.0", "@emotion/sheet": "^1.4.0", "@emotion/utils": "^1.4.2", "@emotion/weak-memoize": "^0.4.0", "stylis": "4.2.0" } }, "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA=="], + + "@emotion/hash": ["@emotion/hash@0.9.2", "", {}, "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g=="], + + "@emotion/memoize": ["@emotion/memoize@0.9.0", "", {}, "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ=="], + + "@emotion/react": ["@emotion/react@11.14.0", "", { "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", "@emotion/cache": "^11.14.0", "@emotion/serialize": "^1.3.3", "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", "@emotion/utils": "^1.4.2", "@emotion/weak-memoize": "^0.4.0", "hoist-non-react-statics": "^3.3.1" }, "peerDependencies": { "react": ">=16.8.0" } }, "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA=="], + + "@emotion/serialize": ["@emotion/serialize@1.3.3", "", { "dependencies": { "@emotion/hash": "^0.9.2", "@emotion/memoize": "^0.9.0", "@emotion/unitless": "^0.10.0", "@emotion/utils": "^1.4.2", "csstype": "^3.0.2" } }, "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA=="], + + "@emotion/sheet": ["@emotion/sheet@1.4.0", "", {}, "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg=="], + + "@emotion/unitless": ["@emotion/unitless@0.10.0", "", {}, "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg=="], + + "@emotion/use-insertion-effect-with-fallbacks": ["@emotion/use-insertion-effect-with-fallbacks@1.2.0", "", { "peerDependencies": { "react": ">=16.8.0" } }, "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg=="], + + "@emotion/utils": ["@emotion/utils@1.4.2", "", {}, "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA=="], + + "@emotion/weak-memoize": ["@emotion/weak-memoize@0.4.0", "", {}, "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg=="], + + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.27.3", "", { "os": "android", "cpu": "arm" }, "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.3", "", { "os": "android", "cpu": "arm64" }, "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.27.3", "", { "os": "android", "cpu": "x64" }, "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.3", "", { "os": "linux", "cpu": "arm" }, "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.3", "", { "os": "linux", "cpu": "ia32" }, "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.3", "", { "os": "linux", "cpu": "x64" }, "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.3", "", { "os": "none", "cpu": "x64" }, "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.3", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.3", "", { "os": "openbsd", "cpu": "x64" }, "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ=="], + + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.3", "", { "os": "sunos", "cpu": "x64" }, "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.3", "", { "os": "win32", "cpu": "x64" }, "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA=="], + + "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ=="], + + "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="], + + "@eslint/config-array": ["@eslint/config-array@0.21.2", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.5" } }, "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw=="], + + "@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "^0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="], + + "@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="], + + "@eslint/eslintrc": ["@eslint/eslintrc@3.3.5", "", { "dependencies": { "ajv": "^6.14.0", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", "minimatch": "^3.1.5", "strip-json-comments": "^3.1.1" } }, "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg=="], + + "@eslint/js": ["@eslint/js@9.39.4", "", {}, "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw=="], + + "@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="], + + "@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="], + + "@floating-ui/core": ["@floating-ui/core@1.7.5", "", { "dependencies": { "@floating-ui/utils": "^0.2.11" } }, "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ=="], + + "@floating-ui/dom": ["@floating-ui/dom@1.7.6", "", { "dependencies": { "@floating-ui/core": "^1.7.5", "@floating-ui/utils": "^0.2.11" } }, "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ=="], + + "@floating-ui/utils": ["@floating-ui/utils@0.2.11", "", {}, "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg=="], + + "@fortawesome/fontawesome-free": ["@fortawesome/fontawesome-free@5.13.0", "", {}, "sha512-xKOeQEl5O47GPZYIMToj6uuA2syyFlq9EMSl2ui0uytjY9xbe8XS0pexNWmxrdcCyNGyDmLyYw5FtKsalBUeOg=="], + + "@fullcalendar/core": ["@fullcalendar/core@6.1.20", "", { "dependencies": { "preact": "~10.12.1" } }, "sha512-1cukXLlePFiJ8YKXn/4tMKsy0etxYLCkXk8nUCFi11nRONF2Ba2CD5b21/ovtOO2tL6afTJfwmc1ed3HG7eB1g=="], + + "@fullcalendar/daygrid": ["@fullcalendar/daygrid@6.1.20", "", { "peerDependencies": { "@fullcalendar/core": "~6.1.20" } }, "sha512-AO9vqhkLP77EesmJzuU+IGXgxNulsA8mgQHynclJ8U70vSwAVnbcLG9qftiTAFSlZjiY/NvhE7sflve6cJelyQ=="], + + "@fullcalendar/react": ["@fullcalendar/react@6.1.20", "", { "peerDependencies": { "@fullcalendar/core": "~6.1.20", "react": "^16.7.0 || ^17 || ^18 || ^19", "react-dom": "^16.7.0 || ^17 || ^18 || ^19" } }, "sha512-1w0pZtceaUdfAnxMSCGHCQalhi+mR1jOe76sXzyAXpcPz/Lf0zHSdcGK/U2XpZlnQgQtBZW+d+QBnnzVQKCxAA=="], + + "@grpc/grpc-js": ["@grpc/grpc-js@1.14.3", "", { "dependencies": { "@grpc/proto-loader": "^0.8.0", "@js-sdsl/ordered-map": "^4.4.2" } }, "sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA=="], + + "@grpc/proto-loader": ["@grpc/proto-loader@0.8.0", "", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.5.3", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ=="], + + "@httptoolkit/websocket-stream": ["@httptoolkit/websocket-stream@6.0.1", "", { "dependencies": { "@types/ws": "*", "duplexify": "^3.5.1", "inherits": "^2.0.1", "isomorphic-ws": "^4.0.1", "readable-stream": "^2.3.3", "safe-buffer": "^5.1.2", "ws": "*", "xtend": "^4.0.0" } }, "sha512-A0NOZI+Glp3Xgcz6Na7i7o09+/+xm2m0UCU8gdtM2nIv6/cjLmhMZMqehSpTlgbx9omtLmV8LVqOskPEyWnmZQ=="], + + "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], + + "@humanfs/node": ["@humanfs/node@0.16.7", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.4.0" } }, "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ=="], + + "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], + + "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="], + + "@ioredis/commands": ["@ioredis/commands@1.5.1", "", {}, "sha512-JH8ZL/ywcJyR9MmJ5BNqZllXNZQqQbnVZOqpPQqE1vHiFgAw4NHbvE0FOduNU8IX9babitBT46571OnPTT0Zcw=="], + + "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], + + "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], + + "@istanbuljs/load-nyc-config": ["@istanbuljs/load-nyc-config@1.1.0", "", { "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", "get-package-type": "^0.1.0", "js-yaml": "^3.13.1", "resolve-from": "^5.0.0" } }, "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ=="], + + "@istanbuljs/schema": ["@istanbuljs/schema@0.1.3", "", {}, "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA=="], + + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], + + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + + "@jridgewell/source-map": ["@jridgewell/source-map@0.3.11", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" } }, "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], + + "@js-sdsl/ordered-map": ["@js-sdsl/ordered-map@4.4.2", "", {}, "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw=="], + + "@kristiandupont/recase": ["@kristiandupont/recase@1.4.1", "", { "dependencies": { "ramda": "^0.30.0" } }, "sha512-e5t4YqhnRGbS9sU4N52cQgTn37qKwTsxDDcIuIkgPvX0UmnL+7eoOR6oFXeCib5zYuw03vYKpR55NBq+W43j1A=="], + + "@mapbox/node-pre-gyp": ["@mapbox/node-pre-gyp@2.0.3", "", { "dependencies": { "consola": "^3.2.3", "detect-libc": "^2.0.0", "https-proxy-agent": "^7.0.5", "node-fetch": "^2.6.7", "nopt": "^8.0.0", "semver": "^7.5.3", "tar": "^7.4.0" }, "bin": { "node-pre-gyp": "bin/node-pre-gyp" } }, "sha512-uwPAhccfFJlsfCxMYTwOdVfOz3xqyj8xYL3zJj8f0pb30tLohnnFPhLuqp4/qoEz8sNxe4SESZedcBojRefIzg=="], + + "@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw=="], + + "@msgpackr-extract/msgpackr-extract-darwin-x64": ["@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw=="], + + "@msgpackr-extract/msgpackr-extract-linux-arm": ["@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3", "", { "os": "linux", "cpu": "arm" }, "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw=="], + + "@msgpackr-extract/msgpackr-extract-linux-arm64": ["@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg=="], + + "@msgpackr-extract/msgpackr-extract-linux-x64": ["@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3", "", { "os": "linux", "cpu": "x64" }, "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg=="], + + "@msgpackr-extract/msgpackr-extract-win32-x64": ["@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3", "", { "os": "win32", "cpu": "x64" }, "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ=="], + + "@napi-rs/snappy-android-arm-eabi": ["@napi-rs/snappy-android-arm-eabi@7.3.3", "", { "os": "android", "cpu": "arm" }, "sha512-d4vUFFzNBvazGfB/KU8MnEax6itTIgRWXodPdZDnWKHy9HwVBndpCiedQDcSNHcZNYV36rx034rpn7SAuTL2NA=="], + + "@napi-rs/snappy-android-arm64": ["@napi-rs/snappy-android-arm64@7.3.3", "", { "os": "android", "cpu": "arm64" }, "sha512-Uh+w18dhzjVl85MGhRnojb7OLlX2ErvMsYIunO/7l3Frvc2zQvfqsWsFJanu2dwqlE2YDooeNP84S+ywgN9sxg=="], + + "@napi-rs/snappy-darwin-arm64": ["@napi-rs/snappy-darwin-arm64@7.3.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-AmJn+6yOu/0V0YNHLKmRUNYkn93iv/1wtPayC7O1OHtfY6YqHQ31/MVeeRBiEYtQW9TwVZxXrDirxSB1PxRdtw=="], + + "@napi-rs/snappy-darwin-x64": ["@napi-rs/snappy-darwin-x64@7.3.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-biLTXBmPjPmO7HIpv+5BaV9Gy/4+QJSUNJW8Pjx1UlWAVnocPy7um+zbvAWStZssTI5sfn/jOClrAegD4w09UA=="], + + "@napi-rs/snappy-freebsd-x64": ["@napi-rs/snappy-freebsd-x64@7.3.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-E3R3ewm8Mrjm0yL2TC3VgnphDsQaCPixNJqBbGiz3NTshVDhlPlOgPKF0NGYqKiKaDGdD9PKtUgOR4vagUtn7g=="], + + "@napi-rs/snappy-linux-arm-gnueabihf": ["@napi-rs/snappy-linux-arm-gnueabihf@7.3.3", "", { "os": "linux", "cpu": "arm" }, "sha512-ZuNgtmk9j0KyT7TfLyEnvZJxOhbkyNR761nk04F0Q4NTHMICP28wQj0xgEsnCHUsEeA9OXrRL4R7waiLn+rOQA=="], + + "@napi-rs/snappy-linux-arm64-gnu": ["@napi-rs/snappy-linux-arm64-gnu@7.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-KIzwtq0dAzshzpqZWjg0Q9lUx93iZN7wCCUzCdLYIQ+mvJZKM10VCdn0RcuQze1R3UJTPwpPLXQIVskNMBYyPA=="], + + "@napi-rs/snappy-linux-arm64-musl": ["@napi-rs/snappy-linux-arm64-musl@7.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-AAED4cQS74xPvktsyVmz5sy8vSxG/+3d7Rq2FDBZzj3Fv6v5vux6uZnECPCAqpALCdTtJ61unqpOyqO7hZCt1Q=="], + + "@napi-rs/snappy-linux-ppc64-gnu": ["@napi-rs/snappy-linux-ppc64-gnu@7.3.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-pofO5eSLg8ZTBwVae4WHHwJxJGZI8NEb4r5Mppvq12J/1/Hq1HecClXmfY3A7bdT2fsS2Td+Q7CI9VdBOj2sbA=="], + + "@napi-rs/snappy-linux-riscv64-gnu": ["@napi-rs/snappy-linux-riscv64-gnu@7.3.3", "", { "os": "linux", "cpu": "none" }, "sha512-OiHYdeuwj0TVBXADUmmQDQ4lL1TB+8EwmXnFgOutoDVXHaUl0CJFyXLa6tYUXe+gRY8hs1v7eb0vyE97LKY06Q=="], + + "@napi-rs/snappy-linux-s390x-gnu": ["@napi-rs/snappy-linux-s390x-gnu@7.3.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-66QdmuV9CTq/S/xifZXlMy3PsZTviAgkqqpZ+7vPCmLtuP+nqhaeupShOFf/sIDsS0gZePazPosPTeTBbhkLHg=="], + + "@napi-rs/snappy-linux-x64-gnu": ["@napi-rs/snappy-linux-x64-gnu@7.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-g6KURjOxrgb8yXDEZMuIcHkUr/7TKlDwSiydEQtMtP3n4iI4sNjkcE/WNKlR3+t9bZh1pFGAq7NFRBtouQGHpQ=="], + + "@napi-rs/snappy-linux-x64-musl": ["@napi-rs/snappy-linux-x64-musl@7.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-6UvOyczHknpaKjrlKKSlX3rwpOrfJwiMG6qA0NRKJFgbcCAEUxmN9A8JvW4inP46DKdQ0bekdOxwRtAhFiTDfg=="], + + "@napi-rs/snappy-openharmony-arm64": ["@napi-rs/snappy-openharmony-arm64@7.3.3", "", { "os": "none", "cpu": "arm64" }, "sha512-I5mak/5rTprobf7wMCk0vFhClmWOL/QiIJM4XontysnadmP/R9hAcmuFmoMV2GaxC9MblqLA7Z++gy8ou5hJVw=="], + + "@napi-rs/snappy-wasm32-wasi": ["@napi-rs/snappy-wasm32-wasi@7.3.3", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.0.3" }, "cpu": "none" }, "sha512-+EroeygVYo9RksOchjF206frhMkfD2PaIun3yH4Zp5j/Y0oIEgs/+VhAYx/f+zHRylQYUIdLzDRclcoepvlR8Q=="], + + "@napi-rs/snappy-win32-arm64-msvc": ["@napi-rs/snappy-win32-arm64-msvc@7.3.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-rxqfntBsCfzgOha/OlG8ld2hs6YSMGhpMUbFjeQLyVDbooY041fRXv3S7yk52DfO6H4QQhLT5+p7cW0mYdhyiQ=="], + + "@napi-rs/snappy-win32-ia32-msvc": ["@napi-rs/snappy-win32-ia32-msvc@7.3.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-joRV16DsRtqjGt0CdSpxGCkO0UlHGeTZ/GqvdscoALpRKbikR2Top4C61dxEchmOd3lSYsXutuwWWGg3Nr++WA=="], + + "@napi-rs/snappy-win32-x64-msvc": ["@napi-rs/snappy-win32-x64-msvc@7.3.3", "", { "os": "win32", "cpu": "x64" }, "sha512-cEnQwcsdJyOU7HSZODWsHpKuQoSYM4jaqw/hn9pOXYbRN1+02WxYppD3fdMuKN6TOA6YG5KA5PHRNeVilNX86Q=="], + + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" } }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="], + + "@nivo/annotations": ["@nivo/annotations@0.79.1", "", { "dependencies": { "@nivo/colors": "0.79.1", "@react-spring/web": "9.3.1", "lodash": "^4.17.21" }, "peerDependencies": { "@nivo/core": "0.79.0", "react": ">= 16.14.0 < 18.0.0" } }, "sha512-lYso9Luu0maSDtIufwvyVt2+Wue7R9Fh3CIjuRDmNR72UjAgAVEcCar27Fy865UXGsj2hRJZ7KY/1s6kT3gu/w=="], + + "@nivo/axes": ["@nivo/axes@0.79.0", "", { "dependencies": { "@nivo/scales": "0.79.0", "@react-spring/web": "9.3.1", "d3-format": "^1.4.4", "d3-time-format": "^3.0.0" }, "peerDependencies": { "@nivo/core": "0.79.0", "prop-types": ">= 15.5.10 < 16.0.0", "react": ">= 16.14.0 < 18.0.0" } }, "sha512-EhSeCPxtWEuxqnifeyF/pIJEzL7pRM3rfygL+MpfT5ypu5NcXYRGQo/Bw0Vh+GF1ML+tNAE0rRvCu2jgLSdVNQ=="], + + "@nivo/bar": ["@nivo/bar@0.79.1", "", { "dependencies": { "@nivo/annotations": "0.79.1", "@nivo/axes": "0.79.0", "@nivo/colors": "0.79.1", "@nivo/legends": "0.79.1", "@nivo/scales": "0.79.0", "@nivo/tooltip": "0.79.0", "@react-spring/web": "9.3.1", "d3-scale": "^3.2.3", "d3-shape": "^1.2.2", "lodash": "^4.17.21" }, "peerDependencies": { "@nivo/core": "0.79.0", "react": ">= 16.14.0 < 18.0.0" } }, "sha512-swJ2FtFeRPWJK9O6aZiqTDi2J6GrU2Z6kIHBBCXBlFmq6+vfd5AqOHytdXPTaN80JsKDBBdtY7tqRjpRPlDZwQ=="], + + "@nivo/colors": ["@nivo/colors@0.79.1", "", { "dependencies": { "d3-color": "^2.0.0", "d3-scale": "^3.2.3", "d3-scale-chromatic": "^2.0.0", "lodash": "^4.17.21" }, "peerDependencies": { "@nivo/core": "0.79.0", "prop-types": ">= 15.5.10 < 16.0.0", "react": ">= 16.14.0 < 18.0.0" } }, "sha512-45huBmz46OoQtfqzHrnqDJ9msebOBX84fTijyOBi8mn8iTDOK2xWgzT7cCYP3hKE58IclkibkzVyWCeJ+rUlqg=="], + + "@nivo/core": ["@nivo/core@0.79.0", "", { "dependencies": { "@nivo/recompose": "0.79.0", "@react-spring/web": "9.3.1", "d3-color": "^2.0.0", "d3-format": "^1.4.4", "d3-interpolate": "^2.0.1", "d3-scale": "^3.2.3", "d3-scale-chromatic": "^2.0.0", "d3-shape": "^1.3.5", "d3-time-format": "^3.0.0", "lodash": "^4.17.21" }, "peerDependencies": { "@nivo/tooltip": "0.79.0", "prop-types": ">= 15.5.10 < 16.0.0", "react": ">= 16.14.0 < 18.0.0" } }, "sha512-e1iGodmGuXkF+QWAjhHVFc+lUnfBoUwaWqVcBXBfebzNc50tTJrTTMHyQczjgOIfTc8gEu23lAY4mVZCDKscig=="], + + "@nivo/legends": ["@nivo/legends@0.79.1", "", { "peerDependencies": { "@nivo/core": "0.79.0", "prop-types": ">= 15.5.10 < 16.0.0", "react": ">= 16.14.0 < 18.0.0" } }, "sha512-AoabiLherOAk3/HR/N791fONxNdwNk/gCTJC/6BKUo2nX+JngEYm3nVFmTC1R6RdjwJTeCb9Vtuc4MHA+mcgig=="], + + "@nivo/line": ["@nivo/line@0.79.1", "", { "dependencies": { "@nivo/annotations": "0.79.1", "@nivo/axes": "0.79.0", "@nivo/colors": "0.79.1", "@nivo/legends": "0.79.1", "@nivo/scales": "0.79.0", "@nivo/tooltip": "0.79.0", "@nivo/voronoi": "0.79.0", "@react-spring/web": "9.3.1", "d3-shape": "^1.3.5" }, "peerDependencies": { "@nivo/core": "0.79.0", "prop-types": ">= 15.5.10 < 16.0.0", "react": ">= 16.14.0 < 18.0.0" } }, "sha512-V+2wY5TGpWiWBcb2LDtNsO79Ix93QtSq1HAdEIsjYtwFT/ekoCUA/OorIjRVUVzyf27vjjlbhmNNKrqIsYQR1Q=="], + + "@nivo/recompose": ["@nivo/recompose@0.79.0", "", { "dependencies": { "react-lifecycles-compat": "^3.0.4" }, "peerDependencies": { "react": ">= 16.14.0 < 18.0.0" } }, "sha512-2GFnOHfA2jzTOA5mdKMwJ6myCRGoXQQbQvFFQ7B/+hnHfU/yrOVpiGt6TPAn3qReC4dyDYrzy1hr9UeQh677ig=="], + + "@nivo/scales": ["@nivo/scales@0.79.0", "", { "dependencies": { "d3-scale": "^3.2.3", "d3-time": "^1.0.11", "d3-time-format": "^3.0.0", "lodash": "^4.17.21" } }, "sha512-5fAt5Wejp8yzAk6qmA3KU+celCxNYrrBhfvOi2ECDG8KQi+orbDnrO6qjVF6+ebfOn9az8ZVukcSeGA5HceiMg=="], + + "@nivo/tooltip": ["@nivo/tooltip@0.79.0", "", { "dependencies": { "@react-spring/web": "9.3.1" }, "peerDependencies": { "@nivo/core": "0.79.0" } }, "sha512-hsJsvhDVR9P/QqIEDIttaA6aslR3tU9So1s/k2jMdppL7J9ZH/IrVx9TbIP7jDKmnU5AMIP5uSstXj9JiKLhQA=="], + + "@nivo/voronoi": ["@nivo/voronoi@0.79.0", "", { "dependencies": { "d3-delaunay": "^5.3.0", "d3-scale": "^3.2.3" }, "peerDependencies": { "@nivo/core": "0.79.0", "react": ">= 16.14.0 < 18.0.0" } }, "sha512-0MrY33MBjLPQsgtf6PU+NUeQVib0g5fR9UBWsbO3YdkgDhXNnbXZ4FZlMAznoDSOxQ/efAuP7jWfnemFCpSwUg=="], + + "@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], + + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], + + "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], + + "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], + + "@nolyfill/is-core-module": ["@nolyfill/is-core-module@1.0.39", "", {}, "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA=="], + + "@octokit/app": ["@octokit/app@15.1.0", "", { "dependencies": { "@octokit/auth-app": "^7.0.0", "@octokit/auth-unauthenticated": "^6.0.0", "@octokit/core": "^6.1.2", "@octokit/oauth-app": "^7.0.0", "@octokit/plugin-paginate-rest": "^11.0.0", "@octokit/types": "^13.0.0", "@octokit/webhooks": "^13.0.0" } }, "sha512-TkBr7QgOmE6ORxvIAhDbZsqPkF7RSqTY4pLTtUQCvr6dTXqvi2fFo46q3h1lxlk/sGMQjqyZ0kEahkD/NyzOHg=="], + + "@octokit/auth-app": ["@octokit/auth-app@7.2.2", "", { "dependencies": { "@octokit/auth-oauth-app": "^8.1.4", "@octokit/auth-oauth-user": "^5.1.4", "@octokit/request": "^9.2.3", "@octokit/request-error": "^6.1.8", "@octokit/types": "^14.0.0", "toad-cache": "^3.7.0", "universal-github-app-jwt": "^2.2.0", "universal-user-agent": "^7.0.0" } }, "sha512-p6hJtEyQDCJEPN9ijjhEC/kpFHMHN4Gca9r+8S0S8EJi7NaWftaEmexjxxpT1DFBeJpN4u/5RE22ArnyypupJw=="], + + "@octokit/auth-oauth-app": ["@octokit/auth-oauth-app@8.1.4", "", { "dependencies": { "@octokit/auth-oauth-device": "^7.1.5", "@octokit/auth-oauth-user": "^5.1.4", "@octokit/request": "^9.2.3", "@octokit/types": "^14.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-71iBa5SflSXcclk/OL3lJzdt4iFs56OJdpBGEBl1wULp7C58uiswZLV6TdRaiAzHP1LT8ezpbHlKuxADb+4NkQ=="], + + "@octokit/auth-oauth-device": ["@octokit/auth-oauth-device@7.1.5", "", { "dependencies": { "@octokit/oauth-methods": "^5.1.5", "@octokit/request": "^9.2.3", "@octokit/types": "^14.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-lR00+k7+N6xeECj0JuXeULQ2TSBB/zjTAmNF2+vyGPDEFx1dgk1hTDmL13MjbSmzusuAmuJD8Pu39rjp9jH6yw=="], + + "@octokit/auth-oauth-user": ["@octokit/auth-oauth-user@5.1.6", "", { "dependencies": { "@octokit/auth-oauth-device": "^7.1.5", "@octokit/oauth-methods": "^5.1.5", "@octokit/request": "^9.2.3", "@octokit/types": "^14.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-/R8vgeoulp7rJs+wfJ2LtXEVC7pjQTIqDab7wPKwVG6+2v/lUnCOub6vaHmysQBbb45FknM3tbHW8TOVqYHxCw=="], + + "@octokit/auth-token": ["@octokit/auth-token@5.1.2", "", {}, "sha512-JcQDsBdg49Yky2w2ld20IHAlwr8d/d8N6NiOXbtuoPCqzbsiJgF633mVUw3x4mo0H5ypataQIX7SFu3yy44Mpw=="], + + "@octokit/auth-unauthenticated": ["@octokit/auth-unauthenticated@6.1.3", "", { "dependencies": { "@octokit/request-error": "^6.1.8", "@octokit/types": "^14.0.0" } }, "sha512-d5gWJla3WdSl1yjbfMpET+hUSFCE15qM0KVSB0H1shyuJihf/RL1KqWoZMIaonHvlNojkL9XtLFp8QeLe+1iwA=="], + + "@octokit/core": ["@octokit/core@6.1.6", "", { "dependencies": { "@octokit/auth-token": "^5.0.0", "@octokit/graphql": "^8.2.2", "@octokit/request": "^9.2.3", "@octokit/request-error": "^6.1.8", "@octokit/types": "^14.0.0", "before-after-hook": "^3.0.2", "universal-user-agent": "^7.0.0" } }, "sha512-kIU8SLQkYWGp3pVKiYzA5OSaNF5EE03P/R8zEmmrG6XwOg5oBjXyQVVIauQ0dgau4zYhpZEhJrvIYt6oM+zZZA=="], + + "@octokit/endpoint": ["@octokit/endpoint@10.1.4", "", { "dependencies": { "@octokit/types": "^14.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-OlYOlZIsfEVZm5HCSR8aSg02T2lbUWOsCQoPKfTXJwDzcHQBrVBGdGXb89dv2Kw2ToZaRtudp8O3ZIYoaOjKlA=="], + + "@octokit/graphql": ["@octokit/graphql@8.2.2", "", { "dependencies": { "@octokit/request": "^9.2.3", "@octokit/types": "^14.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-Yi8hcoqsrXGdt0yObxbebHXFOiUA+2v3n53epuOg1QUgOB6c4XzvisBNVXJSl8RYA5KrDuSL2yq9Qmqe5N0ryA=="], + + "@octokit/oauth-app": ["@octokit/oauth-app@7.1.6", "", { "dependencies": { "@octokit/auth-oauth-app": "^8.1.3", "@octokit/auth-oauth-user": "^5.1.3", "@octokit/auth-unauthenticated": "^6.1.2", "@octokit/core": "^6.1.4", "@octokit/oauth-authorization-url": "^7.1.1", "@octokit/oauth-methods": "^5.1.4", "@types/aws-lambda": "^8.10.83", "universal-user-agent": "^7.0.0" } }, "sha512-OMcMzY2WFARg80oJNFwWbY51TBUfLH4JGTy119cqiDawSFXSIBujxmpXiKbGWQlvfn0CxE6f7/+c6+Kr5hI2YA=="], + + "@octokit/oauth-authorization-url": ["@octokit/oauth-authorization-url@7.1.1", "", {}, "sha512-ooXV8GBSabSWyhLUowlMIVd9l1s2nsOGQdlP2SQ4LnkEsGXzeCvbSbCPdZThXhEFzleGPwbapT0Sb+YhXRyjCA=="], + + "@octokit/oauth-methods": ["@octokit/oauth-methods@5.1.5", "", { "dependencies": { "@octokit/oauth-authorization-url": "^7.0.0", "@octokit/request": "^9.2.3", "@octokit/request-error": "^6.1.8", "@octokit/types": "^14.0.0" } }, "sha512-Ev7K8bkYrYLhoOSZGVAGsLEscZQyq7XQONCBBAl2JdMg7IT3PQn/y8P0KjloPoYpI5UylqYrLeUcScaYWXwDvw=="], + + "@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="], + + "@octokit/openapi-webhooks-types": ["@octokit/openapi-webhooks-types@11.0.0", "", {}, "sha512-ZBzCFj98v3SuRM7oBas6BHZMJRadlnDoeFfvm1olVxZnYeU6Vh97FhPxyS5aLh5pN51GYv2I51l/hVUAVkGBlA=="], + + "@octokit/plugin-paginate-rest": ["@octokit/plugin-paginate-rest@11.6.0", "", { "dependencies": { "@octokit/types": "^13.10.0" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-n5KPteiF7pWKgBIBJSk8qzoZWcUkza2O6A0za97pMGVrGfPdltxrfmfF5GucHYvHGZD8BdaZmmHGz5cX/3gdpw=="], + + "@octokit/request": ["@octokit/request@9.2.4", "", { "dependencies": { "@octokit/endpoint": "^10.1.4", "@octokit/request-error": "^6.1.8", "@octokit/types": "^14.0.0", "fast-content-type-parse": "^2.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-q8ybdytBmxa6KogWlNa818r0k1wlqzNC+yNkcQDECHvQo8Vmstrg18JwqJHdJdUiHD2sjlwBgSm9kHkOKe2iyA=="], + + "@octokit/request-error": ["@octokit/request-error@6.1.8", "", { "dependencies": { "@octokit/types": "^14.0.0" } }, "sha512-WEi/R0Jmq+IJKydWlKDmryPcmdYSVjL3ekaiEL1L9eo1sUnqMJ+grqmC9cjk7CA7+b2/T397tO5d8YLOH3qYpQ=="], + + "@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], + + "@octokit/webhooks": ["@octokit/webhooks@13.9.1", "", { "dependencies": { "@octokit/openapi-webhooks-types": "11.0.0", "@octokit/request-error": "^6.1.7", "@octokit/webhooks-methods": "^5.1.1" } }, "sha512-Nss2b4Jyn4wB3EAqAPJypGuCJFalz/ZujKBQQ5934To7Xw9xjf4hkr/EAByxQY7hp7MKd790bWGz7XYSTsHmaw=="], + + "@octokit/webhooks-methods": ["@octokit/webhooks-methods@5.1.1", "", {}, "sha512-NGlEHZDseJTCj8TMMFehzwa9g7On4KJMPVHDSrHxCQumL6uSQR8wIkP/qesv52fXqV1BPf4pTxwtS31ldAt9Xg=="], + + "@octokit/webhooks-types": ["@octokit/webhooks-types@7.5.1", "", {}, "sha512-1dozxWEP8lKGbtEu7HkRbK1F/nIPuJXNfT0gd96y6d3LcHZTtRtlf8xz3nicSJfesADxJyDh+mWBOsdLkqgzYw=="], + + "@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="], + + "@oxc-project/runtime": ["@oxc-project/runtime@0.115.0", "", {}, "sha512-Rg8Wlt5dCbXhQnsXPrkOjL1DTSvXLgb2R/KYfnf1/K+R0k6UMLEmbQXPM+kwrWqSmWA2t0B1EtHy2/3zikQpvQ=="], + + "@oxc-project/types": ["@oxc-project/types@0.115.0", "", {}, "sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw=="], + + "@paralleldrive/cuid2": ["@paralleldrive/cuid2@2.3.1", "", { "dependencies": { "@noble/hashes": "^1.1.5" } }, "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw=="], + + "@pinojs/redact": ["@pinojs/redact@0.4.0", "", {}, "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg=="], + + "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], + + "@popperjs/core": ["@popperjs/core@2.11.8", "", {}, "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="], + + "@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="], + + "@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="], + + "@protobufjs/codegen": ["@protobufjs/codegen@2.0.4", "", {}, "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="], + + "@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.0", "", {}, "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="], + + "@protobufjs/fetch": ["@protobufjs/fetch@1.1.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" } }, "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ=="], + + "@protobufjs/float": ["@protobufjs/float@1.0.2", "", {}, "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="], + + "@protobufjs/inquire": ["@protobufjs/inquire@1.1.0", "", {}, "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="], + + "@protobufjs/path": ["@protobufjs/path@1.1.2", "", {}, "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="], + + "@protobufjs/pool": ["@protobufjs/pool@1.1.0", "", {}, "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="], + + "@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="], + + "@react-aria/ssr": ["@react-aria/ssr@3.9.10", "", { "dependencies": { "@swc/helpers": "^0.5.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-hvTm77Pf+pMBhuBm760Li0BVIO38jv1IBws1xFm1NoL26PU+fe+FMW5+VZWyANR6nYL65joaJKZqOdTQMkO9IQ=="], + + "@react-spring/animated": ["@react-spring/animated@9.3.2", "", { "dependencies": { "@react-spring/shared": "~9.3.0", "@react-spring/types": "~9.3.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0" } }, "sha512-pBvKydRHbTzuyaeHtxGIOvnskZxGo/S5/YK1rtYm88b9NQZuZa95Rgd3O0muFL+99nvBMBL8cvQGD0UJmsqQsg=="], + + "@react-spring/core": ["@react-spring/core@9.3.2", "", { "dependencies": { "@react-spring/animated": "~9.3.0", "@react-spring/shared": "~9.3.0", "@react-spring/types": "~9.3.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0" } }, "sha512-kMRjkgdQ6LJ0lmb/wQlONpghaMT83UxglXHJC6m9kZS/GKVmN//TYMEK85xN1rC5Gg+BmjG61DtLCSkkLDTfNw=="], + + "@react-spring/rafz": ["@react-spring/rafz@9.3.2", "", {}, "sha512-YtqNnAYp5bl6NdnDOD5TcYS40VJmB+Civ4LPtcWuRPKDAOa/XAf3nep48r0wPTmkK936mpX8aIm7h+luW59u5A=="], + + "@react-spring/shared": ["@react-spring/shared@9.3.2", "", { "dependencies": { "@react-spring/rafz": "~9.3.0", "@react-spring/types": "~9.3.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0" } }, "sha512-ypGQQ8w7mWnrELLon4h6mBCBxdd8j1pgLzmHXLpTC/f4ya2wdP+0WIKBWXJymIf+5NiTsXgSJra5SnHP5FBY+A=="], + + "@react-spring/types": ["@react-spring/types@9.3.2", "", {}, "sha512-u+IK9z9Re4hjNkBYKebZr7xVDYTai2RNBsI4UPL/k0B6lCNSwuqWIXfKZUDVlMOeZHtDqayJn4xz6HcSkTj3FQ=="], + + "@react-spring/web": ["@react-spring/web@9.3.1", "", { "dependencies": { "@react-spring/animated": "~9.3.0", "@react-spring/core": "~9.3.0", "@react-spring/shared": "~9.3.0", "@react-spring/types": "~9.3.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0", "react-dom": "^16.8.0 || ^17.0.0" } }, "sha512-sisZIgFGva/Z+xKWPSfXpukF0AP3kR9ALTxlHL87fVotMUCJX5vtH/YlVcywToEFwTHKt3MpI5Wy2M+vgVEeaw=="], + + "@restart/hooks": ["@restart/hooks@0.4.16", "", { "dependencies": { "dequal": "^2.0.3" }, "peerDependencies": { "react": ">=16.8.0" } }, "sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w=="], + + "@restart/ui": ["@restart/ui@1.9.4", "", { "dependencies": { "@babel/runtime": "^7.26.0", "@popperjs/core": "^2.11.8", "@react-aria/ssr": "^3.5.0", "@restart/hooks": "^0.5.0", "@types/warning": "^3.0.3", "dequal": "^2.0.3", "dom-helpers": "^5.2.0", "uncontrollable": "^8.0.4", "warning": "^4.0.3" }, "peerDependencies": { "react": ">=16.14.0", "react-dom": ">=16.14.0" } }, "sha512-N4C7haUc3vn4LTwVUPlkJN8Ach/+yIMvRuTVIhjilNHqegY60SGLrzud6errOMNJwSnmYFnt1J0H/k8FE3A4KA=="], + + "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-rc.9", "", { "os": "android", "cpu": "arm64" }, "sha512-lcJL0bN5hpgJfSIz/8PIf02irmyL43P+j1pTCfbD1DbLkmGRuFIA4DD3B3ZOvGqG0XiVvRznbKtN0COQVaKUTg=="], + + "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-rc.9", "", { "os": "darwin", "cpu": "arm64" }, "sha512-J7Zk3kLYFsLtuH6U+F4pS2sYVzac0qkjcO5QxHS7OS7yZu2LRs+IXo+uvJ/mvpyUljDJ3LROZPoQfgBIpCMhdQ=="], + + "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.0-rc.9", "", { "os": "darwin", "cpu": "x64" }, "sha512-iwtmmghy8nhfRGeNAIltcNXzD0QMNaaA5U/NyZc1Ia4bxrzFByNMDoppoC+hl7cDiUq5/1CnFthpT9n+UtfFyg=="], + + "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.0-rc.9", "", { "os": "freebsd", "cpu": "x64" }, "sha512-DLFYI78SCiZr5VvdEplsVC2Vx53lnA4/Ga5C65iyldMVaErr86aiqCoNBLl92PXPfDtUYjUh+xFFor40ueNs4Q=="], + + "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.9", "", { "os": "linux", "cpu": "arm" }, "sha512-CsjTmTwd0Hri6iTw/DRMK7kOZ7FwAkrO4h8YWKoX/kcj833e4coqo2wzIFywtch/8Eb5enQ/lwLM7w6JX1W5RQ=="], + + "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.0-rc.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-2x9O2JbSPxpxMDhP9Z74mahAStibTlrBMW0520+epJH5sac7/LwZW5Bmg/E6CXuEF53JJFW509uP+lSedaUNxg=="], + + "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.0-rc.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-JA1QRW31ogheAIRhIg9tjMfsYbglXXYGNPLdPEYrwFxdbkQCAzvpSCSHCDWNl4hTtrol8WeboCSEpjdZK8qrCg=="], + + "@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.9", "", { "os": "linux", "cpu": "ppc64" }, "sha512-aOKU9dJheda8Kj8Y3w9gnt9QFOO+qKPAl8SWd7JPHP+Cu0EuDAE5wokQubLzIDQWg2myXq2XhTpOVS07qqvT+w=="], + + "@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.0.0-rc.9", "", { "os": "linux", "cpu": "s390x" }, "sha512-OalO94fqj7IWRn3VdXWty75jC5dk4C197AWEuMhIpvVv2lw9fiPhud0+bW2ctCxb3YoBZor71QHbY+9/WToadA=="], + + "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.0-rc.9", "", { "os": "linux", "cpu": "x64" }, "sha512-cVEl1vZtBsBZna3YMjGXNvnYYrOJ7RzuWvZU0ffvJUexWkukMaDuGhUXn0rjnV0ptzGVkvc+vW9Yqy6h8YX4pg=="], + + "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.0-rc.9", "", { "os": "linux", "cpu": "x64" }, "sha512-UzYnKCIIc4heAKgI4PZ3dfBGUZefGCJ1TPDuLHoCzgrMYPb5Rv6TLFuYtyM4rWyHM7hymNdsg5ik2C+UD9VDbA=="], + + "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.0-rc.9", "", { "os": "none", "cpu": "arm64" }, "sha512-+6zoiF+RRyf5cdlFQP7nm58mq7+/2PFaY2DNQeD4B87N36JzfF/l9mdBkkmTvSYcYPE8tMh/o3cRlsx1ldLfog=="], + + "@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.0-rc.9", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.1.1" }, "cpu": "none" }, "sha512-rgFN6sA/dyebil3YTlL2evvi/M+ivhfnyxec7AccTpRPccno/rPoNlqybEZQBkcbZu8Hy+eqNJCqfBR8P7Pg8g=="], + + "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.0-rc.9", "", { "os": "win32", "cpu": "arm64" }, "sha512-lHVNUG/8nlF1IQk1C0Ci574qKYyty2goMiPlRqkC5R+3LkXDkL5Dhx8ytbxq35m+pkHVIvIxviD+TWLdfeuadA=="], + + "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.0-rc.9", "", { "os": "win32", "cpu": "x64" }, "sha512-G0oA4+w1iY5AGi5HcDTxWsoxF509hrFIPB2rduV5aDqS9FtDg1CAfa7V34qImbjfhIcA8C+RekocJZA96EarwQ=="], + + "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.7", "", {}, "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA=="], + + "@rollup/pluginutils": ["@rollup/pluginutils@4.2.1", "", { "dependencies": { "estree-walker": "^2.0.1", "picomatch": "^2.2.2" } }, "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ=="], + + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.59.0", "", { "os": "android", "cpu": "arm" }, "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg=="], + + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.59.0", "", { "os": "android", "cpu": "arm64" }, "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q=="], + + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.59.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg=="], + + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.59.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w=="], + + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.59.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA=="], + + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.59.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg=="], + + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.59.0", "", { "os": "linux", "cpu": "arm" }, "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw=="], + + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.59.0", "", { "os": "linux", "cpu": "arm" }, "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA=="], + + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.59.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA=="], + + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.59.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA=="], + + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg=="], + + "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q=="], + + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.59.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA=="], + + "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.59.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA=="], + + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg=="], + + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg=="], + + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.59.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w=="], + + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.59.0", "", { "os": "linux", "cpu": "x64" }, "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg=="], + + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.59.0", "", { "os": "linux", "cpu": "x64" }, "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg=="], + + "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.59.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ=="], + + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.59.0", "", { "os": "none", "cpu": "arm64" }, "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA=="], + + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.59.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A=="], + + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.59.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA=="], + + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.59.0", "", { "os": "win32", "cpu": "x64" }, "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA=="], + + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.59.0", "", { "os": "win32", "cpu": "x64" }, "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA=="], + + "@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="], + + "@sapphire/async-queue": ["@sapphire/async-queue@1.5.5", "", {}, "sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg=="], + + "@sapphire/snowflake": ["@sapphire/snowflake@1.3.6", "", {}, "sha512-QnzuLp+p9D7agynVub/zqlDVriDza9y3STArBhNiNBUgIX8+GL5FpQxstRfw1jDr5jkZUjcuKYAHxjIuXKdJAg=="], + + "@sindresorhus/is": ["@sindresorhus/is@4.6.0", "", {}, "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw=="], + + "@smithy/types": ["@smithy/types@4.13.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-COuLsZILbbQsdrwKQpkkpyep7lCsByxwj7m0Mg5v66/ZTyenlfBc40/QFQ5chO0YN/PNEH1Bi3fGtfXPnYNeDw=="], + + "@so-ric/colorspace": ["@so-ric/colorspace@1.1.6", "", { "dependencies": { "color": "^5.0.2", "text-hex": "1.0.x" } }, "sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw=="], + + "@swc/helpers": ["@swc/helpers@0.5.19", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-QamiFeIK3txNjgUTNppE6MiG3p7TdninpZu0E0PbqVh1a9FNLT2FRhisaa4NcaX52XVhA5l7Pk58Ft7Sqi/2sA=="], + + "@tsconfig/node10": ["@tsconfig/node10@1.0.12", "", {}, "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ=="], + + "@tsconfig/node12": ["@tsconfig/node12@1.0.11", "", {}, "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag=="], + + "@tsconfig/node14": ["@tsconfig/node14@1.0.3", "", {}, "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow=="], + + "@tsconfig/node16": ["@tsconfig/node16@1.0.4", "", {}, "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA=="], + + "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], + + "@types/aws-lambda": ["@types/aws-lambda@8.10.161", "", {}, "sha512-rUYdp+MQwSFocxIOcSsYSF3YYYC/uUpMbCY/mbO21vGqfrEYvNSoPyKYDj6RhXXpPfS0KstW9RwG3qXh9sL7FQ=="], + + "@types/bcryptjs": ["@types/bcryptjs@2.4.6", "", {}, "sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ=="], + + "@types/body-parser": ["@types/body-parser@1.19.6", "", { "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g=="], + + "@types/bson": ["@types/bson@1.0.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-j+UcCWI+FsbI5/FQP/Kj2CXyplWAz39ktHFkXk84h7dNblKRSoNJs95PZFRd96NQGqsPEPgeclqnznWZr14ZDA=="], + + "@types/bunyan": ["@types/bunyan@1.8.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-758fRH7umIMk5qt5ELmRMff4mLDlN+xyYzC+dkPTdKwbSkJFvz6xwyScrytPU0QIBbRRwbiE8/BIg8bpajerNQ=="], + + "@types/chai": ["@types/chai@5.2.3", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="], + + "@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="], + + "@types/connect-redis": ["@types/connect-redis@0.0.18", "", { "dependencies": { "@types/express": "*", "@types/express-session": "*", "@types/ioredis": "*", "@types/redis": "^2.8.0" } }, "sha512-iGygGbXgPIr94DEAuoluWhzre3c2/ew5NPlbW9IWvwCTXMM1YCmc7M9wpXMkYqt6kB9aO1sjZnmDzyugUu+2vQ=="], + + "@types/cookiejar": ["@types/cookiejar@2.1.5", "", {}, "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q=="], + + "@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="], + + "@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="], + + "@types/eslint": ["@types/eslint@9.6.1", "", { "dependencies": { "@types/estree": "*", "@types/json-schema": "*" } }, "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag=="], + + "@types/eslint__js": ["@types/eslint__js@8.42.3", "", { "dependencies": { "@types/eslint": "*" } }, "sha512-alfG737uhmPdnvkrLdZLcEKJ/B8s9Y4hrZ+YAdzUeoArBlSUERA2E87ROfOaS4jd/C45fzOoZzidLc1IPwLqOw=="], + + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + + "@types/express": ["@types/express@4.17.13", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.18", "@types/qs": "*", "@types/serve-static": "*" } }, "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA=="], + + "@types/express-rate-limit": ["@types/express-rate-limit@5.1.3", "", { "dependencies": { "@types/express": "*" } }, "sha512-H+TYy3K53uPU2TqPGFYaiWc2xJV6+bIFkDd/Ma2/h67Pa6ARk9kWE0p/K9OH1Okm0et9Sfm66fmXoAxsH2PHXg=="], + + "@types/express-serve-static-core": ["@types/express-serve-static-core@4.17.29", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*" } }, "sha512-uMd++6dMKS32EOuw1Uli3e3BPgdLIXmezcfHv7N4c1s3gkhikBplORPpMq3fuWkxncZN1reb16d5n8yhQ80x7Q=="], + + "@types/express-session": ["@types/express-session@1.17.4", "", { "dependencies": { "@types/express": "*" } }, "sha512-7cNlSI8+oOBUHTfPXMwDxF/Lchx5aJ3ho7+p9jJZYVg9dVDJFh3qdMXmJtRsysnvS+C6x46k9DRYmrmCkE+MVg=="], + + "@types/glob": ["@types/glob@7.2.0", "", { "dependencies": { "@types/minimatch": "*", "@types/node": "*" } }, "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA=="], + + "@types/google-protobuf": ["@types/google-protobuf@3.15.12", "", {}, "sha512-40um9QqwHjRS92qnOaDpL7RmDK15NuZYo9HihiJRbYkMQZlWnuH8AdvbMy8/o6lgLmKbDUKa+OALCltHdbOTpQ=="], + + "@types/hast": ["@types/hast@2.3.10", "", { "dependencies": { "@types/unist": "^2" } }, "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw=="], + + "@types/history": ["@types/history@4.7.11", "", {}, "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA=="], + + "@types/http-errors": ["@types/http-errors@2.0.5", "", {}, "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg=="], + + "@types/humanize-duration": ["@types/humanize-duration@3.27.4", "", {}, "sha512-yaf7kan2Sq0goxpbcwTQ+8E9RP6HutFBPv74T/IA/ojcHKhuKVlk2YFYyHhWZeLvZPzzLE3aatuQB4h0iqyyUA=="], + + "@types/ioredis": ["@types/ioredis@5.0.0", "", { "dependencies": { "ioredis": "*" } }, "sha512-zJbJ3FVE17CNl5KXzdeSPtdltc4tMT3TzC6fxQS0sQngkbFZ6h+0uTafsRqu+eSLIugf6Yb0Ea0SUuRr42Nk9g=="], + + "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], + + "@types/json5": ["@types/json5@2.2.0", "", { "dependencies": { "json5": "*" } }, "sha512-NrVug5woqbvNZ0WX+Gv4R+L4TGddtmFek2u8RtccAgFZWtS9QXF2xCXY22/M4nzkaKF0q9Fc6M/5rxLDhfwc/A=="], + + "@types/lodash": ["@types/lodash@4.14.172", "", {}, "sha512-/BHF5HAx3em7/KkzVKm3LrsD6HZAXuXO1AJZQ3cRRBZj4oHZDviWPYu0aEplAqDFNHZPW6d3G7KN+ONcCCC7pw=="], + + "@types/lodash.get": ["@types/lodash.get@4.4.9", "", { "dependencies": { "@types/lodash": "*" } }, "sha512-J5dvW98sxmGnamqf+/aLP87PYXyrha9xIgc2ZlHl6OHMFR2Ejdxep50QfU0abO1+CH6+ugx+8wEUN1toImAinA=="], + + "@types/luxon": ["@types/luxon@2.4.0", "", {}, "sha512-oCavjEjRXuR6URJEtQm0eBdfsBiEcGBZbq21of8iGkeKxU1+1xgKuFPClaBZl2KB8ZZBSWlgk61tH6Mf+nvZVw=="], + + "@types/mdast": ["@types/mdast@3.0.15", "", { "dependencies": { "@types/unist": "^2" } }, "sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ=="], + + "@types/mdurl": ["@types/mdurl@1.0.5", "", {}, "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA=="], + + "@types/methods": ["@types/methods@1.1.4", "", {}, "sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ=="], + + "@types/minimatch": ["@types/minimatch@6.0.0", "", { "dependencies": { "minimatch": "*" } }, "sha512-zmPitbQ8+6zNutpwgcQuLcsEpn/Cj54Kbn7L5pX0Os5kdWplB7xPgEh/g+SWOB/qmows2gpuCaPyduq8ZZRnxA=="], + + "@types/mkdirp": ["@types/mkdirp@1.0.2", "", { "dependencies": { "@types/node": "*" } }, "sha512-o0K1tSO0Dx5X6xlU5F1D6625FawhC3dU3iqr25lluNv/+/QIVH8RLNEiVokgIZo+mz+87w/3Mkg/VvQS+J51fQ=="], + + "@types/mongodb": ["@types/mongodb@3.6.20", "", { "dependencies": { "@types/bson": "*", "@types/node": "*" } }, "sha512-WcdpPJCakFzcWWD9juKoZbRtQxKIMYF/JIAM4JrNHrMcnJL6/a2NWjXxW7fo9hxboxxkg+icff8d7+WIEvKgYQ=="], + + "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], + + "@types/multer": ["@types/multer@1.4.7", "", { "dependencies": { "@types/express": "*" } }, "sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA=="], + + "@types/natural-compare": ["@types/natural-compare@1.4.3", "", {}, "sha512-XCAxy+Gg6+S6VagwzcknnvCKujj/bVv1q+GFuCrFEelqaZPqJoC+FeXLwc2dp+oLP7qDZQ4ZfQiTJQ9sIUmlLw=="], + + "@types/node": ["@types/node@20.19.37", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw=="], + + "@types/node-fetch": ["@types/node-fetch@2.5.12", "", { "dependencies": { "@types/node": "*", "form-data": "^3.0.0" } }, "sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw=="], + + "@types/nodemailer": ["@types/nodemailer@6.4.23", "", { "dependencies": { "@types/node": "*" } }, "sha512-aFV3/NsYFLSx9mbb5gtirBSXJnAlrusoKNuPbxsASWc7vrKLmIrTQRpdcxNcSFL3VW2A2XpeLEavwb2qMi6nlQ=="], + + "@types/parse-json": ["@types/parse-json@4.0.2", "", {}, "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw=="], + + "@types/pg": ["@types/pg@8.18.0", "", { "dependencies": { "@types/node": "*", "pg-protocol": "*", "pg-types": "^2.2.0" } }, "sha512-gT+oueVQkqnj6ajGJXblFR4iavIXWsGAFCk3dP4Kki5+a9R4NMt0JARdk6s8cUKcfUoqP5dAtDSLU8xYUTFV+Q=="], + + "@types/prop-types": ["@types/prop-types@15.7.15", "", {}, "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw=="], + + "@types/qs": ["@types/qs@6.15.0", "", {}, "sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow=="], + + "@types/range-parser": ["@types/range-parser@1.2.7", "", {}, "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ=="], + + "@types/rate-limit-redis": ["@types/rate-limit-redis@1.7.4", "", { "dependencies": { "@types/express-rate-limit": "3", "@types/ioredis": "*", "@types/redis": "^2.8.0" } }, "sha512-TDsh9CJHHhx+sGHlqF6MI+PgEv91o/wQ67e2IR02ebYPzWQ8Rk0pcVY+WBy2pjxa+cAkPwjcOFDd21VToKaOzQ=="], + + "@types/react": ["@types/react@17.0.13", "", { "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", "csstype": "^3.0.2" } }, "sha512-D/G3PiuqTfE3IMNjLn/DCp6umjVCSvtZTPdtAFy5+Ved6CsdRvivfKeCzw79W4AatShtU4nGqgvOv5Gro534vQ=="], + + "@types/react-dom": ["@types/react-dom@17.0.8", "", { "dependencies": { "@types/react": "*" } }, "sha512-0ohAiJAx1DAUEcY9UopnfwCE9sSMDGnY/oXjWMax6g3RpzmTt2GMyMVAXcbn0mo8XAff0SbQJl2/SBU+hjSZ1A=="], + + "@types/react-google-recaptcha": ["@types/react-google-recaptcha@2.1.2", "", { "dependencies": { "@types/react": "*" } }, "sha512-Zeb0pwDeXHYIQy5mNgewMr+jf4xtrjSHTdJW8wrubNB6sNEaxqo8yk02HVpwy7p7Hzh5y6iSz6gKoPonVBlswQ=="], + + "@types/react-router": ["@types/react-router@5.1.20", "", { "dependencies": { "@types/history": "^4.7.11", "@types/react": "*" } }, "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q=="], + + "@types/react-router-bootstrap": ["@types/react-router-bootstrap@0.26.1", "", { "dependencies": { "@types/react": "*" } }, "sha512-EdgZn/PmSA8+I0RW6WyDUgBvkVXc8AmbbgOJ8WJfec1R/V06X++OrIOzwzdgYl4g3uXvEB6oEIxzcjx1/8Opqw=="], + + "@types/react-router-dom": ["@types/react-router-dom@5.1.7", "", { "dependencies": { "@types/history": "*", "@types/react": "*", "@types/react-router": "*" } }, "sha512-D5mHD6TbdV/DNHYsnwBTv+y73ei+mMjrkGrla86HthE4/PVvL1J94Bu3qABU+COXzpL23T1EZapVVpwHuBXiUg=="], + + "@types/react-transition-group": ["@types/react-transition-group@4.4.12", "", { "peerDependencies": { "@types/react": "*" } }, "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w=="], + + "@types/redis": ["@types/redis@2.8.32", "", { "dependencies": { "@types/node": "*" } }, "sha512-7jkMKxcGq9p242exlbsVzuJb57KqHRhNl4dHoQu2Y5v9bCAbtIXXH0R3HleSQW4CTOqpHIYUW3t6tpUj4BVQ+w=="], + + "@types/rimraf": ["@types/rimraf@3.0.2", "", { "dependencies": { "@types/glob": "*", "@types/node": "*" } }, "sha512-F3OznnSLAUxFrCEu/L5PY8+ny8DtcFRjx7fZZ9bycvXRi3KPTRS9HOitGZwvPg0juRhXFWIeKX58cnX5YqLohQ=="], + + "@types/safe-json-stringify": ["@types/safe-json-stringify@1.1.2", "", {}, "sha512-Hj/LZMBXFH3Qj9sNmNu6syBpkZqBaM00HgP7naf9CnZhB3kdxmrenWUD2cY6vvTWjuBM3NPOLknPKDUOQuTWXA=="], + + "@types/scheduler": ["@types/scheduler@0.26.0", "", {}, "sha512-WFHp9YUJQ6CKshqoC37iOlHnQSmxNc795UhB26CyBBttrN9svdIrUjl/NjnNmfcwtncN0h/0PPAFWv9ovP8mLA=="], + + "@types/semver": ["@types/semver@7.7.1", "", {}, "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA=="], + + "@types/serve-static": ["@types/serve-static@2.2.0", "", { "dependencies": { "@types/http-errors": "*", "@types/node": "*" } }, "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ=="], + + "@types/superagent": ["@types/superagent@8.1.9", "", { "dependencies": { "@types/cookiejar": "^2.1.5", "@types/methods": "^1.1.4", "@types/node": "*", "form-data": "^4.0.0" } }, "sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ=="], + + "@types/supertest": ["@types/supertest@2.0.11", "", { "dependencies": { "@types/superagent": "*" } }, "sha512-uci4Esokrw9qGb9bvhhSVEjd6rkny/dk5PK/Qz4yxKiyppEI+dOPlNrZBahE3i+PoKFYyDxChVXZ/ysS/nrm1Q=="], + + "@types/tap": ["@types/tap@15.0.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-usOLtmMm1jfjPdkt9R9HMTU/J6m9QNYjgFs5U2tFiOzQSd7lDd/aAMprExYLnJnZb6tM4ujmGv7ITe+1smIRgg=="], + + "@types/triple-beam": ["@types/triple-beam@1.3.5", "", {}, "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw=="], + + "@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], + + "@types/warning": ["@types/warning@3.0.3", "", {}, "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q=="], + + "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], + + "@types/yoga-layout": ["@types/yoga-layout@1.9.2", "", {}, "sha512-S9q47ByT2pPvD65IvrWp7qppVMpk9WGMbVq9wbWZOHg6tnXSD4vyhao6nOSBwwfDdV2p3Kx9evA9vI+XWTfDvw=="], + + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@4.33.0", "", { "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" }, "peerDependencies": { "@typescript-eslint/parser": "^4.0.0", "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg=="], + + "@typescript-eslint/experimental-utils": ["@typescript-eslint/experimental-utils@4.33.0", "", { "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" }, "peerDependencies": { "eslint": "*" } }, "sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q=="], + + "@typescript-eslint/parser": ["@typescript-eslint/parser@4.33.0", "", { "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" }, "peerDependencies": { "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA=="], + + "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.56.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.56.1", "@typescript-eslint/types": "^8.56.1", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ=="], + + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@4.33.0", "", { "dependencies": { "@typescript-eslint/types": "4.33.0", "@typescript-eslint/visitor-keys": "4.33.0" } }, "sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ=="], + + "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.56.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ=="], + + "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.56.1", "", { "dependencies": { "@typescript-eslint/types": "8.56.1", "@typescript-eslint/typescript-estree": "8.56.1", "@typescript-eslint/utils": "8.56.1", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg=="], + + "@typescript-eslint/types": ["@typescript-eslint/types@4.33.0", "", {}, "sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ=="], + + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@4.33.0", "", { "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" } }, "sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA=="], + + "@typescript-eslint/utils": ["@typescript-eslint/utils@8.56.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.56.1", "@typescript-eslint/types": "8.56.1", "@typescript-eslint/typescript-estree": "8.56.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA=="], + + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@4.33.0", "", { "dependencies": { "@typescript-eslint/types": "4.33.0", "eslint-visitor-keys": "^2.0.0" } }, "sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg=="], + + "@typescript/native-preview": ["@typescript/native-preview@7.0.0-dev.20260309.1", "", { "optionalDependencies": { "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260309.1", "@typescript/native-preview-darwin-x64": "7.0.0-dev.20260309.1", "@typescript/native-preview-linux-arm": "7.0.0-dev.20260309.1", "@typescript/native-preview-linux-arm64": "7.0.0-dev.20260309.1", "@typescript/native-preview-linux-x64": "7.0.0-dev.20260309.1", "@typescript/native-preview-win32-arm64": "7.0.0-dev.20260309.1", "@typescript/native-preview-win32-x64": "7.0.0-dev.20260309.1" }, "bin": { "tsgo": "bin/tsgo.js" } }, "sha512-ZK+ExK7scBzUCAXCTtAwUm6QENJ+l3tCDQXNCly4WcGUvbIAWdaiNns4brganGN9nrxxRkC9Rx0CrxvIsn9zHA=="], + + "@typescript/native-preview-darwin-arm64": ["@typescript/native-preview-darwin-arm64@7.0.0-dev.20260309.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Vszk6vbONyyT47mUTEFNAXk+bJisM8F0pI+MyNPM8i2oorex7Gbp7ivFUGzdZHRFPDXMrlw6AXmgx1U2tZxiHw=="], + + "@typescript/native-preview-darwin-x64": ["@typescript/native-preview-darwin-x64@7.0.0-dev.20260309.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-UmmW/L1fW6URMILx5HqxcL2kElOyTYbY6M8yRMQK7gmBzsbkGj37JYN+WZgPkz/PQCVsxwIFcot6WmKRRXeBxQ=="], + + "@typescript/native-preview-linux-arm": ["@typescript/native-preview-linux-arm@7.0.0-dev.20260309.1", "", { "os": "linux", "cpu": "arm" }, "sha512-G5zgoOZP2NjZ1kga9mend2in1e3C+Mm3XufelVZ9RwWRka744s6KxAsen853LizCrxBh58foj9pPVnH6gKUJvg=="], + + "@typescript/native-preview-linux-arm64": ["@typescript/native-preview-linux-arm64@7.0.0-dev.20260309.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-sN5rQRvqre8JHUISJhybUQ1e4a+mb/Ifa+uWHJawJ2tojTXWkU1rJTZBnAN3/XeoIJgeSdaZQAZRDlW9B7zbvw=="], + + "@typescript/native-preview-linux-x64": ["@typescript/native-preview-linux-x64@7.0.0-dev.20260309.1", "", { "os": "linux", "cpu": "x64" }, "sha512-ZuHu9Sg4/akGSrO49hKLNKwrFXx7AZ2CS3PcTd85cC4nKudqB1aGD9rHxZZZyClj++e0qcNQ+4eTMn1sxDA9VQ=="], + + "@typescript/native-preview-win32-arm64": ["@typescript/native-preview-win32-arm64@7.0.0-dev.20260309.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-RNIidoGPsRaALc1znXiWfNARkGptm9e55qYnaz11YPvMrqbRKP9Y6Ipx4Oh/diIeF7y9UYiikeyk7EsyKe//sw=="], + + "@typescript/native-preview-win32-x64": ["@typescript/native-preview-win32-x64@7.0.0-dev.20260309.1", "", { "os": "win32", "cpu": "x64" }, "sha512-/rEvAKowcoEdL2VeNju8apkGHEmbat10jIn1Sncny1zIaWvaMFw6bhmny+kKwX+9deitMfo9ihLlo5GCPJuMPQ=="], + + "@unrs/resolver-binding-android-arm-eabi": ["@unrs/resolver-binding-android-arm-eabi@1.11.1", "", { "os": "android", "cpu": "arm" }, "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw=="], + + "@unrs/resolver-binding-android-arm64": ["@unrs/resolver-binding-android-arm64@1.11.1", "", { "os": "android", "cpu": "arm64" }, "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g=="], + + "@unrs/resolver-binding-darwin-arm64": ["@unrs/resolver-binding-darwin-arm64@1.11.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g=="], + + "@unrs/resolver-binding-darwin-x64": ["@unrs/resolver-binding-darwin-x64@1.11.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ=="], + + "@unrs/resolver-binding-freebsd-x64": ["@unrs/resolver-binding-freebsd-x64@1.11.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw=="], + + "@unrs/resolver-binding-linux-arm-gnueabihf": ["@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1", "", { "os": "linux", "cpu": "arm" }, "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw=="], + + "@unrs/resolver-binding-linux-arm-musleabihf": ["@unrs/resolver-binding-linux-arm-musleabihf@1.11.1", "", { "os": "linux", "cpu": "arm" }, "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw=="], + + "@unrs/resolver-binding-linux-arm64-gnu": ["@unrs/resolver-binding-linux-arm64-gnu@1.11.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ=="], + + "@unrs/resolver-binding-linux-arm64-musl": ["@unrs/resolver-binding-linux-arm64-musl@1.11.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w=="], + + "@unrs/resolver-binding-linux-ppc64-gnu": ["@unrs/resolver-binding-linux-ppc64-gnu@1.11.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA=="], + + "@unrs/resolver-binding-linux-riscv64-gnu": ["@unrs/resolver-binding-linux-riscv64-gnu@1.11.1", "", { "os": "linux", "cpu": "none" }, "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ=="], + + "@unrs/resolver-binding-linux-riscv64-musl": ["@unrs/resolver-binding-linux-riscv64-musl@1.11.1", "", { "os": "linux", "cpu": "none" }, "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew=="], + + "@unrs/resolver-binding-linux-s390x-gnu": ["@unrs/resolver-binding-linux-s390x-gnu@1.11.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg=="], + + "@unrs/resolver-binding-linux-x64-gnu": ["@unrs/resolver-binding-linux-x64-gnu@1.11.1", "", { "os": "linux", "cpu": "x64" }, "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w=="], + + "@unrs/resolver-binding-linux-x64-musl": ["@unrs/resolver-binding-linux-x64-musl@1.11.1", "", { "os": "linux", "cpu": "x64" }, "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA=="], + + "@unrs/resolver-binding-wasm32-wasi": ["@unrs/resolver-binding-wasm32-wasi@1.11.1", "", { "dependencies": { "@napi-rs/wasm-runtime": "^0.2.11" }, "cpu": "none" }, "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ=="], + + "@unrs/resolver-binding-win32-arm64-msvc": ["@unrs/resolver-binding-win32-arm64-msvc@1.11.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw=="], + + "@unrs/resolver-binding-win32-ia32-msvc": ["@unrs/resolver-binding-win32-ia32-msvc@1.11.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ=="], + + "@unrs/resolver-binding-win32-x64-msvc": ["@unrs/resolver-binding-win32-x64-msvc@1.11.1", "", { "os": "win32", "cpu": "x64" }, "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g=="], + + "@valuabletouch/winston-seq": ["@valuabletouch/winston-seq@1.3.0", "", { "dependencies": { "seq-logging": "^1.1.1", "winston-transport": "^4.4.0" } }, "sha512-j6oHAXTTdhwUap0VJGHIwiKhbw9IffOWYMrMI1Y2uXStNCNSnwIHYHHfjDw46hrynbVN838DRR+voGtYEvzF1w=="], + + "@vitejs/plugin-react": ["@vitejs/plugin-react@6.0.1", "", { "dependencies": { "@rolldown/pluginutils": "1.0.0-rc.7" }, "peerDependencies": { "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", "babel-plugin-react-compiler": "^1.0.0", "vite": "^8.0.0" }, "optionalPeers": ["@rolldown/plugin-babel", "babel-plugin-react-compiler"] }, "sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ=="], + + "@vitest/coverage-v8": ["@vitest/coverage-v8@3.2.4", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "@bcoe/v8-coverage": "^1.0.2", "ast-v8-to-istanbul": "^0.3.3", "debug": "^4.4.1", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", "istanbul-lib-source-maps": "^5.0.6", "istanbul-reports": "^3.1.7", "magic-string": "^0.30.17", "magicast": "^0.3.5", "std-env": "^3.9.0", "test-exclude": "^7.0.1", "tinyrainbow": "^2.0.0" }, "peerDependencies": { "@vitest/browser": "3.2.4", "vitest": "3.2.4" }, "optionalPeers": ["@vitest/browser"] }, "sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ=="], + + "@vitest/expect": ["@vitest/expect@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig=="], + + "@vitest/mocker": ["@vitest/mocker@3.2.4", "", { "dependencies": { "@vitest/spy": "3.2.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "optionalPeers": ["msw", "vite"] }, "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ=="], + + "@vitest/pretty-format": ["@vitest/pretty-format@3.2.4", "", { "dependencies": { "tinyrainbow": "^2.0.0" } }, "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA=="], + + "@vitest/runner": ["@vitest/runner@3.2.4", "", { "dependencies": { "@vitest/utils": "3.2.4", "pathe": "^2.0.3", "strip-literal": "^3.0.0" } }, "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ=="], + + "@vitest/snapshot": ["@vitest/snapshot@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "magic-string": "^0.30.17", "pathe": "^2.0.3" } }, "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ=="], + + "@vitest/spy": ["@vitest/spy@3.2.4", "", { "dependencies": { "tinyspy": "^4.0.3" } }, "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw=="], + + "@vitest/utils": ["@vitest/utils@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" } }, "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA=="], + + "abbrev": ["abbrev@3.0.1", "", {}, "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg=="], + + "abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="], + + "accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="], + + "acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="], + + "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], + + "acorn-walk": ["acorn-walk@8.3.5", "", { "dependencies": { "acorn": "^8.11.0" } }, "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw=="], + + "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], + + "aggregate-error": ["aggregate-error@3.1.0", "", { "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" } }, "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA=="], + + "ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="], + + "ansi-escapes": ["ansi-escapes@4.3.2", "", { "dependencies": { "type-fest": "^0.21.3" } }, "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ=="], + + "ansi-regex": ["ansi-regex@4.1.1", "", {}, "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="], + + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "ansicolors": ["ansicolors@0.3.2", "", {}, "sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg=="], + + "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], + + "api-parity": ["api-parity@workspace:typescript/api-parity"], + + "append-field": ["append-field@1.0.0", "", {}, "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw=="], + + "append-transform": ["append-transform@2.0.0", "", { "dependencies": { "default-require-extensions": "^3.0.0" } }, "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg=="], + + "archy": ["archy@1.0.0", "", {}, "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw=="], + + "arg": ["arg@4.1.3", "", {}, "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA=="], + + "argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], + + "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], + + "array-buffer-byte-length": ["array-buffer-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "is-array-buffer": "^3.0.5" } }, "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw=="], + + "array-flatten": ["array-flatten@1.1.1", "", {}, "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="], + + "array-includes": ["array-includes@3.1.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.24.0", "es-object-atoms": "^1.1.1", "get-intrinsic": "^1.3.0", "is-string": "^1.1.1", "math-intrinsics": "^1.1.0" } }, "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ=="], + + "array-union": ["array-union@2.1.0", "", {}, "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="], + + "array.prototype.findlast": ["array.prototype.findlast@1.2.5", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-shim-unscopables": "^1.0.2" } }, "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ=="], + + "array.prototype.findlastindex": ["array.prototype.findlastindex@1.2.6", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-shim-unscopables": "^1.1.0" } }, "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ=="], + + "array.prototype.flat": ["array.prototype.flat@1.3.3", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-shim-unscopables": "^1.0.2" } }, "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg=="], + + "array.prototype.flatmap": ["array.prototype.flatmap@1.3.3", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-shim-unscopables": "^1.0.2" } }, "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg=="], + + "array.prototype.tosorted": ["array.prototype.tosorted@1.1.4", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.3", "es-errors": "^1.3.0", "es-shim-unscopables": "^1.0.2" } }, "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA=="], + + "arraybuffer.prototype.slice": ["arraybuffer.prototype.slice@1.0.4", "", { "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "is-array-buffer": "^3.0.4" } }, "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ=="], + + "arrify": ["arrify@2.0.1", "", {}, "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug=="], + + "asap": ["asap@2.0.6", "", {}, "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="], + + "asn1": ["asn1@0.2.6", "", { "dependencies": { "safer-buffer": "~2.1.0" } }, "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ=="], + + "assert-plus": ["assert-plus@1.0.0", "", {}, "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw=="], + + "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="], + + "ast-types-flow": ["ast-types-flow@0.0.8", "", {}, "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ=="], + + "ast-v8-to-istanbul": ["ast-v8-to-istanbul@0.3.12", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.31", "estree-walker": "^3.0.3", "js-tokens": "^10.0.0" } }, "sha512-BRRC8VRZY2R4Z4lFIL35MwNXmwVqBityvOIwETtsCSwvjl0IdgFsy9NhdaA6j74nUdtJJlIypeRhpDam19Wq3g=="], + + "astral-regex": ["astral-regex@2.0.0", "", {}, "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ=="], + + "async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="], + + "async-exit-hook": ["async-exit-hook@2.0.1", "", {}, "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw=="], + + "async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="], + + "async-hook-domain": ["async-hook-domain@2.0.4", "", {}, "sha512-14LjCmlK1PK8eDtTezR6WX8TMaYNIzBIsd2D1sGoGjgx0BuNMMoSdk7i/drlbtamy0AWv9yv2tkB+ASdmeqFIw=="], + + "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], + + "atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="], + + "auto-bind": ["auto-bind@4.0.0", "", {}, "sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ=="], + + "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], + + "aws-crt": ["aws-crt@1.29.1", "", { "dependencies": { "@aws-sdk/util-utf8-browser": "^3.259.0", "@httptoolkit/websocket-stream": "^6.0.1", "axios": "^1.12.2", "buffer": "^6.0.3", "crypto-js": "^4.2.0", "mqtt": "^4.3.8", "process": "^0.11.10" } }, "sha512-YeuwHbh9SjRkMpaY6hXi8NzNn2yjuwEen8Vg/Wasg4hOoqiwxINwX3g7LZEc+mMCOoxQWOQfTJcaOAbU24HroQ=="], + + "aws-sign2": ["aws-sign2@0.7.0", "", {}, "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA=="], + + "aws4": ["aws4@1.13.2", "", {}, "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw=="], + + "axe-core": ["axe-core@4.11.1", "", {}, "sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A=="], + + "axios": ["axios@1.13.6", "", { "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", "proxy-from-env": "^1.1.0" } }, "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ=="], + + "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], + + "babel-plugin-macros": ["babel-plugin-macros@3.1.0", "", { "dependencies": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", "resolve": "^1.19.0" } }, "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg=="], + + "bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="], + + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + + "baseline-browser-mapping": ["baseline-browser-mapping@2.10.0", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA=="], + + "bcrypt-pbkdf": ["bcrypt-pbkdf@1.0.2", "", { "dependencies": { "tweetnacl": "^0.14.3" } }, "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w=="], + + "bcryptjs": ["bcryptjs@2.4.3", "", {}, "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ=="], + + "before-after-hook": ["before-after-hook@3.0.2", "", {}, "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A=="], + + "better-sqlite3": ["better-sqlite3@9.4.5", "", { "dependencies": { "bindings": "^1.5.0", "prebuild-install": "^7.1.1" } }, "sha512-uFVyoyZR9BNcjSca+cp3MWCv6upAv+tbMC4SWM51NIMhoQOm4tjIkyxFO/ZsYdGAF61WJBgdzyJcz4OokJi0gQ=="], + + "big-integer": ["big-integer@1.6.52", "", {}, "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg=="], + + "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], + + "binary-parser": ["binary-parser@2.3.0", "", {}, "sha512-TXOlPrhvi+kZUv3vA1qZ+MBdqZdihF8gWw7j/MRINiJqXH652GtLSqFTHNPjG8kHbiMQSCATG9oat9ao6aA8dA=="], + + "bind-obj-methods": ["bind-obj-methods@3.0.0", "", {}, "sha512-nLEaaz3/sEzNSyPWRsN9HNsqwk1AUyECtGj+XwGdIi3xABnEqecvXtIJ0wehQXuuER5uZ/5fTs2usONgYjG+iw=="], + + "bindings": ["bindings@1.5.0", "", { "dependencies": { "file-uri-to-path": "1.0.0" } }, "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="], + + "bintrees": ["bintrees@1.0.2", "", {}, "sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw=="], + + "bl": ["bl@2.2.1", "", { "dependencies": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" } }, "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g=="], + + "bliss": ["bliss@workspace:typescript/bliss"], + + "bms-table-loader": ["bms-table-loader@2.0.0", "", { "dependencies": { "node-fetch": "2.6.2", "zod": "^3.19.1" } }, "sha512-CFCwo6FLVPeDTL64/xhqAVA1dTim3Qm0nbT9nGtDTEMvlLjW83bE8IswUPzX8SSE+k4UCjJ9vgLveuaQ5KbWHQ=="], + + "body-parser": ["body-parser@1.20.3", "", { "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" } }, "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g=="], + + "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], + + "bootstrap-scss": ["bootstrap-scss@5.3.8", "", {}, "sha512-lDjTMXl2lRwfhGJY3vmDXlWSk50gg7eW2+zzCQi9tsyeZgD6N5hcmMk3G28F7MvLniJKS9LZV+2YNCxiW8+WIw=="], + + "bowser": ["bowser@2.14.1", "", {}, "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg=="], + + "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], + + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + + "broadcast-channel": ["broadcast-channel@3.7.0", "", { "dependencies": { "@babel/runtime": "^7.7.2", "detect-node": "^2.1.0", "js-sha3": "0.8.0", "microseconds": "0.2.0", "nano-time": "1.0.0", "oblivious-set": "1.0.0", "rimraf": "3.0.2", "unload": "2.2.0" } }, "sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg=="], + + "browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="], + + "bson": ["bson@1.1.6", "", {}, "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg=="], + + "btoa": ["btoa@1.2.1", "", { "bin": { "btoa": "bin/btoa.js" } }, "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g=="], + + "buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], + + "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], + + "bullmq": ["bullmq@1.68.4", "", { "dependencies": { "cron-parser": "^2.18.0", "get-port": "^5.1.1", "glob": "^7.2.0", "ioredis": "^4.28.2", "lodash": "^4.17.21", "msgpackr": "^1.4.6", "semver": "^6.3.0", "tslib": "^1.14.1", "uuid": "^8.3.2" } }, "sha512-I0BYxhRocWHcNpzdXX5jR8DwKG1PkGJ8KUt9SJhWCCWd4sYvsMl6KV6J35ZfigGydXuAja19tbEefTUxdVv/sw=="], + + "bunyan": ["bunyan@1.8.15", "", { "optionalDependencies": { "dtrace-provider": "~0.8", "moment": "^2.19.3", "mv": "~2", "safe-json-stringify": "~1" }, "bin": { "bunyan": "bin/bunyan" } }, "sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig=="], + + "busboy": ["busboy@1.6.0", "", { "dependencies": { "streamsearch": "^1.1.0" } }, "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA=="], + + "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], + + "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], + + "caching-transform": ["caching-transform@4.0.0", "", { "dependencies": { "hasha": "^5.0.0", "make-dir": "^3.0.0", "package-hash": "^4.0.0", "write-file-atomic": "^3.0.0" } }, "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA=="], + + "call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="], + + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + + "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], + + "caller-callsite": ["caller-callsite@4.1.0", "", { "dependencies": { "callsites": "^3.1.0" } }, "sha512-99nnnGlJexTc41xwQTr+mWl15OI5PPczUJzM4YRE7QjkefMKCXGa5gfQjCOuVrD+1TjI/fevIDHg2nz3iYN5Ig=="], + + "caller-path": ["caller-path@3.0.1", "", { "dependencies": { "caller-callsite": "^4.1.0" } }, "sha512-fhmztL4wURO/BzwJUJ4aVRdnKEFskPBbrJ8fNgl7XdUiD1ygzzlt+nhPgUBSRq2ciEVubo6x+W8vJQzm55QLLQ=="], + + "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], + + "camel-case": ["camel-case@4.1.2", "", { "dependencies": { "pascal-case": "^3.1.2", "tslib": "^2.0.3" } }, "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw=="], + + "camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="], + + "caniuse-lite": ["caniuse-lite@1.0.30001777", "", {}, "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ=="], + + "cardinal": ["cardinal@2.1.1", "", { "dependencies": { "ansicolors": "~0.3.2", "redeyed": "~2.1.0" }, "bin": { "cdl": "./bin/cdl.js" } }, "sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw=="], + + "caseless": ["caseless@0.12.0", "", {}, "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw=="], + + "chai": ["chai@5.3.3", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw=="], + + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="], + + "check-error": ["check-error@2.1.3", "", {}, "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA=="], + + "cheerio": ["cheerio@1.2.0", "", { "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "encoding-sniffer": "^0.2.1", "htmlparser2": "^10.1.0", "parse5": "^7.3.0", "parse5-htmlparser2-tree-adapter": "^7.1.0", "parse5-parser-stream": "^7.1.2", "undici": "^7.19.0", "whatwg-mimetype": "^4.0.0" } }, "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg=="], + + "cheerio-select": ["cheerio-select@2.1.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-select": "^5.1.0", "css-what": "^6.1.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.0.1" } }, "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g=="], + + "chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], + + "chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="], + + "ci-info": ["ci-info@2.0.0", "", {}, "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="], + + "classnames": ["classnames@2.5.1", "", {}, "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="], + + "clean-css": ["clean-css@5.3.3", "", { "dependencies": { "source-map": "~0.6.0" } }, "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg=="], + + "clean-stack": ["clean-stack@2.2.0", "", {}, "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="], + + "cli-cursor": ["cli-cursor@3.1.0", "", { "dependencies": { "restore-cursor": "^3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="], + + "cli-progress": ["cli-progress@3.12.0", "", { "dependencies": { "string-width": "^4.2.3" } }, "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A=="], + + "cli-truncate": ["cli-truncate@2.1.0", "", { "dependencies": { "slice-ansi": "^3.0.0", "string-width": "^4.2.0" } }, "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg=="], + + "cliui": ["cliui@7.0.4", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" } }, "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ=="], + + "clone": ["clone@2.1.2", "", {}, "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w=="], + + "cluster-key-slot": ["cluster-key-slot@1.1.2", "", {}, "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA=="], + + "color": ["color@5.0.3", "", { "dependencies": { "color-convert": "^3.1.3", "color-string": "^2.1.3" } }, "sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA=="], + + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "color-string": ["color-string@2.1.4", "", { "dependencies": { "color-name": "^2.0.0" } }, "sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg=="], + + "color-support": ["color-support@1.1.3", "", { "bin": { "color-support": "bin.js" } }, "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg=="], + + "colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="], + + "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], + + "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="], + + "commander": ["commander@8.3.0", "", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="], + + "commist": ["commist@1.1.0", "", { "dependencies": { "leven": "^2.1.0", "minimist": "^1.1.0" } }, "sha512-rraC8NXWOEjhADbZe9QBNzLAN5Q3fsTPQtBV+fEVj6xKIgDgNiEVE6ZNfHpZOqfQ21YUzfVNUXLOEZquYvQPPg=="], + + "commondir": ["commondir@1.0.1", "", {}, "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg=="], + + "component-emitter": ["component-emitter@1.3.1", "", {}, "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ=="], + + "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + + "concat-stream": ["concat-stream@2.0.0", "", { "dependencies": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.0.2", "typedarray": "^0.0.6" } }, "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A=="], + + "connect-history-api-fallback": ["connect-history-api-fallback@1.6.0", "", {}, "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg=="], + + "connect-redis": ["connect-redis@6.1.1", "", {}, "sha512-4on27NmUz1hVCVsrUFUOe06YkgCx88ZZ29Wi7D5mXg22alN/Xx+Y+iPrJ1Cc7coUKAe5SP3W2LF/zo6WXSJFFg=="], + + "consola": ["consola@2.15.3", "", {}, "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw=="], + + "content-disposition": ["content-disposition@0.5.4", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ=="], + + "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], + + "convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], + + "cookie": ["cookie@0.6.0", "", {}, "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw=="], + + "cookie-signature": ["cookie-signature@1.0.6", "", {}, "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="], + + "cookiejar": ["cookiejar@2.1.4", "", {}, "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw=="], + + "core-js": ["core-js@1.2.7", "", {}, "sha512-ZiPp9pZlgxpWRu0M+YWbm6+aQ84XEfH1JRXvfOc/fILWI0VKhLC2LX13X1NYq4fULzLMq7Hfh43CSo2/aIaUPA=="], + + "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], + + "cosmiconfig": ["cosmiconfig@7.1.0", "", { "dependencies": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", "parse-json": "^5.0.0", "path-type": "^4.0.0", "yaml": "^1.10.0" } }, "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA=="], + + "coveralls": ["coveralls@3.1.1", "", { "dependencies": { "js-yaml": "^3.13.1", "lcov-parse": "^1.0.0", "log-driver": "^1.2.7", "minimist": "^1.2.5", "request": "^2.88.2" }, "bin": { "coveralls": "bin/coveralls.js" } }, "sha512-+dxnG2NHncSD1NrqbSM3dn/lE57O6Qf/koe9+I7c+wzkqRmEvcp0kgJdxKInzYzkICKkFMZsX3Vct3++tsF9ww=="], + + "create-require": ["create-require@1.1.1", "", {}, "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ=="], + + "cron-parser": ["cron-parser@2.18.0", "", { "dependencies": { "is-nan": "^1.3.0", "moment-timezone": "^0.5.31" } }, "sha512-s4odpheTyydAbTBQepsqd2rNWGa2iV3cyo8g7zbI2QQYGLVsfbhmwukayS1XHppe02Oy1fg7mg6xoaraVJeEcg=="], + + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "crypto-js": ["crypto-js@4.2.0", "", {}, "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="], + + "css-select": ["css-select@4.3.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.0.1", "domhandler": "^4.3.1", "domutils": "^2.8.0", "nth-check": "^2.0.1" } }, "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ=="], + + "css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="], + + "csstype": ["csstype@3.1.1", "", {}, "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw=="], + + "csv-parse": ["csv-parse@5.6.0", "", {}, "sha512-l3nz3euub2QMg5ouu5U09Ew9Wf6/wQ8I++ch1loQ0ljmzhmfZYrH9fflS22i/PQEvsPvxCwxgz5q7UB8K1JO4Q=="], + + "d3-array": ["d3-array@2.12.1", "", { "dependencies": { "internmap": "^1.0.0" } }, "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ=="], + + "d3-color": ["d3-color@2.0.0", "", {}, "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ=="], + + "d3-delaunay": ["d3-delaunay@5.3.0", "", { "dependencies": { "delaunator": "4" } }, "sha512-amALSrOllWVLaHTnDLHwMIiz0d1bBu9gZXd1FiLfXf8sHcX9jrcj81TVZOqD4UX7MgBZZ07c8GxzEgBpJqc74w=="], + + "d3-format": ["d3-format@1.4.5", "", {}, "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ=="], + + "d3-interpolate": ["d3-interpolate@2.0.1", "", { "dependencies": { "d3-color": "1 - 2" } }, "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ=="], + + "d3-path": ["d3-path@1.0.9", "", {}, "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="], + + "d3-scale": ["d3-scale@3.3.0", "", { "dependencies": { "d3-array": "^2.3.0", "d3-format": "1 - 2", "d3-interpolate": "1.2.0 - 2", "d3-time": "^2.1.1", "d3-time-format": "2 - 3" } }, "sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ=="], + + "d3-scale-chromatic": ["d3-scale-chromatic@2.0.0", "", { "dependencies": { "d3-color": "1 - 2", "d3-interpolate": "1 - 2" } }, "sha512-LLqy7dJSL8yDy7NRmf6xSlsFZ6zYvJ4BcWFE4zBrOPnQERv9zj24ohnXKRbyi9YHnYV+HN1oEO3iFK971/gkzA=="], + + "d3-shape": ["d3-shape@1.3.7", "", { "dependencies": { "d3-path": "1" } }, "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw=="], + + "d3-time": ["d3-time@2.1.1", "", { "dependencies": { "d3-array": "2" } }, "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ=="], + + "d3-time-format": ["d3-time-format@3.0.0", "", { "dependencies": { "d3-time": "1 - 2" } }, "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag=="], + + "damerau-levenshtein": ["damerau-levenshtein@1.0.8", "", {}, "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA=="], + + "dashdash": ["dashdash@1.14.1", "", { "dependencies": { "assert-plus": "^1.0.0" } }, "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g=="], + + "data-view-buffer": ["data-view-buffer@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ=="], + + "data-view-byte-length": ["data-view-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ=="], + + "data-view-byte-offset": ["data-view-byte-offset@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-data-view": "^1.0.1" } }, "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ=="], + + "dateformat": ["dateformat@4.6.3", "", {}, "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "decamelize": ["decamelize@1.2.0", "", {}, "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA=="], + + "decode-named-character-reference": ["decode-named-character-reference@1.3.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q=="], + + "decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="], + + "deeks": ["deeks@2.5.1", "", {}, "sha512-fqrBeUz7f1UqaXDRzVB5RG2EfPk15HJRrb2pMZj8mLlSTtz4tRPsK5leFOskoHFPuyZ6+7aRM9j657fvXLkJ7Q=="], + + "deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="], + + "deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="], + + "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], + + "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="], + + "default-require-extensions": ["default-require-extensions@3.0.1", "", { "dependencies": { "strip-bom": "^4.0.0" } }, "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw=="], + + "defaults": ["defaults@1.0.4", "", { "dependencies": { "clone": "^1.0.2" } }, "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A=="], + + "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], + + "define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="], + + "delaunator": ["delaunator@4.0.1", "", {}, "sha512-WNPWi1IRKZfCt/qIDMfERkDp93+iZEmOxN2yy4Jg+Xhv8SLk2UTqqbe1sfiipn0and9QrE914/ihdx82Y/Giag=="], + + "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], + + "denque": ["denque@1.5.1", "", {}, "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw=="], + + "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], + + "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], + + "destroy": ["destroy@1.2.0", "", {}, "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="], + + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + + "detect-node": ["detect-node@2.1.0", "", {}, "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g=="], + + "dezalgo": ["dezalgo@1.0.4", "", { "dependencies": { "asap": "^2.0.0", "wrappy": "1" } }, "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig=="], + + "diff": ["diff@4.0.4", "", {}, "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ=="], + + "dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="], + + "discord-api-types": ["discord-api-types@0.22.0", "", {}, "sha512-l8yD/2zRbZItUQpy7ZxBJwaLX/Bs2TGaCthRppk8Sw24LOIWg12t9JEreezPoYD0SQcC2htNNo27kYEpYW/Srg=="], + + "discord.js": ["discord.js@13.6.0", "", { "dependencies": { "@discordjs/builders": "^0.11.0", "@discordjs/collection": "^0.4.0", "@sapphire/async-queue": "^1.1.9", "@types/node-fetch": "^2.5.12", "@types/ws": "^8.2.2", "discord-api-types": "^0.26.0", "form-data": "^4.0.0", "node-fetch": "^2.6.1", "ws": "^8.4.0" } }, "sha512-tXNR8zgsEPxPBvGk3AQjJ9ljIIC6/LOPjzKwpwz8Y1Q2X66Vi3ZqFgRHYwnHKC0jC0F+l4LzxlhmOJsBZDNg9g=="], + + "doc-path": ["doc-path@3.0.2", "", {}, "sha512-VRlA2OKSjTbHWj6wmSanxJ338fE/YN8pqmZ0FIWK5JWkIJMFRc4KmD35JtOrnjvVG0WrzOtDDNHx1lN1tkb+lA=="], + + "doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="], + + "dom-helpers": ["dom-helpers@5.2.1", "", { "dependencies": { "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" } }, "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA=="], + + "dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], + + "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], + + "domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], + + "domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], + + "dot-case": ["dot-case@3.0.4", "", { "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w=="], + + "dot-prop": ["dot-prop@6.0.1", "", { "dependencies": { "is-obj": "^2.0.0" } }, "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA=="], + + "dotenv": ["dotenv@16.0.0", "", {}, "sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q=="], + + "dotenv-expand": ["dotenv-expand@8.0.3", "", {}, "sha512-SErOMvge0ZUyWd5B0NXMQlDkN+8r+HhVUsxgOO7IoPDOdDRD2JjExpN6y3KnFR66jsJMwSn1pqIivhU5rcJiNg=="], + + "dtrace-provider": ["dtrace-provider@0.8.8", "", { "dependencies": { "nan": "^2.14.0" } }, "sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg=="], + + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + + "duplexify": ["duplexify@3.7.1", "", { "dependencies": { "end-of-stream": "^1.0.0", "inherits": "^2.0.1", "readable-stream": "^2.0.0", "stream-shift": "^1.0.0" } }, "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g=="], + + "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], + + "ecc-jsbn": ["ecc-jsbn@0.1.2", "", { "dependencies": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" } }, "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw=="], + + "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], + + "ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="], + + "electron-to-chromium": ["electron-to-chromium@1.5.307", "", {}, "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg=="], + + "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + + "enabled": ["enabled@2.0.0", "", {}, "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ=="], + + "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], + + "encoding": ["encoding@0.1.13", "", { "dependencies": { "iconv-lite": "^0.6.2" } }, "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A=="], + + "encoding-japanese": ["encoding-japanese@1.0.30", "", {}, "sha512-bd/DFLAoJetvv7ar/KIpE3CNO8wEuyrt9Xuw6nSMiZ+Vrz/Q21BPsMHvARL2Wz6IKHKXgb+DWZqtRg1vql9cBg=="], + + "encoding-sniffer": ["encoding-sniffer@0.2.1", "", { "dependencies": { "iconv-lite": "^0.6.3", "whatwg-encoding": "^3.1.1" } }, "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw=="], + + "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], + + "entities": ["entities@2.2.0", "", {}, "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="], + + "error-ex": ["error-ex@1.3.4", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ=="], + + "es-abstract": ["es-abstract@1.24.1", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.3.0", "get-proto": "^1.0.1", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-negative-zero": "^2.0.3", "is-regex": "^1.2.1", "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "stop-iteration-iterator": "^1.1.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.19" } }, "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw=="], + + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-iterator-helpers": ["es-iterator-helpers@1.2.2", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.24.1", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.1.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.3.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "iterator.prototype": "^1.1.5", "safe-array-concat": "^1.1.3" } }, "sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w=="], + + "es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="], + + "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + + "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], + + "es-shim-unscopables": ["es-shim-unscopables@1.1.0", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw=="], + + "es-to-primitive": ["es-to-primitive@1.3.0", "", { "dependencies": { "is-callable": "^1.2.7", "is-date-object": "^1.0.5", "is-symbol": "^1.0.4" } }, "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g=="], + + "es6-error": ["es6-error@4.1.1", "", {}, "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg=="], + + "esbuild": ["esbuild@0.27.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.3", "@esbuild/android-arm": "0.27.3", "@esbuild/android-arm64": "0.27.3", "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", "@esbuild/freebsd-x64": "0.27.3", "@esbuild/linux-arm": "0.27.3", "@esbuild/linux-arm64": "0.27.3", "@esbuild/linux-ia32": "0.27.3", "@esbuild/linux-loong64": "0.27.3", "@esbuild/linux-mips64el": "0.27.3", "@esbuild/linux-ppc64": "0.27.3", "@esbuild/linux-riscv64": "0.27.3", "@esbuild/linux-s390x": "0.27.3", "@esbuild/linux-x64": "0.27.3", "@esbuild/netbsd-arm64": "0.27.3", "@esbuild/netbsd-x64": "0.27.3", "@esbuild/openbsd-arm64": "0.27.3", "@esbuild/openbsd-x64": "0.27.3", "@esbuild/openharmony-arm64": "0.27.3", "@esbuild/sunos-x64": "0.27.3", "@esbuild/win32-arm64": "0.27.3", "@esbuild/win32-ia32": "0.27.3", "@esbuild/win32-x64": "0.27.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg=="], + + "esbuild-android-64": ["esbuild-android-64@0.15.18", "", { "os": "android", "cpu": "x64" }, "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA=="], + + "esbuild-android-arm64": ["esbuild-android-arm64@0.15.18", "", { "os": "android", "cpu": "arm64" }, "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ=="], + + "esbuild-darwin-64": ["esbuild-darwin-64@0.15.18", "", { "os": "darwin", "cpu": "x64" }, "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg=="], + + "esbuild-darwin-arm64": ["esbuild-darwin-arm64@0.15.18", "", { "os": "darwin", "cpu": "arm64" }, "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA=="], + + "esbuild-freebsd-64": ["esbuild-freebsd-64@0.15.18", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA=="], + + "esbuild-freebsd-arm64": ["esbuild-freebsd-arm64@0.15.18", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA=="], + + "esbuild-linux-32": ["esbuild-linux-32@0.15.18", "", { "os": "linux", "cpu": "ia32" }, "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg=="], + + "esbuild-linux-64": ["esbuild-linux-64@0.15.18", "", { "os": "linux", "cpu": "x64" }, "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw=="], + + "esbuild-linux-arm": ["esbuild-linux-arm@0.15.18", "", { "os": "linux", "cpu": "arm" }, "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA=="], + + "esbuild-linux-arm64": ["esbuild-linux-arm64@0.15.18", "", { "os": "linux", "cpu": "arm64" }, "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug=="], + + "esbuild-linux-mips64le": ["esbuild-linux-mips64le@0.15.18", "", { "os": "linux", "cpu": "none" }, "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ=="], + + "esbuild-linux-ppc64le": ["esbuild-linux-ppc64le@0.15.18", "", { "os": "linux", "cpu": "ppc64" }, "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w=="], + + "esbuild-linux-riscv64": ["esbuild-linux-riscv64@0.15.18", "", { "os": "linux", "cpu": "none" }, "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg=="], + + "esbuild-linux-s390x": ["esbuild-linux-s390x@0.15.18", "", { "os": "linux", "cpu": "s390x" }, "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ=="], + + "esbuild-netbsd-64": ["esbuild-netbsd-64@0.15.18", "", { "os": "none", "cpu": "x64" }, "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg=="], + + "esbuild-openbsd-64": ["esbuild-openbsd-64@0.15.18", "", { "os": "openbsd", "cpu": "x64" }, "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ=="], + + "esbuild-sunos-64": ["esbuild-sunos-64@0.15.18", "", { "os": "sunos", "cpu": "x64" }, "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw=="], + + "esbuild-windows-32": ["esbuild-windows-32@0.15.18", "", { "os": "win32", "cpu": "ia32" }, "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ=="], + + "esbuild-windows-64": ["esbuild-windows-64@0.15.18", "", { "os": "win32", "cpu": "x64" }, "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw=="], + + "esbuild-windows-arm64": ["esbuild-windows-arm64@0.15.18", "", { "os": "win32", "cpu": "arm64" }, "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ=="], + + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + + "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], + + "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], + + "eslint": ["eslint@9.39.4", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.2", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.5", "@eslint/js": "9.39.4", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ=="], + + "eslint-config-prettier": ["eslint-config-prettier@9.1.2", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": { "eslint-config-prettier": "bin/cli.js" } }, "sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ=="], + + "eslint-config-tachi": ["eslint-config-tachi@workspace:typescript/eslint-config"], + + "eslint-import-resolver-node": ["eslint-import-resolver-node@0.3.9", "", { "dependencies": { "debug": "^3.2.7", "is-core-module": "^2.13.0", "resolve": "^1.22.4" } }, "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g=="], + + "eslint-import-resolver-typescript": ["eslint-import-resolver-typescript@3.10.1", "", { "dependencies": { "@nolyfill/is-core-module": "1.0.39", "debug": "^4.4.0", "get-tsconfig": "^4.10.0", "is-bun-module": "^2.0.0", "stable-hash": "^0.0.5", "tinyglobby": "^0.2.13", "unrs-resolver": "^1.6.2" }, "peerDependencies": { "eslint": "*", "eslint-plugin-import": "*", "eslint-plugin-import-x": "*" }, "optionalPeers": ["eslint-plugin-import", "eslint-plugin-import-x"] }, "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ=="], + + "eslint-module-utils": ["eslint-module-utils@2.12.1", "", { "dependencies": { "debug": "^3.2.7" } }, "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw=="], + + "eslint-plugin-import": ["eslint-plugin-import@2.32.0", "", { "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", "array.prototype.findlastindex": "^1.2.6", "array.prototype.flat": "^1.3.3", "array.prototype.flatmap": "^1.3.3", "debug": "^3.2.7", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.9", "eslint-module-utils": "^2.12.1", "hasown": "^2.0.2", "is-core-module": "^2.16.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", "object.fromentries": "^2.0.8", "object.groupby": "^1.0.3", "object.values": "^1.2.1", "semver": "^6.3.1", "string.prototype.trimend": "^1.0.9", "tsconfig-paths": "^3.15.0" }, "peerDependencies": { "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } }, "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA=="], + + "eslint-plugin-jsx-a11y": ["eslint-plugin-jsx-a11y@6.10.2", "", { "dependencies": { "aria-query": "^5.3.2", "array-includes": "^3.1.8", "array.prototype.flatmap": "^1.3.2", "ast-types-flow": "^0.0.8", "axe-core": "^4.10.0", "axobject-query": "^4.1.0", "damerau-levenshtein": "^1.0.8", "emoji-regex": "^9.2.2", "hasown": "^2.0.2", "jsx-ast-utils": "^3.3.5", "language-tags": "^1.0.9", "minimatch": "^3.1.2", "object.fromentries": "^2.0.8", "safe-regex-test": "^1.0.3", "string.prototype.includes": "^2.0.1" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" } }, "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q=="], + + "eslint-plugin-perfectionist": ["eslint-plugin-perfectionist@3.9.1", "", { "dependencies": { "@typescript-eslint/types": "^8.9.0", "@typescript-eslint/utils": "^8.9.0", "minimatch": "^9.0.5", "natural-compare-lite": "^1.4.0" }, "peerDependencies": { "astro-eslint-parser": "^1.0.2", "eslint": ">=8.0.0", "svelte": ">=3.0.0", "svelte-eslint-parser": "^0.41.1", "vue-eslint-parser": ">=9.0.0" }, "optionalPeers": ["astro-eslint-parser", "svelte", "svelte-eslint-parser", "vue-eslint-parser"] }, "sha512-9WRzf6XaAxF4Oi5t/3TqKP5zUjERhasHmLFHin2Yw6ZAp/EP/EVA2dr3BhQrrHWCm5SzTMZf0FcjDnBkO2xFkA=="], + + "eslint-plugin-react": ["eslint-plugin-react@7.37.5", "", { "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.3", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", "es-iterator-helpers": "^1.2.1", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.9", "object.fromentries": "^2.0.8", "object.values": "^1.2.1", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", "string.prototype.matchall": "^4.0.12", "string.prototype.repeat": "^1.0.0" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA=="], + + "eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@5.2.0", "", { "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg=="], + + "eslint-plugin-react-refresh": ["eslint-plugin-react-refresh@0.4.26", "", { "peerDependencies": { "eslint": ">=8.40" } }, "sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ=="], + + "eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="], + + "eslint-utils": ["eslint-utils@3.0.0", "", { "dependencies": { "eslint-visitor-keys": "^2.0.0" }, "peerDependencies": { "eslint": ">=5" } }, "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA=="], + + "eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], + + "esm": ["esm@3.2.25", "", {}, "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA=="], + + "espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="], + + "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], + + "esquery": ["esquery@1.7.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g=="], + + "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], + + "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], + + "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], + + "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], + + "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], + + "event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="], + + "events-to-array": ["events-to-array@1.1.2", "", {}, "sha512-inRWzRY7nG+aXZxBzEqYKB3HPgwflZRopAjDCHv0whhRx+MTUr1ei0ICZUypdyE0HRm4L2d5VEcIqLD6yl+BFA=="], + + "expand-template": ["expand-template@2.0.3", "", {}, "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="], + + "expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="], + + "express": ["express@4.20.0", "", { "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "1.2.0", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", "qs": "6.11.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", "serve-static": "1.16.0", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw=="], + + "express-async-errors": ["express-async-errors@3.1.1", "", { "peerDependencies": { "express": "^4.16.2" } }, "sha512-h6aK1da4tpqWSbyCa3FxB/V6Ehd4EEB15zyQq9qe75OZBp0krinNKuH4rAY+S/U/2I36vdLAUFSjQJ+TFmODng=="], + + "express-prom-bundle": ["express-prom-bundle@7.0.2", "", { "dependencies": { "@types/express": "^4.17.21", "express": "^4.18.2", "on-finished": "^2.3.0", "url-value-parser": "^2.0.0" }, "peerDependencies": { "prom-client": ">=15.0.0" } }, "sha512-ffFV4HGHvCKnkNJFqm42sYztRJE5mLgOj8MpGey1HOatuFhtcwXoBD2m5gca7ZbcyjkIf7lOH5ZdrhlrBf0sGw=="], + + "express-rate-limit": ["express-rate-limit@5.5.1", "", {}, "sha512-MTjE2eIbHv5DyfuFz4zLYWxpqVhEhkTiwFGuB74Q9CSou2WHO52nlE5y3Zlg6SIsiYUIPj6ifFxnkPz6O3sIUg=="], + + "express-session": ["express-session@1.17.2", "", { "dependencies": { "cookie": "0.4.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "~2.0.0", "on-headers": "~1.0.2", "parseurl": "~1.3.3", "safe-buffer": "5.2.1", "uid-safe": "~2.1.5" } }, "sha512-mPcYcLA0lvh7D4Oqr5aNJFMtBMKPLl++OKKxkHzZ0U0oDq1rpKBnkR5f5vCHR26VeArlTOEF9td4x5IjICksRQ=="], + + "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], + + "extract-pg-schema": ["extract-pg-schema@5.8.1", "", { "dependencies": { "knex": "3.1.0", "knex-pglite": "^0.12.0", "pg": "8.17.2", "pg-query-emscripten": "^5.1.0", "ramda": "^0.31.0" }, "bin": { "extract-pg-schema": "bin/extract-pg-schema" } }, "sha512-rNotRBXxWQnvjcErsX3k9cZwY4KQbVniEp+KAd6RghfDvt29kOtnDdfO7S+Y6b/5tge6caovbJq8s9cgsUtBUA=="], + + "extsprintf": ["extsprintf@1.3.0", "", {}, "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g=="], + + "fast-content-type-parse": ["fast-content-type-parse@2.0.1", "", {}, "sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q=="], + + "fast-copy": ["fast-copy@4.0.2", "", {}, "sha512-ybA6PDXIXOXivLJK/z9e+Otk7ve13I4ckBvGO5I2RRmBU1gMHLVDJYEuJYhGwez7YNlYji2M2DvVU+a9mSFDlw=="], + + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + + "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], + + "fast-json-stable-hash": ["fast-json-stable-hash@1.0.3", "", {}, "sha512-iLK3Tq2J/KbiUn/5OHyhxikHqzwFXSM2e803Dp2JtBdQjsCVuZwWvL+WqWXPPRUEuDX4c0kqID1SU84RCfxs3A=="], + + "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], + + "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], + + "fast-safe-stringify": ["fast-safe-stringify@2.1.1", "", {}, "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="], + + "fast-xml-parser": ["fast-xml-parser@4.5.4", "", { "dependencies": { "strnum": "^1.0.5" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-jE8ugADnYOBsu1uaoayVl1tVKAMNOXyjwvv2U6udEA2ORBhDooJDWoGxTkhd4Qn4yh59JVVt/pKXtjPwx9OguQ=="], + + "fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="], + + "fbjs": ["fbjs@0.8.18", "", { "dependencies": { "core-js": "^1.0.0", "isomorphic-fetch": "^2.1.1", "loose-envify": "^1.0.0", "object-assign": "^4.1.0", "promise": "^7.1.1", "setimmediate": "^1.0.5", "ua-parser-js": "^0.7.30" } }, "sha512-EQaWFK+fEPSoibjNy8IxUtaFOMXcWsY0JaVrQoZR9zC8N2Ygf9iDITPWjUTVIax95b6I742JFLqASHfsag/vKA=="], + + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + + "fecha": ["fecha@4.2.3", "", {}, "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="], + + "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], + + "file-uri-to-path": ["file-uri-to-path@1.0.0", "", {}, "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="], + + "filelist": ["filelist@1.0.6", "", { "dependencies": { "minimatch": "^5.0.1" } }, "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA=="], + + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + + "finalhandler": ["finalhandler@1.2.0", "", { "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", "statuses": "2.0.1", "unpipe": "~1.0.0" } }, "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg=="], + + "find-cache-dir": ["find-cache-dir@3.3.2", "", { "dependencies": { "commondir": "^1.0.1", "make-dir": "^3.0.2", "pkg-dir": "^4.1.0" } }, "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig=="], + + "find-root": ["find-root@1.1.0", "", {}, "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="], + + "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], + + "findit": ["findit@2.0.0", "", {}, "sha512-ENZS237/Hr8bjczn5eKuBohLgaD0JyUd0arxretR1f9RO46vZHA1b2y0VorgGV3WaOT3c+78P8h7v4JGJ1i/rg=="], + + "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], + + "flatted": ["flatted@3.4.0", "", {}, "sha512-kC6Bb+ooptOIvWj5B63EQWkF0FEnNjV2ZNkLMLZRDDduIiWeFF4iKnslwhiWxjAdbg4NzTNo6h0qLuvFrcx+Sw=="], + + "flow-remove-types": ["flow-remove-types@2.304.0", "", { "dependencies": { "hermes-parser": "0.33.3", "pirates": "^3.0.2", "vlq": "^0.2.1" }, "bin": { "flow-remove-types": "flow-remove-types", "flow-node": "flow-node" } }, "sha512-3/c6h0ELxBY5I4MEDig6c0gjlT6GYGfxH0VlpgPOF2/78VaI01RPPnVoVyaixJs8uexsAeycxlxd4feIHPYPrQ=="], + + "fn.name": ["fn.name@1.1.0", "", {}, "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="], + + "follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="], + + "for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="], + + "foreground-child": ["foreground-child@2.0.0", "", { "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^3.0.2" } }, "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA=="], + + "forever-agent": ["forever-agent@0.6.1", "", {}, "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw=="], + + "form-data": ["form-data@3.0.4", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.35" } }, "sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ=="], + + "formidable": ["formidable@2.1.5", "", { "dependencies": { "@paralleldrive/cuid2": "^2.2.2", "dezalgo": "^1.0.4", "once": "^1.4.0", "qs": "^6.11.0" } }, "sha512-Oz5Hwvwak/DCaXVVUtPn4oLMLLy1CdclLKO1LFgU7XzDpVMUU5UjlSLpGMocyQNNk8F6IJW9M/YdooSn2MRI+Q=="], + + "formik": ["formik@2.2.9", "", { "dependencies": { "deepmerge": "^2.1.1", "hoist-non-react-statics": "^3.3.0", "lodash": "^4.17.21", "lodash-es": "^4.17.21", "react-fast-compare": "^2.0.1", "tiny-warning": "^1.0.2", "tslib": "^1.10.0" }, "peerDependencies": { "react": ">=16.8.0" } }, "sha512-LQLcISMmf1r5at4/gyJigGn0gOwFbeEAlji+N9InZF6LIMXnFNkO42sCI8Jt84YZggpD4cPWObAZaxpEFtSzNA=="], + + "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], + + "fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="], + + "fromentries": ["fromentries@1.3.2", "", {}, "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg=="], + + "fs-constants": ["fs-constants@1.0.0", "", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="], + + "fs-exists-cached": ["fs-exists-cached@1.0.0", "", {}, "sha512-kSxoARUDn4F2RPXX48UXnaFKwVU7Ivd/6qpzZL29MCDmr9sTvybv4gFCp+qaI4fM9m0z9fgz/yJvi56GAz+BZg=="], + + "fs-extra": ["fs-extra@7.0.1", "", { "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw=="], + + "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + + "function-loop": ["function-loop@2.0.1", "", {}, "sha512-ktIR+O6i/4h+j/ZhZJNdzeI4i9lEPeEK6UPR2EVyTVBqOwcU3Za9xYKLH64ZR9HmcROyRrOkizNyjjtWJzDDkQ=="], + + "function.prototype.name": ["function.prototype.name@1.1.8", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "functions-have-names": "^1.2.3", "hasown": "^2.0.2", "is-callable": "^1.2.7" } }, "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q=="], + + "functional-red-black-tree": ["functional-red-black-tree@1.0.1", "", {}, "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g=="], + + "functions-have-names": ["functions-have-names@1.2.3", "", {}, "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="], + + "generator-function": ["generator-function@2.0.1", "", {}, "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g=="], + + "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], + + "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + + "get-package-type": ["get-package-type@0.1.0", "", {}, "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q=="], + + "get-port": ["get-port@5.1.1", "", {}, "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ=="], + + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + + "get-symbol-description": ["get-symbol-description@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="], + + "get-tsconfig": ["get-tsconfig@4.13.6", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw=="], + + "getopts": ["getopts@2.3.0", "", {}, "sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA=="], + + "getpass": ["getpass@0.1.7", "", { "dependencies": { "assert-plus": "^1.0.0" } }, "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng=="], + + "github-from-package": ["github-from-package@0.0.0", "", {}, "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="], + + "glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + + "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], + + "globals": ["globals@15.15.0", "", {}, "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg=="], + + "globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="], + + "globby": ["globby@11.1.0", "", { "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.2.9", "ignore": "^5.2.0", "merge2": "^1.4.1", "slash": "^3.0.0" } }, "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g=="], + + "goober": ["goober@2.1.18", "", { "peerDependencies": { "csstype": "^3.0.10" } }, "sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw=="], + + "google-protobuf": ["google-protobuf@3.21.4", "", {}, "sha512-MnG7N936zcKTco4Jd2PX2U96Kf9PxygAPKBug+74LHzmHXmceN16MmRcdgZv+DGef/S9YvQAfRsNCn4cjf9yyQ=="], + + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + + "grpc-tools": ["grpc-tools@1.13.1", "", { "dependencies": { "@mapbox/node-pre-gyp": "^2.0.0" }, "bin": { "grpc_tools_node_protoc": "bin/protoc.js", "grpc_tools_node_protoc_plugin": "bin/protoc_plugin.js" } }, "sha512-0sttMUxThNIkCTJq5qI0xXMz5zWqV2u3yG1kR3Sj9OokGIoyRBFjoInK9NyW7x5fH7knj48Roh1gq5xbl0VoDQ=="], + + "har-schema": ["har-schema@2.0.0", "", {}, "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q=="], + + "har-validator": ["har-validator@5.1.5", "", { "dependencies": { "ajv": "^6.12.3", "har-schema": "^2.0.0" } }, "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w=="], + + "has-bigints": ["has-bigints@1.1.0", "", {}, "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg=="], + + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="], + + "has-proto": ["has-proto@1.2.0", "", { "dependencies": { "dunder-proto": "^1.0.0" } }, "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ=="], + + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + + "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], + + "hash.js": ["hash.js@1.1.7", "", { "dependencies": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" } }, "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA=="], + + "hasha": ["hasha@5.2.2", "", { "dependencies": { "is-stream": "^2.0.0", "type-fest": "^0.8.0" } }, "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ=="], + + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + + "he": ["he@1.2.0", "", { "bin": { "he": "bin/he" } }, "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="], + + "helmet": ["helmet@5.0.2", "", {}, "sha512-QWlwUZZ8BtlvwYVTSDTBChGf8EOcQ2LkGMnQJxSzD1mUu8CCjXJZq/BXP8eWw4kikRnzlhtYo3lCk0ucmYA3Vg=="], + + "help-me": ["help-me@5.0.0", "", {}, "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg=="], + + "hermes-estree": ["hermes-estree@0.33.3", "", {}, "sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg=="], + + "hermes-parser": ["hermes-parser@0.33.3", "", { "dependencies": { "hermes-estree": "0.33.3" } }, "sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA=="], + + "history": ["history@4.10.1", "", { "dependencies": { "@babel/runtime": "^7.1.2", "loose-envify": "^1.2.0", "resolve-pathname": "^3.0.0", "tiny-invariant": "^1.0.2", "tiny-warning": "^1.0.0", "value-equal": "^1.0.1" } }, "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew=="], + + "hoist-non-react-statics": ["hoist-non-react-statics@3.3.2", "", { "dependencies": { "react-is": "^16.7.0" } }, "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw=="], + + "html-entities": ["html-entities@2.6.0", "", {}, "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ=="], + + "html-escaper": ["html-escaper@2.0.2", "", {}, "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="], + + "html-minifier-terser": ["html-minifier-terser@6.1.0", "", { "dependencies": { "camel-case": "^4.1.2", "clean-css": "^5.2.2", "commander": "^8.3.0", "he": "^1.2.0", "param-case": "^3.0.4", "relateurl": "^0.2.7", "terser": "^5.10.0" }, "bin": { "html-minifier-terser": "cli.js" } }, "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw=="], + + "htmlparser2": ["htmlparser2@10.1.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "entities": "^7.0.1" } }, "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ=="], + + "http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="], + + "http-signature": ["http-signature@1.2.0", "", { "dependencies": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", "sshpk": "^1.7.0" } }, "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ=="], + + "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], + + "humanize-duration": ["humanize-duration@3.33.2", "", {}, "sha512-K7Ny/ULO1hDm2nnhvAY+SJV1skxFb61fd073SG1IWJl+D44ULrruCuTyjHKjBVVcSuTlnY99DKtgEG39CM5QOQ=="], + + "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + + "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + + "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], + + "ignore-by-default": ["ignore-by-default@1.0.1", "", {}, "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA=="], + + "immutable": ["immutable@4.3.8", "", {}, "sha512-d/Ld9aLbKpNwyl0KiM2CT1WYvkitQ1TSvmRtkcV8FKStiDoA7Slzgjmb/1G2yhKM1p0XeNOieaTbFZmU1d3Xuw=="], + + "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], + + "import-jsx": ["import-jsx@4.0.1", "", { "dependencies": { "@babel/core": "^7.5.5", "@babel/plugin-proposal-object-rest-spread": "^7.5.5", "@babel/plugin-transform-destructuring": "^7.5.0", "@babel/plugin-transform-react-jsx": "^7.3.0", "caller-path": "^3.0.1", "find-cache-dir": "^3.2.0", "make-dir": "^3.0.2", "resolve-from": "^3.0.0", "rimraf": "^3.0.0" } }, "sha512-2Cj4nWRuAmvokFRU6UNo3xgzXKh+4nq/LBtD6mTp3V9c9nYV7O+dRvPChPOM34Qcj1+Ijz3oK6HqkixG0GP9Rg=="], + + "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], + + "indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="], + + "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="], + + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + + "ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], + + "ink": ["ink@2.7.1", "", { "dependencies": { "ansi-escapes": "^4.2.1", "arrify": "^2.0.1", "auto-bind": "^4.0.0", "chalk": "^3.0.0", "cli-cursor": "^3.1.0", "cli-truncate": "^2.1.0", "is-ci": "^2.0.0", "lodash.throttle": "^4.1.1", "log-update": "^3.0.0", "prop-types": "^15.6.2", "react-reconciler": "^0.24.0", "scheduler": "^0.18.0", "signal-exit": "^3.0.2", "slice-ansi": "^3.0.0", "string-length": "^3.1.0", "widest-line": "^3.1.0", "wrap-ansi": "^6.2.0", "yoga-layout-prebuilt": "^1.9.3" }, "peerDependencies": { "@types/react": ">=16.8.0", "react": ">=16.8.0" }, "optionalPeers": ["@types/react"] }, "sha512-s7lJuQDJEdjqtaIWhp3KYHl6WV3J04U9zoQ6wVc+Xoa06XM27SXUY57qC5DO46xkF0CfgXMKkKNcgvSu/SAEpA=="], + + "inline-style-parser": ["inline-style-parser@0.1.1", "", {}, "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q=="], + + "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="], + + "internmap": ["internmap@1.0.1", "", {}, "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="], + + "interpret": ["interpret@2.2.0", "", {}, "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw=="], + + "invariant": ["invariant@2.2.4", "", { "dependencies": { "loose-envify": "^1.0.0" } }, "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA=="], + + "ioredis": ["ioredis@4.31.0", "", { "dependencies": { "@ioredis/commands": "^1.0.2", "cluster-key-slot": "^1.1.0", "debug": "^4.3.1", "denque": "^1.1.0", "lodash.defaults": "^4.2.0", "lodash.flatten": "^4.4.0", "lodash.isarguments": "^3.1.0", "p-map": "^2.1.0", "redis-errors": "^1.2.0", "redis-parser": "^3.0.0", "standard-as-callback": "^2.1.0" } }, "sha512-tVrCrc4LWJwX82GD79dZ0teZQGq+5KJEGpXJRgzHOrhHtLgF9ME6rTwDV5+HN5bjnvmtrnS8ioXhflY16sy2HQ=="], + + "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], + + "is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="], + + "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="], + + "is-async-function": ["is-async-function@2.1.1", "", { "dependencies": { "async-function": "^1.0.0", "call-bound": "^1.0.3", "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ=="], + + "is-bigint": ["is-bigint@1.1.0", "", { "dependencies": { "has-bigints": "^1.0.2" } }, "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ=="], + + "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], + + "is-boolean-object": ["is-boolean-object@1.2.2", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A=="], + + "is-buffer": ["is-buffer@2.0.5", "", {}, "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ=="], + + "is-bun-module": ["is-bun-module@2.0.0", "", { "dependencies": { "semver": "^7.7.1" } }, "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ=="], + + "is-callable": ["is-callable@1.2.7", "", {}, "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="], + + "is-ci": ["is-ci@2.0.0", "", { "dependencies": { "ci-info": "^2.0.0" }, "bin": { "is-ci": "bin.js" } }, "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w=="], + + "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], + + "is-data-view": ["is-data-view@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "is-typed-array": "^1.1.13" } }, "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw=="], + + "is-date-object": ["is-date-object@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" } }, "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg=="], + + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], + + "is-finalizationregistry": ["is-finalizationregistry@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg=="], + + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "is-generator-function": ["is-generator-function@1.1.2", "", { "dependencies": { "call-bound": "^1.0.4", "generator-function": "^2.0.0", "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA=="], + + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], + + "is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="], + + "is-nan": ["is-nan@1.3.2", "", { "dependencies": { "call-bind": "^1.0.0", "define-properties": "^1.1.3" } }, "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w=="], + + "is-negative-zero": ["is-negative-zero@2.0.3", "", {}, "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw=="], + + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + + "is-number-object": ["is-number-object@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw=="], + + "is-obj": ["is-obj@2.0.0", "", {}, "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="], + + "is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="], + + "is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="], + + "is-set": ["is-set@2.0.3", "", {}, "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg=="], + + "is-shared-array-buffer": ["is-shared-array-buffer@1.0.4", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A=="], + + "is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], + + "is-string": ["is-string@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA=="], + + "is-symbol": ["is-symbol@1.1.1", "", { "dependencies": { "call-bound": "^1.0.2", "has-symbols": "^1.1.0", "safe-regex-test": "^1.1.0" } }, "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w=="], + + "is-typed-array": ["is-typed-array@1.1.15", "", { "dependencies": { "which-typed-array": "^1.1.16" } }, "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ=="], + + "is-typedarray": ["is-typedarray@1.0.0", "", {}, "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="], + + "is-weakmap": ["is-weakmap@2.0.2", "", {}, "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w=="], + + "is-weakref": ["is-weakref@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew=="], + + "is-weakset": ["is-weakset@2.0.4", "", { "dependencies": { "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ=="], + + "is-windows": ["is-windows@1.0.2", "", {}, "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA=="], + + "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], + + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "isomorphic-fetch": ["isomorphic-fetch@2.2.1", "", { "dependencies": { "node-fetch": "^1.0.1", "whatwg-fetch": ">=0.10.0" } }, "sha512-9c4TNAKYXM5PRyVcwUZrF3W09nQ+sO7+jydgs4ZGW9dhsLG2VOlISJABombdQqQRXCwuYG3sYV/puGf5rp0qmA=="], + + "isomorphic-ws": ["isomorphic-ws@4.0.1", "", { "peerDependencies": { "ws": "*" } }, "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w=="], + + "isstream": ["isstream@0.1.2", "", {}, "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g=="], + + "istanbul-lib-coverage": ["istanbul-lib-coverage@3.2.2", "", {}, "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg=="], + + "istanbul-lib-hook": ["istanbul-lib-hook@3.0.0", "", { "dependencies": { "append-transform": "^2.0.0" } }, "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ=="], + + "istanbul-lib-instrument": ["istanbul-lib-instrument@4.0.3", "", { "dependencies": { "@babel/core": "^7.7.5", "@istanbuljs/schema": "^0.1.2", "istanbul-lib-coverage": "^3.0.0", "semver": "^6.3.0" } }, "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ=="], + + "istanbul-lib-processinfo": ["istanbul-lib-processinfo@2.0.3", "", { "dependencies": { "archy": "^1.0.0", "cross-spawn": "^7.0.3", "istanbul-lib-coverage": "^3.2.0", "p-map": "^3.0.0", "rimraf": "^3.0.0", "uuid": "^8.3.2" } }, "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg=="], + + "istanbul-lib-report": ["istanbul-lib-report@3.0.1", "", { "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", "supports-color": "^7.1.0" } }, "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw=="], + + "istanbul-lib-source-maps": ["istanbul-lib-source-maps@5.0.6", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.23", "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0" } }, "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A=="], + + "istanbul-reports": ["istanbul-reports@3.2.0", "", { "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" } }, "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA=="], + + "iterator.prototype": ["iterator.prototype@1.1.5", "", { "dependencies": { "define-data-property": "^1.1.4", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.6", "get-proto": "^1.0.0", "has-symbols": "^1.1.0", "set-function-name": "^2.0.2" } }, "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g=="], + + "jackspeak": ["jackspeak@1.4.2", "", { "dependencies": { "cliui": "^7.0.4" } }, "sha512-GHeGTmnuaHnvS+ZctRB01bfxARuu9wW83ENbuiweu07SFcVlZrJpcshSre/keGT7YGBhLHg/+rXCNSrsEHKU4Q=="], + + "jake": ["jake@10.9.4", "", { "dependencies": { "async": "^3.2.6", "filelist": "^1.0.4", "picocolors": "^1.1.1" }, "bin": { "jake": "bin/cli.js" } }, "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA=="], + + "joycon": ["joycon@3.1.1", "", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="], + + "js-sdsl": ["js-sdsl@4.3.0", "", {}, "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ=="], + + "js-sha3": ["js-sha3@0.8.0", "", {}, "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q=="], + + "js-tokens": ["js-tokens@10.0.0", "", {}, "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q=="], + + "js-yaml": ["js-yaml@3.14.2", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg=="], + + "jsbn": ["jsbn@0.1.1", "", {}, "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg=="], + + "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], + + "json-2-csv": ["json-2-csv@3.14.4", "", { "dependencies": { "deeks": "2.5.1", "doc-path": "3.0.2" } }, "sha512-6Dg4ZJb5g1Lu6gVM2jJGpu1WUo0/b3xS1b35+dXAWmYzlu2AqTXSFrUzA3l5/aYptjhoiGxCN7CZbxBwrUmhig=="], + + "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], + + "json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="], + + "json-schema": ["json-schema@0.4.0", "", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="], + + "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + + "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], + + "json-stringify-safe": ["json-stringify-safe@5.0.1", "", {}, "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="], + + "json5": ["json5@2.2.0", "", { "dependencies": { "minimist": "^1.2.5" }, "bin": { "json5": "lib/cli.js" } }, "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA=="], + + "jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], + + "jsprim": ["jsprim@1.4.2", "", { "dependencies": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", "json-schema": "0.4.0", "verror": "1.10.0" } }, "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw=="], + + "jsx-ast-utils": ["jsx-ast-utils@3.3.5", "", { "dependencies": { "array-includes": "^3.1.6", "array.prototype.flat": "^1.3.1", "object.assign": "^4.1.4", "object.values": "^1.1.6" } }, "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ=="], + + "kanel": ["kanel@3.16.1", "", { "dependencies": { "@kristiandupont/recase": "^1.2.1", "chalk": "4.1.2", "cli-progress": "^3.11.2", "extract-pg-schema": "^5.8.1", "optionator": "^0.9.1", "pg": "^8.10.0", "ramda": "^0.32.0", "rimraf": "^6.0.0", "tagged-comment-parser": "^1.3.5" }, "bin": { "kanel": "bin/kanel" } }, "sha512-DDc0dTrsdBWpq15Q9dw8DB2pKYOHl23QDHI6vrB01v1Fy4TGv2LZoLUi4eE9iBarEWE3DAQ3GTWq5arsDG2nSQ=="], + + "kanel-kysely": ["kanel-kysely@0.8.0", "", { "dependencies": { "@kristiandupont/recase": "^1.2.1" } }, "sha512-e5iv8pkkKPV+tktNuJvVb1/iqjyYtF1WUA15B9mehYO8ceKn0+d1KYnvcuKGPyjcUCHH0bTIs87DAO8lI9GX4Q=="], + + "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], + + "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], + + "knex": ["knex@3.1.0", "", { "dependencies": { "colorette": "2.0.19", "commander": "^10.0.0", "debug": "4.3.4", "escalade": "^3.1.1", "esm": "^3.2.25", "get-package-type": "^0.1.0", "getopts": "2.3.0", "interpret": "^2.2.0", "lodash": "^4.17.21", "pg-connection-string": "2.6.2", "rechoir": "^0.8.0", "resolve-from": "^5.0.0", "tarn": "^3.0.2", "tildify": "2.0.0" }, "bin": { "knex": "bin/cli.js" } }, "sha512-GLoII6hR0c4ti243gMs5/1Rb3B+AjwMOfjYm97pu0FOQa7JH56hgBxYf5WK2525ceSbBY1cjeZ9yk99GPMB6Kw=="], + + "knex-pglite": ["knex-pglite@0.12.1", "", { "peerDependencies": { "@electric-sql/pglite": "0.x", "knex": "3.x" } }, "sha512-7aMZfDVt2f6MQEdT1ASP/rS8T2bQCIieFGxMry9AO1zEHduI1fwqsOa0D63z3qFzHHLcEGNfSCqOfoUFbXoxtg=="], + + "kuler": ["kuler@2.0.0", "", {}, "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="], + + "kysely": ["kysely@0.27.6", "", {}, "sha512-FIyV/64EkKhJmjgC0g2hygpBv5RNWVPyNCqSAD7eTCv6eFWNIi4PN1UvdSJGicN/o35bnevgis4Y0UDC0qi8jQ=="], + + "language-subtag-registry": ["language-subtag-registry@0.3.23", "", {}, "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ=="], + + "language-tags": ["language-tags@1.0.9", "", { "dependencies": { "language-subtag-registry": "^0.3.20" } }, "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA=="], + + "lcov-parse": ["lcov-parse@1.0.0", "", { "bin": { "lcov-parse": "./bin/cli.js" } }, "sha512-aprLII/vPzuQvYZnDRU78Fns9I2Ag3gi4Ipga/hxnVMCZC8DnR2nI7XBqrPoywGfxqIx/DgarGvDJZAD3YBTgQ=="], + + "leven": ["leven@2.1.0", "", {}, "sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA=="], + + "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], + + "libtap": ["libtap@1.4.1", "", { "dependencies": { "async-hook-domain": "^2.0.4", "bind-obj-methods": "^3.0.0", "diff": "^4.0.2", "function-loop": "^2.0.1", "minipass": "^3.1.5", "own-or": "^1.0.0", "own-or-env": "^1.0.2", "signal-exit": "^3.0.4", "stack-utils": "^2.0.4", "tap-parser": "^11.0.0", "tap-yaml": "^1.0.0", "tcompare": "^5.0.6", "trivial-deferred": "^1.0.1" } }, "sha512-S9v19shLTigoMn3c02V7LZ4t09zxmVP3r3RbEAwuHFYeKgF+ESFJxoQ0PMFKW4XdgQhcjVBEwDoopG6WROq/gw=="], + + "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], + + "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="], + + "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.32.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ=="], + + "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.32.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w=="], + + "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.32.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig=="], + + "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.32.0", "", { "os": "linux", "cpu": "arm" }, "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw=="], + + "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ=="], + + "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg=="], + + "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA=="], + + "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg=="], + + "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.32.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw=="], + + "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="], + + "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], + + "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], + + "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], + + "lodash-es": ["lodash-es@4.17.23", "", {}, "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg=="], + + "lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="], + + "lodash.defaults": ["lodash.defaults@4.2.0", "", {}, "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="], + + "lodash.flatten": ["lodash.flatten@4.4.0", "", {}, "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g=="], + + "lodash.flattendeep": ["lodash.flattendeep@4.4.0", "", {}, "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ=="], + + "lodash.get": ["lodash.get@4.4.2", "", {}, "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="], + + "lodash.isarguments": ["lodash.isarguments@3.1.0", "", {}, "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg=="], + + "lodash.isequal": ["lodash.isequal@4.5.0", "", {}, "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="], + + "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], + + "lodash.throttle": ["lodash.throttle@4.1.1", "", {}, "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ=="], + + "log-driver": ["log-driver@1.2.7", "", {}, "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg=="], + + "log-update": ["log-update@3.4.0", "", { "dependencies": { "ansi-escapes": "^3.2.0", "cli-cursor": "^2.1.0", "wrap-ansi": "^5.0.0" } }, "sha512-ILKe88NeMt4gmDvk/eb615U/IVn7K9KWGkoYbdatQ69Z65nj1ZzjM6fHXfcs0Uge+e+EGnMW7DY4T9yko8vWFg=="], + + "logform": ["logform@2.7.0", "", { "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", "fecha": "^4.2.0", "ms": "^2.1.1", "safe-stable-stringify": "^2.3.1", "triple-beam": "^1.3.0" } }, "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ=="], + + "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="], + + "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], + + "loupe": ["loupe@3.2.1", "", {}, "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ=="], + + "lower-case": ["lower-case@2.0.2", "", { "dependencies": { "tslib": "^2.0.3" } }, "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg=="], + + "lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], + + "luxon": ["luxon@2.5.2", "", {}, "sha512-Yg7/RDp4nedqmLgyH0LwgGRvMEKVzKbUdkBYyCosbHgJ+kaOUx0qzSiSatVc3DFygnirTPYnMM2P5dg2uH1WvA=="], + + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + + "magicast": ["magicast@0.3.5", "", { "dependencies": { "@babel/parser": "^7.25.4", "@babel/types": "^7.25.4", "source-map-js": "^1.2.0" } }, "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ=="], + + "make-dir": ["make-dir@3.1.0", "", { "dependencies": { "semver": "^6.0.0" } }, "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw=="], + + "make-error": ["make-error@1.3.6", "", {}, "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw=="], + + "match-sorter": ["match-sorter@6.4.0", "", { "dependencies": { "@babel/runtime": "^7.23.8", "remove-accents": "0.5.0" } }, "sha512-d4664ahzdL1QTTvmK1iI0JsrxWeJ6gn33qkYtnPg3mcn+naBLtXSgSPOe+X2vUgtgGwaAk3eiaj7gwKjjMAq+Q=="], + + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + + "mdast-util-definitions": ["mdast-util-definitions@5.1.2", "", { "dependencies": { "@types/mdast": "^3.0.0", "@types/unist": "^2.0.0", "unist-util-visit": "^4.0.0" } }, "sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA=="], + + "mdast-util-from-markdown": ["mdast-util-from-markdown@1.3.1", "", { "dependencies": { "@types/mdast": "^3.0.0", "@types/unist": "^2.0.0", "decode-named-character-reference": "^1.0.0", "mdast-util-to-string": "^3.1.0", "micromark": "^3.0.0", "micromark-util-decode-numeric-character-reference": "^1.0.0", "micromark-util-decode-string": "^1.0.0", "micromark-util-normalize-identifier": "^1.0.0", "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.0", "unist-util-stringify-position": "^3.0.0", "uvu": "^0.5.0" } }, "sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww=="], + + "mdast-util-to-hast": ["mdast-util-to-hast@11.3.0", "", { "dependencies": { "@types/hast": "^2.0.0", "@types/mdast": "^3.0.0", "@types/mdurl": "^1.0.0", "mdast-util-definitions": "^5.0.0", "mdurl": "^1.0.0", "unist-builder": "^3.0.0", "unist-util-generated": "^2.0.0", "unist-util-position": "^4.0.0", "unist-util-visit": "^4.0.0" } }, "sha512-4o3Cli3hXPmm1LhB+6rqhfsIUBjnKFlIUZvudaermXB+4/KONdd/W4saWWkC+LBLbPMqhFSSTSRgafHsT5fVJw=="], + + "mdast-util-to-string": ["mdast-util-to-string@3.2.0", "", { "dependencies": { "@types/mdast": "^3.0.0" } }, "sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg=="], + + "mdurl": ["mdurl@1.0.1", "", {}, "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g=="], + + "media-typer": ["media-typer@0.3.0", "", {}, "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="], + + "memoize-one": ["memoize-one@6.0.0", "", {}, "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="], + + "memory-pager": ["memory-pager@1.5.0", "", {}, "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg=="], + + "merge-descriptors": ["merge-descriptors@1.0.3", "", {}, "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ=="], + + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], + + "methods": ["methods@1.1.2", "", {}, "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="], + + "micromark": ["micromark@3.2.0", "", { "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", "decode-named-character-reference": "^1.0.0", "micromark-core-commonmark": "^1.0.1", "micromark-factory-space": "^1.0.0", "micromark-util-character": "^1.0.0", "micromark-util-chunked": "^1.0.0", "micromark-util-combine-extensions": "^1.0.0", "micromark-util-decode-numeric-character-reference": "^1.0.0", "micromark-util-encode": "^1.0.0", "micromark-util-normalize-identifier": "^1.0.0", "micromark-util-resolve-all": "^1.0.0", "micromark-util-sanitize-uri": "^1.0.0", "micromark-util-subtokenize": "^1.0.0", "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.1", "uvu": "^0.5.0" } }, "sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA=="], + + "micromark-core-commonmark": ["micromark-core-commonmark@1.1.0", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "micromark-factory-destination": "^1.0.0", "micromark-factory-label": "^1.0.0", "micromark-factory-space": "^1.0.0", "micromark-factory-title": "^1.0.0", "micromark-factory-whitespace": "^1.0.0", "micromark-util-character": "^1.0.0", "micromark-util-chunked": "^1.0.0", "micromark-util-classify-character": "^1.0.0", "micromark-util-html-tag-name": "^1.0.0", "micromark-util-normalize-identifier": "^1.0.0", "micromark-util-resolve-all": "^1.0.0", "micromark-util-subtokenize": "^1.0.0", "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.1", "uvu": "^0.5.0" } }, "sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw=="], + + "micromark-factory-destination": ["micromark-factory-destination@1.1.0", "", { "dependencies": { "micromark-util-character": "^1.0.0", "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.0" } }, "sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg=="], + + "micromark-factory-label": ["micromark-factory-label@1.1.0", "", { "dependencies": { "micromark-util-character": "^1.0.0", "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.0", "uvu": "^0.5.0" } }, "sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w=="], + + "micromark-factory-space": ["micromark-factory-space@1.1.0", "", { "dependencies": { "micromark-util-character": "^1.0.0", "micromark-util-types": "^1.0.0" } }, "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ=="], + + "micromark-factory-title": ["micromark-factory-title@1.1.0", "", { "dependencies": { "micromark-factory-space": "^1.0.0", "micromark-util-character": "^1.0.0", "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.0" } }, "sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ=="], + + "micromark-factory-whitespace": ["micromark-factory-whitespace@1.1.0", "", { "dependencies": { "micromark-factory-space": "^1.0.0", "micromark-util-character": "^1.0.0", "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.0" } }, "sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ=="], + + "micromark-util-character": ["micromark-util-character@1.2.0", "", { "dependencies": { "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.0" } }, "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg=="], + + "micromark-util-chunked": ["micromark-util-chunked@1.1.0", "", { "dependencies": { "micromark-util-symbol": "^1.0.0" } }, "sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ=="], + + "micromark-util-classify-character": ["micromark-util-classify-character@1.1.0", "", { "dependencies": { "micromark-util-character": "^1.0.0", "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.0" } }, "sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw=="], + + "micromark-util-combine-extensions": ["micromark-util-combine-extensions@1.1.0", "", { "dependencies": { "micromark-util-chunked": "^1.0.0", "micromark-util-types": "^1.0.0" } }, "sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA=="], + + "micromark-util-decode-numeric-character-reference": ["micromark-util-decode-numeric-character-reference@1.1.0", "", { "dependencies": { "micromark-util-symbol": "^1.0.0" } }, "sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw=="], + + "micromark-util-decode-string": ["micromark-util-decode-string@1.1.0", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "micromark-util-character": "^1.0.0", "micromark-util-decode-numeric-character-reference": "^1.0.0", "micromark-util-symbol": "^1.0.0" } }, "sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ=="], + + "micromark-util-encode": ["micromark-util-encode@1.1.0", "", {}, "sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw=="], + + "micromark-util-html-tag-name": ["micromark-util-html-tag-name@1.2.0", "", {}, "sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q=="], + + "micromark-util-normalize-identifier": ["micromark-util-normalize-identifier@1.1.0", "", { "dependencies": { "micromark-util-symbol": "^1.0.0" } }, "sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q=="], + + "micromark-util-resolve-all": ["micromark-util-resolve-all@1.1.0", "", { "dependencies": { "micromark-util-types": "^1.0.0" } }, "sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA=="], + + "micromark-util-sanitize-uri": ["micromark-util-sanitize-uri@1.2.0", "", { "dependencies": { "micromark-util-character": "^1.0.0", "micromark-util-encode": "^1.0.0", "micromark-util-symbol": "^1.0.0" } }, "sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A=="], + + "micromark-util-subtokenize": ["micromark-util-subtokenize@1.1.0", "", { "dependencies": { "micromark-util-chunked": "^1.0.0", "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.0", "uvu": "^0.5.0" } }, "sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A=="], + + "micromark-util-symbol": ["micromark-util-symbol@1.1.0", "", {}, "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag=="], + + "micromark-util-types": ["micromark-util-types@1.1.0", "", {}, "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg=="], + + "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + + "microseconds": ["microseconds@0.2.0", "", {}, "sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA=="], + + "mime": ["mime@1.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="], + + "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + + "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + + "mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], + + "mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="], + + "mini-create-react-context": ["mini-create-react-context@0.3.3", "", { "dependencies": { "@babel/runtime": "^7.12.1", "tiny-warning": "^1.0.3" }, "peerDependencies": { "prop-types": "^15.0.0", "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, "sha512-TtF6hZE59SGmS4U8529qB+jJFeW6asTLDIpPgvPLSCsooAwJS7QprHIFTqv9/Qh3NdLwQxFYgiHX5lqb6jqzPA=="], + + "minimalistic-assert": ["minimalistic-assert@1.0.1", "", {}, "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="], + + "minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], + + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + + "minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "minizlib": ["minizlib@3.1.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw=="], + + "mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], + + "mkdirp-classic": ["mkdirp-classic@0.5.3", "", {}, "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="], + + "moment": ["moment@2.30.1", "", {}, "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how=="], + + "moment-timezone": ["moment-timezone@0.5.48", "", { "dependencies": { "moment": "^2.29.4" } }, "sha512-f22b8LV1gbTO2ms2j2z13MuPogNoh5UzxL3nzNAYKGraILnbGc9NEE6dyiiiLv46DGRb8A4kg8UKWLjPthxBHw=="], + + "mongodb": ["mongodb@3.6.3", "", { "dependencies": { "bl": "^2.2.1", "bson": "^1.1.4", "denque": "^1.4.1", "require_optional": "^1.0.1", "safe-buffer": "^5.1.2" }, "optionalDependencies": { "saslprep": "^1.0.0" } }, "sha512-rOZuR0QkodZiM+UbQE5kDsJykBqWi0CL4Ec2i1nrGrUI3KO11r6Fbxskqmq3JK2NH7aW4dcccBuUujAP0ERl5w=="], + + "monk": ["monk@7.3.4", "", { "dependencies": { "@types/mongodb": "^3.5.25", "debug": "*", "mongodb": "^3.2.3", "monk-middleware-cast-ids": "^0.2.1", "monk-middleware-fields": "^0.2.0", "monk-middleware-handle-callback": "^0.2.0", "monk-middleware-options": "^0.2.1", "monk-middleware-query": "^0.2.0", "monk-middleware-wait-for-connection": "^0.2.0", "object-assign": "^4.1.1" } }, "sha512-PkPNiElwroVyKQj01usyziOvwiKYBUVSq7YU1FB4KFr0J3v0GeXW0TebYsLR4u33WB8JGqPiAcuzDspfdujqQg=="], + + "monk-middleware-cast-ids": ["monk-middleware-cast-ids@0.2.1", "", {}, "sha512-Hp9gwjXo+inSPhXUlsV1u3DyZh2cXT3Osij/1gSNCJQCgacAF1lfmnTj6bKmlf1Et4dvLhwUL0PquxdZRIofkA=="], + + "monk-middleware-fields": ["monk-middleware-fields@0.2.0", "", {}, "sha512-pp+k0JeBX+HkIKnCisrtsW/QM2WGkOVG1Bd1qKLSanuBCf1l5khpdHrEullfko0HO6tCjCJMp//MsR16gd5tAw=="], + + "monk-middleware-handle-callback": ["monk-middleware-handle-callback@0.2.2", "", {}, "sha512-5hBynb7asZ2uw9XVze7C3XH0zXT51yFDvYydk/5HnWWzh2NLglDSiKDcX0yLKPHzFgiq+5Z4Laq5fFVnFsmm8w=="], + + "monk-middleware-options": ["monk-middleware-options@0.2.1", "", {}, "sha512-ypE0wGC8n5ARvOq2tlERr1uyu1edckeDRkheQLaXPRm9LoW7kr9P7xMGEjW2vmBh7IxnkpONVc7555X8x+34hQ=="], + + "monk-middleware-query": ["monk-middleware-query@0.2.0", "", {}, "sha512-BApd5HBiczJl1eVy65c9/NBVLtygBePFxuoHgar/LeMWCjWP9odSJk3vsnbxTnsOT1CMJ+hFysbaosLzDsxvtA=="], + + "monk-middleware-wait-for-connection": ["monk-middleware-wait-for-connection@0.2.0", "", {}, "sha512-jSTz73B/+pGTTvhu5Ym8xsG6+QqaWab53UXnXdNNlTijTdLvcHABCLJXudQiJxob5N1Mzr5EOSx5ziwn2sihPQ=="], + + "mqtt": ["mqtt@4.3.8", "", { "dependencies": { "commist": "^1.0.0", "concat-stream": "^2.0.0", "debug": "^4.1.1", "duplexify": "^4.1.1", "help-me": "^3.0.0", "inherits": "^2.0.3", "lru-cache": "^6.0.0", "minimist": "^1.2.5", "mqtt-packet": "^6.8.0", "number-allocator": "^1.0.9", "pump": "^3.0.0", "readable-stream": "^3.6.0", "reinterval": "^1.1.0", "rfdc": "^1.3.0", "split2": "^3.1.0", "ws": "^7.5.5", "xtend": "^4.0.2" }, "bin": { "mqtt": "bin/mqtt.js", "mqtt_pub": "bin/pub.js", "mqtt_sub": "bin/sub.js" } }, "sha512-2xT75uYa0kiPEF/PE0VPdavmEkoBzMT/UL9moid0rAvlCtV48qBwxD62m7Ld/4j8tSkIO1E/iqRl/S72SEOhOw=="], + + "mqtt-packet": ["mqtt-packet@6.10.0", "", { "dependencies": { "bl": "^4.0.2", "debug": "^4.1.1", "process-nextick-args": "^2.0.1" } }, "sha512-ja8+mFKIHdB1Tpl6vac+sktqy3gA8t9Mduom1BA75cI+R9AHnZOiaBQwpGiWnaVJLDGRdNhQmFaAqd7tkKSMGA=="], + + "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "msgpackr": ["msgpackr@1.11.8", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.2" } }, "sha512-bC4UGzHhVvgDNS7kn9tV8fAucIYUBuGojcaLiz7v+P63Lmtm0Xeji8B/8tYKddALXxJLpwIeBmUN3u64C4YkRA=="], + + "msgpackr-extract": ["msgpackr-extract@3.0.3", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA=="], + + "multer": ["multer@2.0.1", "", { "dependencies": { "append-field": "^1.0.0", "busboy": "^1.6.0", "concat-stream": "^2.0.0", "mkdirp": "^0.5.6", "object-assign": "^4.1.1", "type-is": "^1.6.18", "xtend": "^4.0.2" } }, "sha512-Ug8bXeTIUlxurg8xLTEskKShvcKDZALo1THEX5E41pYCD2sCVub5/kIRIGqWNoqV6szyLyQKV6mD4QUrWE5GCQ=="], + + "mv": ["mv@2.1.1", "", { "dependencies": { "mkdirp": "~0.5.1", "ncp": "~2.0.0", "rimraf": "~2.4.0" } }, "sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg=="], + + "mylas": ["mylas@2.1.14", "", {}, "sha512-BzQguy9W9NJgoVn2mRWzbFrFWWztGCcng2QI9+41frfk+Athwgx3qhqhvStz7ExeUUu7Kzw427sNzHpEZNINog=="], + + "nan": ["nan@2.25.0", "", {}, "sha512-0M90Ag7Xn5KMLLZ7zliPWP3rT90P6PN+IzVFS0VqmnPktBk3700xUVv8Ikm9EUaUE5SDWdp/BIxdENzVznpm1g=="], + + "nano-time": ["nano-time@1.0.0", "", { "dependencies": { "big-integer": "^1.6.16" } }, "sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA=="], + + "nanoid": ["nanoid@3.1.23", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw=="], + + "napi-build-utils": ["napi-build-utils@2.0.0", "", {}, "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA=="], + + "napi-postinstall": ["napi-postinstall@0.3.4", "", { "bin": { "napi-postinstall": "lib/cli.js" } }, "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ=="], + + "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], + + "natural-compare-lite": ["natural-compare-lite@1.4.0", "", {}, "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g=="], + + "ncp": ["ncp@2.0.0", "", { "bin": { "ncp": "./bin/ncp" } }, "sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA=="], + + "negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], + + "no-case": ["no-case@3.0.4", "", { "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" } }, "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg=="], + + "node-abi": ["node-abi@3.87.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ=="], + + "node-cache": ["node-cache@5.1.2", "", { "dependencies": { "clone": "2.x" } }, "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg=="], + + "node-exports-info": ["node-exports-info@1.6.0", "", { "dependencies": { "array.prototype.flatmap": "^1.3.3", "es-errors": "^1.3.0", "object.entries": "^1.1.9", "semver": "^6.3.1" } }, "sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw=="], + + "node-fetch": ["node-fetch@2.6.7", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ=="], + + "node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="], + + "node-html-parser": ["node-html-parser@5.4.2", "", { "dependencies": { "css-select": "^4.2.1", "he": "1.2.0" } }, "sha512-RaBPP3+51hPne/OolXxcz89iYvQvKOydaqoePpOgXcrOKZhjVIzmpKZz+Hd/RBO2/zN2q6CNJhQzucVz+u3Jyw=="], + + "node-mocks-http": ["node-mocks-http@1.11.0", "", { "dependencies": { "accepts": "^1.3.7", "content-disposition": "^0.5.3", "depd": "^1.1.0", "fresh": "^0.5.2", "merge-descriptors": "^1.0.1", "methods": "^1.1.2", "mime": "^1.3.4", "parseurl": "^1.3.3", "range-parser": "^1.2.0", "type-is": "^1.6.18" } }, "sha512-jS/WzSOcKbOeGrcgKbenZeNhxUNnP36Yw11+hL4TTxQXErGfqYZ+MaYNNvhaTiGIJlzNSqgQkk9j8dSu1YWSuw=="], + + "node-modules-regexp": ["node-modules-regexp@1.0.0", "", {}, "sha512-JMaRS9L4wSRIR+6PTVEikTrq/lMGEZR43a48ETeilY0Q0iMwVnccMFrUM1k+tNzmYuIU0Vh710bCUqHX+/+ctQ=="], + + "node-preload": ["node-preload@0.2.1", "", { "dependencies": { "process-on-spawn": "^1.0.0" } }, "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ=="], + + "node-releases": ["node-releases@2.0.36", "", {}, "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA=="], + + "nodemailer": ["nodemailer@7.0.11", "", {}, "sha512-gnXhNRE0FNhD7wPSCGhdNh46Hs6nm+uTyg+Kq0cZukNQiYdnCsoQjodNP9BQVG9XrcK/v6/MgpAPBUFyzh9pvw=="], + + "nodemon": ["nodemon@2.0.22", "", { "dependencies": { "chokidar": "^3.5.2", "debug": "^3.2.7", "ignore-by-default": "^1.0.1", "minimatch": "^3.1.2", "pstree.remy": "^1.1.8", "semver": "^5.7.1", "simple-update-notifier": "^1.0.7", "supports-color": "^5.5.0", "touch": "^3.1.0", "undefsafe": "^2.0.5" }, "bin": { "nodemon": "bin/nodemon.js" } }, "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ=="], + + "nopt": ["nopt@8.1.0", "", { "dependencies": { "abbrev": "^3.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A=="], + + "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], + + "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], + + "number-allocator": ["number-allocator@1.0.14", "", { "dependencies": { "debug": "^4.3.1", "js-sdsl": "4.3.0" } }, "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA=="], + + "nyc": ["nyc@15.1.0", "", { "dependencies": { "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.2", "caching-transform": "^4.0.0", "convert-source-map": "^1.7.0", "decamelize": "^1.2.0", "find-cache-dir": "^3.2.0", "find-up": "^4.1.0", "foreground-child": "^2.0.0", "get-package-type": "^0.1.0", "glob": "^7.1.6", "istanbul-lib-coverage": "^3.0.0", "istanbul-lib-hook": "^3.0.0", "istanbul-lib-instrument": "^4.0.0", "istanbul-lib-processinfo": "^2.0.2", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.0.2", "make-dir": "^3.0.0", "node-preload": "^0.2.1", "p-map": "^3.0.0", "process-on-spawn": "^1.0.0", "resolve-from": "^5.0.0", "rimraf": "^3.0.0", "signal-exit": "^3.0.2", "spawn-wrap": "^2.0.0", "test-exclude": "^6.0.0", "yargs": "^15.0.2" }, "bin": { "nyc": "bin/nyc.js" } }, "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A=="], + + "oauth-sign": ["oauth-sign@0.9.0", "", {}, "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="], + + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], + + "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], + + "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="], + + "object.assign": ["object.assign@4.1.7", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0", "has-symbols": "^1.1.0", "object-keys": "^1.1.1" } }, "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw=="], + + "object.entries": ["object.entries@1.1.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-object-atoms": "^1.1.1" } }, "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw=="], + + "object.fromentries": ["object.fromentries@2.0.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-object-atoms": "^1.0.0" } }, "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ=="], + + "object.groupby": ["object.groupby@1.0.3", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2" } }, "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ=="], + + "object.values": ["object.values@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA=="], + + "oblivious-set": ["oblivious-set@1.0.0", "", {}, "sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw=="], + + "on-exit-leak-free": ["on-exit-leak-free@2.1.2", "", {}, "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA=="], + + "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], + + "on-headers": ["on-headers@1.0.2", "", {}, "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="], + + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], + + "one-time": ["one-time@1.0.0", "", { "dependencies": { "fn.name": "1.x.x" } }, "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g=="], + + "onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], + + "opener": ["opener@1.5.2", "", { "bin": { "opener": "bin/opener-bin.js" } }, "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A=="], + + "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], + + "ow": ["ow@0.27.0", "", { "dependencies": { "@sindresorhus/is": "^4.0.1", "callsites": "^3.1.0", "dot-prop": "^6.0.1", "lodash.isequal": "^4.5.0", "type-fest": "^1.2.1", "vali-date": "^1.0.0" } }, "sha512-SGnrGUbhn4VaUGdU0EJLMwZWSupPmF46hnTRII7aCLCrqixTAC5eKo8kI4/XXf1eaaI8YEVT+3FeGNJI9himAQ=="], + + "own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="], + + "own-or": ["own-or@1.0.0", "", {}, "sha512-NfZr5+Tdf6MB8UI9GLvKRs4cXY8/yB0w3xtt84xFdWy8hkGjn+JFc60VhzS/hFRfbyxFcGYMTjnF4Me+RbbqrA=="], + + "own-or-env": ["own-or-env@1.0.2", "", { "dependencies": { "own-or": "^1.0.0" } }, "sha512-NQ7v0fliWtK7Lkb+WdFqe6ky9XAzYmlkXthQrBbzlYbmFKoAYbDDcwmOm6q8kOuwSRXW8bdL5ORksploUJmWgw=="], + + "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], + + "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], + + "p-map": ["p-map@3.0.0", "", { "dependencies": { "aggregate-error": "^3.0.0" } }, "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ=="], + + "p-try": ["p-try@2.2.0", "", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="], + + "package-hash": ["package-hash@4.0.0", "", { "dependencies": { "graceful-fs": "^4.1.15", "hasha": "^5.0.0", "lodash.flattendeep": "^4.4.0", "release-zalgo": "^1.0.0" } }, "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ=="], + + "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], + + "param-case": ["param-case@3.0.4", "", { "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A=="], + + "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], + + "parse-json": ["parse-json@5.2.0", "", { "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="], + + "parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], + + "parse5-htmlparser2-tree-adapter": ["parse5-htmlparser2-tree-adapter@7.1.0", "", { "dependencies": { "domhandler": "^5.0.3", "parse5": "^7.0.0" } }, "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g=="], + + "parse5-parser-stream": ["parse5-parser-stream@7.1.2", "", { "dependencies": { "parse5": "^7.0.0" } }, "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow=="], + + "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], + + "pascal-case": ["pascal-case@3.1.2", "", { "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g=="], + + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], + + "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="], + + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], + + "path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], + + "path-to-regexp": ["path-to-regexp@0.1.10", "", {}, "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w=="], + + "path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="], + + "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + + "pathval": ["pathval@2.0.1", "", {}, "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ=="], + + "performance-now": ["performance-now@2.1.0", "", {}, "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="], + + "pg": ["pg@8.20.0", "", { "dependencies": { "pg-connection-string": "^2.12.0", "pg-pool": "^3.13.0", "pg-protocol": "^1.13.0", "pg-types": "2.2.0", "pgpass": "1.0.5" }, "optionalDependencies": { "pg-cloudflare": "^1.3.0" }, "peerDependencies": { "pg-native": ">=3.0.1" }, "optionalPeers": ["pg-native"] }, "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA=="], + + "pg-cloudflare": ["pg-cloudflare@1.3.0", "", {}, "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ=="], + + "pg-connection-string": ["pg-connection-string@2.12.0", "", {}, "sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ=="], + + "pg-int8": ["pg-int8@1.0.1", "", {}, "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="], + + "pg-pool": ["pg-pool@3.13.0", "", { "peerDependencies": { "pg": ">=8.0" } }, "sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA=="], + + "pg-protocol": ["pg-protocol@1.13.0", "", {}, "sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w=="], + + "pg-query-emscripten": ["pg-query-emscripten@5.1.0", "", {}, "sha512-H1ZWOzLRddmHuE4GZqFjjo55hA9zMiePz/WDDGANA/EnvILCJps9pcRucyGd+MFvapeYOy6TWSYz6DbtBOaxRQ=="], + + "pg-types": ["pg-types@2.2.0", "", { "dependencies": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", "postgres-bytea": "~1.0.0", "postgres-date": "~1.0.4", "postgres-interval": "^1.1.0" } }, "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA=="], + + "pgpass": ["pgpass@1.0.5", "", { "dependencies": { "split2": "^4.1.0" } }, "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + + "pino": ["pino@10.3.1", "", { "dependencies": { "@pinojs/redact": "^0.4.0", "atomic-sleep": "^1.0.0", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^3.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^4.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg=="], + + "pino-abstract-transport": ["pino-abstract-transport@3.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg=="], + + "pino-pretty": ["pino-pretty@13.1.3", "", { "dependencies": { "colorette": "^2.0.7", "dateformat": "^4.6.3", "fast-copy": "^4.0.0", "fast-safe-stringify": "^2.1.1", "help-me": "^5.0.0", "joycon": "^3.1.1", "minimist": "^1.2.6", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^3.0.0", "pump": "^3.0.0", "secure-json-parse": "^4.0.0", "sonic-boom": "^4.0.1", "strip-json-comments": "^5.0.2" }, "bin": { "pino-pretty": "bin.js" } }, "sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg=="], + + "pino-std-serializers": ["pino-std-serializers@7.1.0", "", {}, "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw=="], + + "pirates": ["pirates@3.0.2", "", { "dependencies": { "node-modules-regexp": "^1.0.0" } }, "sha512-c5CgUJq6H2k6MJz72Ak1F5sN9n9wlSlJyEnwvpm9/y3WB4E3pHBDT2c6PEiS1vyJvq2bUxUAIu0EGf8Cx4Ic7Q=="], + + "pkg-dir": ["pkg-dir@4.2.0", "", { "dependencies": { "find-up": "^4.0.0" } }, "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ=="], + + "plimit-lit": ["plimit-lit@1.6.1", "", { "dependencies": { "queue-lit": "^1.5.1" } }, "sha512-B7+VDyb8Tl6oMJT9oSO2CW8XC/T4UcJGrwOVoNGwOQsQYhlpfajmrMj5xeejqaASq3V/EqThyOeATEOMuSEXiA=="], + + "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], + + "postcss": ["postcss@8.5.8", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg=="], + + "postgres-array": ["postgres-array@2.0.0", "", {}, "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="], + + "postgres-bytea": ["postgres-bytea@1.0.1", "", {}, "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ=="], + + "postgres-date": ["postgres-date@1.0.7", "", {}, "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q=="], + + "postgres-interval": ["postgres-interval@1.2.0", "", { "dependencies": { "xtend": "^4.0.0" } }, "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ=="], + + "preact": ["preact@10.12.1", "", {}, "sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg=="], + + "prebuild-install": ["prebuild-install@7.1.3", "", { "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", "github-from-package": "0.0.0", "minimist": "^1.2.3", "mkdirp-classic": "^0.5.3", "napi-build-utils": "^2.0.0", "node-abi": "^3.3.0", "pump": "^3.0.0", "rc": "^1.2.7", "simple-get": "^4.0.0", "tar-fs": "^2.0.0", "tunnel-agent": "^0.6.0" }, "bin": { "prebuild-install": "bin.js" } }, "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug=="], + + "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], + + "prettier": ["prettier@3.2.5", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A=="], + + "pretty-bytes": ["pretty-bytes@5.6.0", "", {}, "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg=="], + + "process": ["process@0.11.10", "", {}, "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="], + + "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], + + "process-on-spawn": ["process-on-spawn@1.1.0", "", { "dependencies": { "fromentries": "^1.2.0" } }, "sha512-JOnOPQ/8TZgjs1JIH/m9ni7FfimjNa/PRx7y/Wb5qdItsnhO0jE4AT7fC0HjC28DUQWDr50dwSYZLdRMlqDq3Q=="], + + "process-warning": ["process-warning@5.0.0", "", {}, "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA=="], + + "prom-client": ["prom-client@15.1.3", "", { "dependencies": { "@opentelemetry/api": "^1.4.0", "tdigest": "^0.1.1" } }, "sha512-6ZiOBfCywsD4k1BN9IX0uZhF+tJkV8q8llP64G5Hajs4JOeVLPCwpPVcpXy3BwYiUGgyJzsJJQeOIv7+hDSq8g=="], + + "promise": ["promise@7.3.1", "", { "dependencies": { "asap": "~2.0.3" } }, "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg=="], + + "prop-types": ["prop-types@15.6.0", "", { "dependencies": { "fbjs": "^0.8.16", "loose-envify": "^1.3.1", "object-assign": "^4.1.1" } }, "sha512-H16NHdiZ8szYSKNkCpmKmS8BCogxyABjJ1AqQknIY2iTpy1xC04egoBAzjKm+WU2pbuNxFonw921dnxR0QYAdw=="], + + "prop-types-extra": ["prop-types-extra@1.1.1", "", { "dependencies": { "react-is": "^16.3.2", "warning": "^4.0.0" }, "peerDependencies": { "react": ">=0.14.0" } }, "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew=="], + + "property-information": ["property-information@6.5.0", "", {}, "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig=="], + + "protobufjs": ["protobufjs@7.5.4", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg=="], + + "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], + + "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], + + "prudence": ["prudence@0.10.0", "", {}, "sha512-QPyNYQR4tx+9xp+GuceW55MWeZIC/nNT3qWUmU8eij0FmO90x3L08oY9bJiIW1weB7mvH63JBra1cY+GH70YKw=="], + + "psl": ["psl@1.15.0", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w=="], + + "pstree.remy": ["pstree.remy@1.1.8", "", {}, "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w=="], + + "pump": ["pump@3.0.4", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA=="], + + "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + + "qs": ["qs@6.11.0", "", { "dependencies": { "side-channel": "^1.0.4" } }, "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q=="], + + "queue-lit": ["queue-lit@1.5.2", "", {}, "sha512-tLc36IOPeMAubu8BkW8YDBV+WyIgKlYU7zUNs0J5Vk9skSZ4JfGlPOqplP0aHdfv7HL0B2Pg6nwiq60Qc6M2Hw=="], + + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], + + "quick-format-unescaped": ["quick-format-unescaped@4.0.4", "", {}, "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="], + + "ramda": ["ramda@0.32.0", "", {}, "sha512-GQWAHhxhxWBWA8oIBr1XahFVjQ9Fic6MK9ikijfd4TZHfE2+urfk+irVlR5VOn48uwMgM+loRRBJd6Yjsbc0zQ=="], + + "random-bytes": ["random-bytes@1.0.0", "", {}, "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ=="], + + "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], + + "rate-limit-redis": ["rate-limit-redis@2.1.0", "", { "dependencies": { "defaults": "^1.0.3", "redis": "^3.0.2" } }, "sha512-6SAsTCzY0v6UCIKLOLLYqR2XzFmgdtF7jWXlSPq2FrNIZk8tZ7xwBvyGW7GFMCe5I4S9lYNdrSJ9E84rz3/CpA=="], + + "raw-body": ["raw-body@2.5.2", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" } }, "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA=="], + + "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="], + + "react": ["react@17.0.2", "", { "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" } }, "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA=="], + + "react-async": ["react-async@10.0.1", "", { "peerDependencies": { "react": ">=16.3.1" } }, "sha512-ORUz5ca0B57QgBIzEZM5SuhJ6xFjkvEEs0gylLNlWf06vuVcLZsjIw3wx58jJkZG38p+0nUAxRgFW2b7mnVZzA=="], + + "react-async-script": ["react-async-script@1.2.0", "", { "dependencies": { "hoist-non-react-statics": "^3.3.0", "prop-types": "^15.5.0" }, "peerDependencies": { "react": ">=16.4.1" } }, "sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q=="], + + "react-bootstrap": ["react-bootstrap@2.9.0-beta.0", "", { "dependencies": { "@babel/runtime": "^7.22.5", "@restart/hooks": "^0.4.9", "@restart/ui": "^1.6.6", "@types/react-transition-group": "^4.4.6", "classnames": "^2.3.2", "dom-helpers": "^5.2.1", "invariant": "^2.2.4", "prop-types": "^15.8.1", "prop-types-extra": "^1.1.0", "react-transition-group": "^4.4.5", "uncontrollable": "^7.2.1", "warning": "^4.0.3" }, "peerDependencies": { "@types/react": ">=16.14.8", "react": ">=16.14.0", "react-dom": ">=16.14.0" }, "optionalPeers": ["@types/react"] }, "sha512-atmQhuRce7g/G+eclJn1eMZ1wbG6j8yYWrtr+Hlv/fVX0bw3QOUs62Q1G3qSqbkaZ4E625w/56GFR0rXf36Fog=="], + + "react-dom": ["react-dom@17.0.2", "", { "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", "scheduler": "^0.20.2" }, "peerDependencies": { "react": "17.0.2" } }, "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA=="], + + "react-fast-compare": ["react-fast-compare@2.0.4", "", {}, "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw=="], + + "react-google-recaptcha": ["react-google-recaptcha@2.1.0", "", { "dependencies": { "prop-types": "^15.5.0", "react-async-script": "^1.1.1" }, "peerDependencies": { "react": ">=16.4.1" } }, "sha512-K9jr7e0CWFigi8KxC3WPvNqZZ47df2RrMAta6KmRoE4RUi7Ys6NmNjytpXpg4HI/svmQJLKR+PncEPaNJ98DqQ=="], + + "react-hot-toast": ["react-hot-toast@2.0.0", "", { "dependencies": { "goober": "^2.0.35" }, "peerDependencies": { "react": ">=16", "react-dom": ">=16" } }, "sha512-J0J2rcSvKetlziVquwESgk85pV9JB0Dz3RJIZcAEv7CWU2y2z8BQqxmZHZUxjPKIBGPqXAocZch4Kj4oUdX4+w=="], + + "react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="], + + "react-lifecycles-compat": ["react-lifecycles-compat@3.0.4", "", {}, "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="], + + "react-markdown": ["react-markdown@7.0.1", "", { "dependencies": { "@types/hast": "^2.0.0", "@types/unist": "^2.0.0", "comma-separated-tokens": "^2.0.0", "prop-types": "^15.0.0", "property-information": "^6.0.0", "react-is": "^17.0.0", "remark-parse": "^10.0.0", "remark-rehype": "^9.0.0", "space-separated-tokens": "^2.0.0", "style-to-object": "^0.3.0", "unified": "^10.0.0", "unist-util-visit": "^4.0.0", "vfile": "^5.0.0" }, "peerDependencies": { "@types/react": ">=16", "react": ">=16" } }, "sha512-pthNPaoiwg0q7hukoE04F2ENwSzijIlWHJ4UMs/96LUe/G/P3FnbP4qHzx3FoNqae+2SqDG8vzniTLnJDeWneg=="], + + "react-query": ["react-query@3.18.1", "", { "dependencies": { "@babel/runtime": "^7.5.5", "broadcast-channel": "^3.4.1", "match-sorter": "^6.0.2" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0" } }, "sha512-17lv3pQxU9n+cB5acUv0/cxNTjo9q8G+RsedC6Ax4V9D8xEM7Q5xf9xAbCPdEhDrrnzPjTls9fQEABKRSi7OJA=="], + + "react-reconciler": ["react-reconciler@0.24.0", "", { "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", "prop-types": "^15.6.2", "scheduler": "^0.18.0" }, "peerDependencies": { "react": "^16.0.0" } }, "sha512-gAGnwWkf+NOTig9oOowqid9O0HjTDC+XVGBCAmJYYJ2A2cN/O4gDdIuuUQjv8A4v6GDwVfJkagpBBLW5OW9HSw=="], + + "react-router": ["react-router@5.1.2", "", { "dependencies": { "@babel/runtime": "^7.1.2", "history": "^4.9.0", "hoist-non-react-statics": "^3.1.0", "loose-envify": "^1.3.1", "mini-create-react-context": "^0.3.0", "path-to-regexp": "^1.7.0", "prop-types": "^15.6.2", "react-is": "^16.6.0", "tiny-invariant": "^1.0.2", "tiny-warning": "^1.0.0" }, "peerDependencies": { "react": ">=15" } }, "sha512-yjEuMFy1ONK246B+rsa0cUam5OeAQ8pyclRDgpxuSCrAlJ1qN9uZ5IgyKC7gQg0w8OM50NXHEegPh/ks9YuR2A=="], + + "react-router-bootstrap": ["react-router-bootstrap@0.25.0", "", { "dependencies": { "prop-types": "^15.5.10" }, "peerDependencies": { "react": ">=0.14.0", "react-router-dom": ">=4.0.0" } }, "sha512-/22eqxjn6Zv5fvY2rZHn57SKmjmJfK7xzJ6/G1OgxAjLtKVfWgV5sn41W2yiqzbtV5eE4/i4LeDLBGYTqx7jbA=="], + + "react-router-dom": ["react-router-dom@5.1.2", "", { "dependencies": { "@babel/runtime": "^7.1.2", "history": "^4.9.0", "loose-envify": "^1.3.1", "prop-types": "^15.6.2", "react-router": "5.1.2", "tiny-invariant": "^1.0.2", "tiny-warning": "^1.0.0" }, "peerDependencies": { "react": ">=15" } }, "sha512-7BPHAaIwWpZS074UKaw1FjVdZBSVWEk8IuDXdB+OkLb8vd/WRQIpA4ag9WQk61aEfQs47wHyjWUoUGGZxpQXew=="], + + "react-select": ["react-select@5.10.2", "", { "dependencies": { "@babel/runtime": "^7.12.0", "@emotion/cache": "^11.4.0", "@emotion/react": "^11.8.1", "@floating-ui/dom": "^1.0.1", "@types/react-transition-group": "^4.4.0", "memoize-one": "^6.0.0", "prop-types": "^15.6.0", "react-transition-group": "^4.3.0", "use-isomorphic-layout-effect": "^1.2.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Z33nHdEFWq9tfnfVXaiM12rbJmk+QjFEztWLtmXqQhz6Al4UZZ9xc0wiatmGtUOCCnHN0WizL3tCMYRENX4rVQ=="], + + "react-transition-group": ["react-transition-group@4.4.5", "", { "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", "loose-envify": "^1.4.0", "prop-types": "^15.6.2" }, "peerDependencies": { "react": ">=16.6.0", "react-dom": ">=16.6.0" } }, "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g=="], + + "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + + "readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], + + "real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="], + + "rechoir": ["rechoir@0.8.0", "", { "dependencies": { "resolve": "^1.20.0" } }, "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ=="], + + "redeyed": ["redeyed@2.1.1", "", { "dependencies": { "esprima": "~4.0.0" } }, "sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ=="], + + "redis": ["redis@3.1.2", "", { "dependencies": { "denque": "^1.5.0", "redis-commands": "^1.7.0", "redis-errors": "^1.2.0", "redis-parser": "^3.0.0" } }, "sha512-grn5KoZLr/qrRQVwoSkmzdbw6pwF+/rwODtrOr6vuBRiR/f3rjSTGupbF90Zpqm2oenix8Do6RV7pYEkGwlKkw=="], + + "redis-commands": ["redis-commands@1.7.0", "", {}, "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ=="], + + "redis-errors": ["redis-errors@1.2.0", "", {}, "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w=="], + + "redis-parser": ["redis-parser@3.0.0", "", { "dependencies": { "redis-errors": "^1.0.0" } }, "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A=="], + + "reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="], + + "regexp.prototype.flags": ["regexp.prototype.flags@1.5.4", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-errors": "^1.3.0", "get-proto": "^1.0.1", "gopd": "^1.2.0", "set-function-name": "^2.0.2" } }, "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA=="], + + "regexpp": ["regexpp@3.2.0", "", {}, "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg=="], + + "reinterval": ["reinterval@1.1.0", "", {}, "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ=="], + + "relateurl": ["relateurl@0.2.7", "", {}, "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog=="], + + "release-zalgo": ["release-zalgo@1.0.0", "", { "dependencies": { "es6-error": "^4.0.1" } }, "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA=="], + + "remark-parse": ["remark-parse@10.0.2", "", { "dependencies": { "@types/mdast": "^3.0.0", "mdast-util-from-markdown": "^1.0.0", "unified": "^10.0.0" } }, "sha512-3ydxgHa/ZQzG8LvC7jTXccARYDcRld3VfcgIIFs7bI6vbRSxJJmzgLEIIoYKyrfhaY+ujuWaf/PJiMZXoiCXgw=="], + + "remark-rehype": ["remark-rehype@9.1.0", "", { "dependencies": { "@types/hast": "^2.0.0", "@types/mdast": "^3.0.0", "mdast-util-to-hast": "^11.0.0", "unified": "^10.0.0" } }, "sha512-oLa6YmgAYg19zb0ZrBACh40hpBLteYROaPLhBXzLgjqyHQrN+gVP9N/FJvfzuNNuzCutktkroXEZBrxAxKhh7Q=="], + + "remove-accents": ["remove-accents@0.5.0", "", {}, "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A=="], + + "request": ["request@2.88.2", "", { "dependencies": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", "caseless": "~0.12.0", "combined-stream": "~1.0.6", "extend": "~3.0.2", "forever-agent": "~0.6.1", "form-data": "~2.3.2", "har-validator": "~5.1.3", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", "mime-types": "~2.1.19", "oauth-sign": "~0.9.0", "performance-now": "^2.1.0", "qs": "~6.5.2", "safe-buffer": "^5.1.2", "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" } }, "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw=="], + + "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + + "require-main-filename": ["require-main-filename@2.0.0", "", {}, "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="], + + "require_optional": ["require_optional@1.0.1", "", { "dependencies": { "resolve-from": "^2.0.0", "semver": "^5.1.0" } }, "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g=="], + + "resolve": ["resolve@2.0.0-next.6", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "node-exports-info": "^1.6.0", "object-keys": "^1.1.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA=="], + + "resolve-from": ["resolve-from@3.0.0", "", {}, "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw=="], + + "resolve-pathname": ["resolve-pathname@3.0.0", "", {}, "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng=="], + + "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], + + "restore-cursor": ["restore-cursor@3.1.0", "", { "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA=="], + + "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], + + "rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="], + + "rg-stats": ["rg-stats@1.2.1", "", {}, "sha512-mpZaD0jxf4xdWS6ddYnfnKG7Ov0okB0OiLEgxCrX4NiHH3TCFTjsCOocFBxprtP/5qiGH7x+daGGjg2L6iK+PQ=="], + + "rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="], + + "rolldown": ["rolldown@1.0.0-rc.9", "", { "dependencies": { "@oxc-project/types": "=0.115.0", "@rolldown/pluginutils": "1.0.0-rc.9" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-rc.9", "@rolldown/binding-darwin-arm64": "1.0.0-rc.9", "@rolldown/binding-darwin-x64": "1.0.0-rc.9", "@rolldown/binding-freebsd-x64": "1.0.0-rc.9", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.9", "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.9", "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.9", "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.9", "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.9", "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.9", "@rolldown/binding-linux-x64-musl": "1.0.0-rc.9", "@rolldown/binding-openharmony-arm64": "1.0.0-rc.9", "@rolldown/binding-wasm32-wasi": "1.0.0-rc.9", "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.9", "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.9" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-9EbgWge7ZH+yqb4d2EnELAntgPTWbfL8ajiTW+SyhJEC4qhBbkCKbqFV4Ge4zmu5ziQuVbWxb/XwLZ+RIO7E8Q=="], + + "rollup": ["rollup@4.59.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.59.0", "@rollup/rollup-android-arm64": "4.59.0", "@rollup/rollup-darwin-arm64": "4.59.0", "@rollup/rollup-darwin-x64": "4.59.0", "@rollup/rollup-freebsd-arm64": "4.59.0", "@rollup/rollup-freebsd-x64": "4.59.0", "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", "@rollup/rollup-linux-arm-musleabihf": "4.59.0", "@rollup/rollup-linux-arm64-gnu": "4.59.0", "@rollup/rollup-linux-arm64-musl": "4.59.0", "@rollup/rollup-linux-loong64-gnu": "4.59.0", "@rollup/rollup-linux-loong64-musl": "4.59.0", "@rollup/rollup-linux-ppc64-gnu": "4.59.0", "@rollup/rollup-linux-ppc64-musl": "4.59.0", "@rollup/rollup-linux-riscv64-gnu": "4.59.0", "@rollup/rollup-linux-riscv64-musl": "4.59.0", "@rollup/rollup-linux-s390x-gnu": "4.59.0", "@rollup/rollup-linux-x64-gnu": "4.59.0", "@rollup/rollup-linux-x64-musl": "4.59.0", "@rollup/rollup-openbsd-x64": "4.59.0", "@rollup/rollup-openharmony-arm64": "4.59.0", "@rollup/rollup-win32-arm64-msvc": "4.59.0", "@rollup/rollup-win32-ia32-msvc": "4.59.0", "@rollup/rollup-win32-x64-gnu": "4.59.0", "@rollup/rollup-win32-x64-msvc": "4.59.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg=="], + + "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], + + "sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="], + + "safe-array-concat": ["safe-array-concat@1.1.3", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "has-symbols": "^1.1.0", "isarray": "^2.0.5" } }, "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q=="], + + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "safe-json-stringify": ["safe-json-stringify@1.2.0", "", {}, "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg=="], + + "safe-push-apply": ["safe-push-apply@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "isarray": "^2.0.5" } }, "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA=="], + + "safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-regex": "^1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="], + + "safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="], + + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + + "saslprep": ["saslprep@1.0.3", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag=="], + + "sass": ["sass@1.64.1", "", { "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", "source-map-js": ">=0.6.2 <2.0.0" }, "bin": { "sass": "sass.js" } }, "sha512-16rRACSOFEE8VN7SCgBu1MpYCyN7urj9At898tyzdXFhC+a+yOX5dXwAR7L8/IdPJ1NB8OYoXmD55DM30B2kEQ=="], + + "scheduler": ["scheduler@0.20.2", "", { "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" } }, "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ=="], + + "secure-json-parse": ["secure-json-parse@4.1.0", "", {}, "sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA=="], + + "semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], + + "send": ["send@0.19.0", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "~1.2.1", "statuses": "2.0.1" } }, "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw=="], + + "seq-logging": ["seq-logging@1.1.1", "", {}, "sha512-9miWILWu22dKNCkZi2UePAnZeQEzaYsQRKbAi5eSBUbuOyyeYPyYO1bEvIvZAZRjltEwY1S0yz94hc0/f+niDg=="], + + "serve-static": ["serve-static@1.16.0", "", { "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "0.18.0" } }, "sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA=="], + + "set-blocking": ["set-blocking@2.0.0", "", {}, "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="], + + "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], + + "set-function-name": ["set-function-name@2.0.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", "has-property-descriptors": "^1.0.2" } }, "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ=="], + + "set-proto": ["set-proto@1.0.0", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0" } }, "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw=="], + + "setimmediate": ["setimmediate@1.0.5", "", {}, "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="], + + "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], + + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], + + "side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="], + + "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], + + "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], + + "siginfo": ["siginfo@2.0.0", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="], + + "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], + + "simple-concat": ["simple-concat@1.0.1", "", {}, "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="], + + "simple-get": ["simple-get@4.0.1", "", { "dependencies": { "decompress-response": "^6.0.0", "once": "^1.3.1", "simple-concat": "^1.0.0" } }, "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA=="], + + "simple-update-notifier": ["simple-update-notifier@1.1.0", "", { "dependencies": { "semver": "~7.0.0" } }, "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg=="], + + "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], + + "slice-ansi": ["slice-ansi@3.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", "is-fullwidth-code-point": "^3.0.0" } }, "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ=="], + + "snappy": ["snappy@7.3.3", "", { "optionalDependencies": { "@napi-rs/snappy-android-arm-eabi": "7.3.3", "@napi-rs/snappy-android-arm64": "7.3.3", "@napi-rs/snappy-darwin-arm64": "7.3.3", "@napi-rs/snappy-darwin-x64": "7.3.3", "@napi-rs/snappy-freebsd-x64": "7.3.3", "@napi-rs/snappy-linux-arm-gnueabihf": "7.3.3", "@napi-rs/snappy-linux-arm64-gnu": "7.3.3", "@napi-rs/snappy-linux-arm64-musl": "7.3.3", "@napi-rs/snappy-linux-ppc64-gnu": "7.3.3", "@napi-rs/snappy-linux-riscv64-gnu": "7.3.3", "@napi-rs/snappy-linux-s390x-gnu": "7.3.3", "@napi-rs/snappy-linux-x64-gnu": "7.3.3", "@napi-rs/snappy-linux-x64-musl": "7.3.3", "@napi-rs/snappy-openharmony-arm64": "7.3.3", "@napi-rs/snappy-wasm32-wasi": "7.3.3", "@napi-rs/snappy-win32-arm64-msvc": "7.3.3", "@napi-rs/snappy-win32-ia32-msvc": "7.3.3", "@napi-rs/snappy-win32-x64-msvc": "7.3.3" } }, "sha512-UDJVCunvgblRpfTOjo/uT7pQzfrTsSICJ4yVS4aq7SsGBaUSpJwaVP15nF//jqinSLpN7boe/BqbUmtWMTQ5MQ=="], + + "sonic-boom": ["sonic-boom@4.2.1", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q=="], + + "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="], + + "space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="], + + "sparse-bitfield": ["sparse-bitfield@3.0.3", "", { "dependencies": { "memory-pager": "^1.0.2" } }, "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ=="], + + "spawn-wrap": ["spawn-wrap@2.0.0", "", { "dependencies": { "foreground-child": "^2.0.0", "is-windows": "^1.0.2", "make-dir": "^3.0.0", "rimraf": "^3.0.0", "signal-exit": "^3.0.2", "which": "^2.0.1" } }, "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg=="], + + "split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="], + + "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], + + "sshpk": ["sshpk@1.18.0", "", { "dependencies": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", "bcrypt-pbkdf": "^1.0.0", "dashdash": "^1.12.0", "ecc-jsbn": "~0.1.1", "getpass": "^0.1.1", "jsbn": "~0.1.0", "safer-buffer": "^2.0.2", "tweetnacl": "~0.14.0" }, "bin": { "sshpk-conv": "bin/sshpk-conv", "sshpk-sign": "bin/sshpk-sign", "sshpk-verify": "bin/sshpk-verify" } }, "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ=="], + + "stable-hash": ["stable-hash@0.0.5", "", {}, "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA=="], + + "stack-trace": ["stack-trace@0.0.10", "", {}, "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg=="], + + "stack-utils": ["stack-utils@2.0.6", "", { "dependencies": { "escape-string-regexp": "^2.0.0" } }, "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ=="], + + "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="], + + "standard-as-callback": ["standard-as-callback@2.1.0", "", {}, "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="], + + "statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], + + "std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="], + + "stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="], + + "stream-shift": ["stream-shift@1.0.3", "", {}, "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ=="], + + "streamsearch": ["streamsearch@1.1.0", "", {}, "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="], + + "string-length": ["string-length@3.1.0", "", { "dependencies": { "astral-regex": "^1.0.0", "strip-ansi": "^5.2.0" } }, "sha512-Ttp5YvkGm5v9Ijagtaz1BnN+k9ObpvS0eIBblPMp2YWL8FBmi9qblQ9fexc2k/CXFgrTIteU3jAw3payCnwSTA=="], + + "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "string.prototype.includes": ["string.prototype.includes@2.0.1", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.3" } }, "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg=="], + + "string.prototype.matchall": ["string.prototype.matchall@4.0.12", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.6", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "regexp.prototype.flags": "^1.5.3", "set-function-name": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA=="], + + "string.prototype.repeat": ["string.prototype.repeat@1.0.0", "", { "dependencies": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" } }, "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w=="], + + "string.prototype.trim": ["string.prototype.trim@1.2.10", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-data-property": "^1.1.4", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-object-atoms": "^1.0.0", "has-property-descriptors": "^1.0.2" } }, "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA=="], + + "string.prototype.trimend": ["string.prototype.trimend@1.0.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ=="], + + "string.prototype.trimstart": ["string.prototype.trimstart@1.0.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg=="], + + "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], + + "strip-ansi": ["strip-ansi@5.2.0", "", { "dependencies": { "ansi-regex": "^4.1.0" } }, "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA=="], + + "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="], + + "strip-json-comments": ["strip-json-comments@5.0.3", "", {}, "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw=="], + + "strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="], + + "strnum": ["strnum@1.1.2", "", {}, "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA=="], + + "style-to-object": ["style-to-object@0.3.0", "", { "dependencies": { "inline-style-parser": "0.1.1" } }, "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA=="], + + "stylis": ["stylis@4.2.0", "", {}, "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw=="], + + "superagent": ["superagent@7.1.6", "", { "dependencies": { "component-emitter": "^1.3.0", "cookiejar": "^2.1.3", "debug": "^4.3.4", "fast-safe-stringify": "^2.1.1", "form-data": "^4.0.0", "formidable": "^2.0.1", "methods": "^1.1.2", "mime": "2.6.0", "qs": "^6.10.3", "readable-stream": "^3.6.0", "semver": "^7.3.7" } }, "sha512-gZkVCQR1gy/oUXr+kxJMLDjla434KmSOKbx5iGD30Ql+AkJQ/YlPKECJy2nhqOsHLjGHzoDTXNSjhnvWhzKk7g=="], + + "supertest": ["supertest@6.2.2", "", { "dependencies": { "methods": "^1.1.2", "superagent": "^7.1.0" } }, "sha512-wCw9WhAtKJsBvh07RaS+/By91NNE0Wh0DN19/hWPlBOU8tAfOtbZoVSV4xXeoKoxgPx0rx2y+y+8660XtE7jzg=="], + + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + + "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], + + "sync-fetch": ["sync-fetch@0.3.1", "", { "dependencies": { "buffer": "^5.7.0", "node-fetch": "^2.6.1" } }, "sha512-xj5qiCDap/03kpci5a+qc5wSJjc8ZSixgG2EUmH1B8Ea2sfWclQA7eH40hiHPCtkCn6MCk4Wb+dqcXdCy2PP3g=="], + + "tachi-autogen-docs": ["tachi-autogen-docs@workspace:typescript/docs-autogen-scripts"], + + "tachi-bot": ["tachi-bot@workspace:typescript/bot"], + + "tachi-client": ["tachi-client@workspace:typescript/client"], + + "tachi-common": ["tachi-common@workspace:typescript/common"], + + "tachi-db": ["tachi-db@workspace:typescript/db"], + + "tachi-db-migration-engine": ["tachi-db-migration-engine@workspace:typescript/db-migration-engine"], + + "tachi-db-migration-engine-cli": ["tachi-db-migration-engine-cli@workspace:typescript/db-cli"], + + "tachi-github-bot": ["tachi-github-bot@workspace:typescript/github-bot"], + + "tachi-seeds-scripts": ["tachi-seeds-scripts@workspace:typescript/seeds-scripts"], + + "tachi-server": ["tachi-server@workspace:typescript/server"], + + "tachi-sieglinde": ["tachi-sieglinde@workspace:typescript/sieglinde"], + + "tagged-comment-parser": ["tagged-comment-parser@1.3.8", "", {}, "sha512-HYkOQ/8ha113ln/Vp48wiDTPtbB59AWOdU44AXjhLyJLJjWWfn2kjnXUcyWLQepwbixA/mEeo1iW2Z9OwaBClQ=="], + + "tap": ["tap@workspace:typescript-vendor/tap"], + + "tap-mocha-reporter": ["tap-mocha-reporter@5.0.4", "", { "dependencies": { "color-support": "^1.1.0", "debug": "^4.1.1", "diff": "^4.0.1", "escape-string-regexp": "^2.0.0", "glob": "^7.0.5", "tap-parser": "^11.0.0", "tap-yaml": "^1.0.0", "unicode-length": "^2.0.2" }, "bin": { "tap-mocha-reporter": "index.js" } }, "sha512-J+YMO8B7lq1O6Zxd/jeuG27vJ+Y4tLiRMKPSb7KR6FVh86k3Rq1TwYc2GKPyIjCbzzdMdReh3Vfz9L5cg1Z2Bw=="], + + "tap-parser": ["tap-parser@10.1.0", "", { "dependencies": { "events-to-array": "^1.0.1", "minipass": "^3.0.0", "tap-yaml": "^1.0.0" }, "bin": { "tap-parser": "bin/cmd.js" } }, "sha512-FujQeciDaOiOvaIVGS1Rpb0v4R6XkOjvWCWowlz5oKuhPkEJ8U6pxgqt38xuzYhPt8dWEnfHn2jqpZdJEkW7pA=="], + + "tap-yaml": ["tap-yaml@1.0.2", "", { "dependencies": { "yaml": "^1.10.2" } }, "sha512-GegASpuqBnRNdT1U+yuUPZ8rEU64pL35WPBpCISWwff4dErS2/438barz7WFJl4Nzh3Y05tfPidZnH+GaV1wMg=="], + + "tar": ["tar@7.5.10", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-8mOPs1//5q/rlkNSPcCegA6hiHJYDmSLEI8aMH/CdSQJNWztHC9WHNam5zdQlfpTwB9Xp7IBEsHfV5LKMJGVAw=="], + + "tar-fs": ["tar-fs@2.1.4", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ=="], + + "tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="], + + "tarn": ["tarn@3.0.2", "", {}, "sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ=="], + + "tcompare": ["tcompare@5.0.7", "", { "dependencies": { "diff": "^4.0.2" } }, "sha512-d9iddt6YYGgyxJw5bjsN7UJUO1kGOtjSlNy/4PoGYAjQS5pAT/hzIoLf1bZCw+uUxRmZJh7Yy1aA7xKVRT9B4w=="], + + "tdigest": ["tdigest@0.1.2", "", { "dependencies": { "bintrees": "1.0.2" } }, "sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA=="], + + "terser": ["terser@5.46.0", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg=="], + + "test-exclude": ["test-exclude@7.0.2", "", { "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^10.4.1", "minimatch": "^10.2.2" } }, "sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw=="], + + "text-hex": ["text-hex@1.0.0", "", {}, "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="], + + "thread-stream": ["thread-stream@4.0.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA=="], + + "tildify": ["tildify@2.0.0", "", {}, "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw=="], + + "tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="], + + "tiny-warning": ["tiny-warning@1.0.3", "", {}, "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="], + + "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="], + + "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], + + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], + + "tinypool": ["tinypool@1.1.1", "", {}, "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg=="], + + "tinyrainbow": ["tinyrainbow@2.0.0", "", {}, "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw=="], + + "tinyspy": ["tinyspy@4.0.4", "", {}, "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q=="], + + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + + "toad-cache": ["toad-cache@3.7.0", "", {}, "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw=="], + + "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], + + "touch": ["touch@3.1.1", "", { "bin": { "nodetouch": "bin/nodetouch.js" } }, "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA=="], + + "tough-cookie": ["tough-cookie@2.5.0", "", { "dependencies": { "psl": "^1.1.28", "punycode": "^2.1.1" } }, "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g=="], + + "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], + + "treport": ["treport@2.0.2", "", { "dependencies": { "cardinal": "^2.1.1", "chalk": "^3.0.0", "import-jsx": "^4.0.0", "ink": "^2.6.0", "ms": "^2.1.2", "string-length": "^3.1.0", "tap-parser": "^10.0.1", "unicode-length": "^2.0.2" }, "peerDependencies": { "react": "^16.8.6" } }, "sha512-AnHKgHMy3II7Arfvf1tSHAwv9rzcvgbWrOixFJgdExVKd0mMsOp9wD2LGP9RbXy9j8AZoerBVu3OR2Uz9MpUJw=="], + + "triple-beam": ["triple-beam@1.4.1", "", {}, "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg=="], + + "trivial-deferred": ["trivial-deferred@1.1.2", "", {}, "sha512-vDPiDBC3hyP6O4JrJYMImW3nl3c03Tsj9fEXc7Qc/XKa1O7gf5ZtFfIR/E0dun9SnDHdwjna1Z2rSzYgqpxh/g=="], + + "trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="], + + "ts-api-utils": ["ts-api-utils@2.4.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA=="], + + "ts-mixer": ["ts-mixer@6.0.4", "", {}, "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA=="], + + "ts-node": ["ts-node@10.9.1", "", { "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", "@tsconfig/node12": "^1.0.7", "@tsconfig/node14": "^1.0.0", "@tsconfig/node16": "^1.0.2", "acorn": "^8.4.1", "acorn-walk": "^8.1.1", "arg": "^4.1.0", "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", "v8-compile-cache-lib": "^3.0.1", "yn": "3.1.1" }, "peerDependencies": { "@swc/core": ">=1.2.50", "@swc/wasm": ">=1.2.50", "@types/node": "*", "typescript": ">=2.7" }, "optionalPeers": ["@swc/core", "@swc/wasm"], "bin": { "ts-node": "dist/bin.js", "ts-script": "dist/bin-script-deprecated.js", "ts-node-cwd": "dist/bin-cwd.js", "ts-node-esm": "dist/bin-esm.js", "ts-node-script": "dist/bin-script.js", "ts-node-transpile-only": "dist/bin-transpile.js" } }, "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw=="], + + "ts-protoc-gen": ["ts-protoc-gen@0.15.0", "", { "dependencies": { "google-protobuf": "^3.15.5" }, "bin": { "protoc-gen-ts": "bin/protoc-gen-ts" } }, "sha512-TycnzEyrdVDlATJ3bWFTtra3SCiEP0W0vySXReAuEygXCUr1j2uaVyL0DhzjwuUdQoW5oXPwk6oZWeA0955V+g=="], + + "tsc-alias": ["tsc-alias@1.7.1", "", { "dependencies": { "chokidar": "^3.5.3", "commander": "^9.0.0", "globby": "^11.0.4", "mylas": "^2.1.9", "normalize-path": "^3.0.0", "plimit-lit": "^1.2.6" }, "bin": { "tsc-alias": "dist/bin/index.js" } }, "sha512-P4+0i+OB0hX17Ca+U6EJ4WZZ+OSupqW32VJ34N7g7+Ch+bwSx1AqYOvDdIVYEKymBh3dfG0t1qxbxPlBbtB1lQ=="], + + "tsconfig-paths": ["tsconfig-paths@3.12.0", "", { "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.1", "minimist": "^1.2.0", "strip-bom": "^3.0.0" } }, "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "tsutils": ["tsutils@3.21.0", "", { "dependencies": { "tslib": "^1.8.1" }, "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" } }, "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA=="], + + "tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="], + + "tweetnacl": ["tweetnacl@0.14.5", "", {}, "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="], + + "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], + + "type-fest": ["type-fest@1.4.0", "", {}, "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA=="], + + "type-is": ["type-is@1.6.18", "", { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="], + + "typed-array-buffer": ["typed-array-buffer@1.0.3", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-typed-array": "^1.1.14" } }, "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw=="], + + "typed-array-byte-length": ["typed-array-byte-length@1.0.3", "", { "dependencies": { "call-bind": "^1.0.8", "for-each": "^0.3.3", "gopd": "^1.2.0", "has-proto": "^1.2.0", "is-typed-array": "^1.1.14" } }, "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg=="], + + "typed-array-byte-offset": ["typed-array-byte-offset@1.0.4", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "for-each": "^0.3.3", "gopd": "^1.2.0", "has-proto": "^1.2.0", "is-typed-array": "^1.1.15", "reflect.getprototypeof": "^1.0.9" } }, "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ=="], + + "typed-array-length": ["typed-array-length@1.0.7", "", { "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", "is-typed-array": "^1.1.13", "possible-typed-array-names": "^1.0.0", "reflect.getprototypeof": "^1.0.6" } }, "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg=="], + + "typedarray": ["typedarray@0.0.6", "", {}, "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="], + + "typedarray-to-buffer": ["typedarray-to-buffer@3.1.5", "", { "dependencies": { "is-typedarray": "^1.0.0" } }, "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q=="], + + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + + "typescript-eslint": ["typescript-eslint@8.56.1", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.56.1", "@typescript-eslint/parser": "8.56.1", "@typescript-eslint/typescript-estree": "8.56.1", "@typescript-eslint/utils": "8.56.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ=="], + + "ua-parser-js": ["ua-parser-js@0.7.41", "", { "bin": { "ua-parser-js": "script/cli.js" } }, "sha512-O3oYyCMPYgNNHuO7Jjk3uacJWZF8loBgwrfd/5LE/HyZ3lUIOdniQ7DNXJcIgZbwioZxk0fLfI4EVnetdiX5jg=="], + + "uid-safe": ["uid-safe@2.1.5", "", { "dependencies": { "random-bytes": "~1.0.0" } }, "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA=="], + + "unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="], + + "uncontrollable": ["uncontrollable@7.2.1", "", { "dependencies": { "@babel/runtime": "^7.6.3", "@types/react": ">=16.9.11", "invariant": "^2.2.4", "react-lifecycles-compat": "^3.0.4" }, "peerDependencies": { "react": ">=15.0.0" } }, "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ=="], + + "undefsafe": ["undefsafe@2.0.5", "", {}, "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA=="], + + "undici": ["undici@7.22.0", "", {}, "sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg=="], + + "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], + + "unicode-length": ["unicode-length@2.1.0", "", { "dependencies": { "punycode": "^2.0.0" } }, "sha512-4bV582zTV9Q02RXBxSUMiuN/KHo5w4aTojuKTNT96DIKps/SIawFp7cS5Mu25VuY1AioGXrmYyzKZUzh8OqoUw=="], + + "unified": ["unified@10.1.2", "", { "dependencies": { "@types/unist": "^2.0.0", "bail": "^2.0.0", "extend": "^3.0.0", "is-buffer": "^2.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^5.0.0" } }, "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q=="], + + "unist-builder": ["unist-builder@3.0.1", "", { "dependencies": { "@types/unist": "^2.0.0" } }, "sha512-gnpOw7DIpCA0vpr6NqdPvTWnlPTApCTRzr+38E6hCWx3rz/cjo83SsKIlS1Z+L5ttScQ2AwutNnb8+tAvpb6qQ=="], + + "unist-util-generated": ["unist-util-generated@2.0.1", "", {}, "sha512-qF72kLmPxAw0oN2fwpWIqbXAVyEqUzDHMsbtPvOudIlUzXYFIeQIuxXQCRCFh22B7cixvU0MG7m3MW8FTq/S+A=="], + + "unist-util-is": ["unist-util-is@5.2.1", "", { "dependencies": { "@types/unist": "^2.0.0" } }, "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw=="], + + "unist-util-position": ["unist-util-position@4.0.4", "", { "dependencies": { "@types/unist": "^2.0.0" } }, "sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg=="], + + "unist-util-stringify-position": ["unist-util-stringify-position@3.0.3", "", { "dependencies": { "@types/unist": "^2.0.0" } }, "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg=="], + + "unist-util-visit": ["unist-util-visit@4.1.2", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0", "unist-util-visit-parents": "^5.1.1" } }, "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg=="], + + "unist-util-visit-parents": ["unist-util-visit-parents@5.1.3", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0" } }, "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg=="], + + "universal-github-app-jwt": ["universal-github-app-jwt@2.2.2", "", {}, "sha512-dcmbeSrOdTnsjGjUfAlqNDJrhxXizjAz94ija9Qw8YkZ1uu0d+GoZzyH+Jb9tIIqvGsadUfwg+22k5aDqqwzbw=="], + + "universal-user-agent": ["universal-user-agent@7.0.3", "", {}, "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A=="], + + "universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], + + "unload": ["unload@2.2.0", "", { "dependencies": { "@babel/runtime": "^7.6.2", "detect-node": "^2.0.4" } }, "sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA=="], + + "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], + + "unrs-resolver": ["unrs-resolver@1.11.1", "", { "dependencies": { "napi-postinstall": "^0.3.0" }, "optionalDependencies": { "@unrs/resolver-binding-android-arm-eabi": "1.11.1", "@unrs/resolver-binding-android-arm64": "1.11.1", "@unrs/resolver-binding-darwin-arm64": "1.11.1", "@unrs/resolver-binding-darwin-x64": "1.11.1", "@unrs/resolver-binding-freebsd-x64": "1.11.1", "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-musl": "1.11.1", "@unrs/resolver-binding-wasm32-wasi": "1.11.1", "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" } }, "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg=="], + + "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], + + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + + "url-polyfill": ["url-polyfill@1.1.14", "", {}, "sha512-p4f3TTAG6ADVF3mwbXw7hGw+QJyw5CnNGvYh5fCuQQZIiuKUswqcznyV3pGDP9j0TSmC4UvRKm8kl1QsX1diiQ=="], + + "url-value-parser": ["url-value-parser@2.2.0", "", {}, "sha512-yIQdxJpgkPamPPAPuGdS7Q548rLhny42tg8d4vyTNzFqvOnwqrgHXvgehT09U7fwrzxi3RxCiXjoNUNnNOlQ8A=="], + + "use-isomorphic-layout-effect": ["use-isomorphic-layout-effect@1.2.1", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA=="], + + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + + "utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="], + + "uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], + + "uuidv7": ["uuidv7@1.1.0", "", { "bin": { "uuidv7": "cli.js" } }, "sha512-2VNnOC0+XQlwogChUDzy6pe8GQEys9QFZBGOh54l6qVfwoCUwwRvk7rDTgaIsRgsF5GFa5oiNg8LqXE3jofBBg=="], + + "uvu": ["uvu@0.5.6", "", { "dependencies": { "dequal": "^2.0.0", "diff": "^5.0.0", "kleur": "^4.0.3", "sade": "^1.7.3" }, "bin": { "uvu": "bin.js" } }, "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA=="], + + "v8-compile-cache-lib": ["v8-compile-cache-lib@3.0.1", "", {}, "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg=="], + + "vali-date": ["vali-date@1.0.0", "", {}, "sha512-sgECfZthyaCKW10N0fm27cg8HYTFK5qMWgypqkXMQ4Wbl/zZKx7xZICgcoxIIE+WFAP/MBL2EFwC/YvLxw3Zeg=="], + + "value-equal": ["value-equal@1.0.1", "", {}, "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw=="], + + "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], + + "verror": ["verror@1.10.0", "", { "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw=="], + + "vfile": ["vfile@5.3.7", "", { "dependencies": { "@types/unist": "^2.0.0", "is-buffer": "^2.0.0", "unist-util-stringify-position": "^3.0.0", "vfile-message": "^3.0.0" } }, "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g=="], + + "vfile-message": ["vfile-message@3.1.4", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-stringify-position": "^3.0.0" } }, "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw=="], + + "vite": ["vite@8.0.0", "", { "dependencies": { "@oxc-project/runtime": "0.115.0", "lightningcss": "^1.32.0", "picomatch": "^4.0.3", "postcss": "^8.5.8", "rolldown": "1.0.0-rc.9", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.0.0-alpha.31", "esbuild": "^0.27.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-fPGaRNj9Zytaf8LEiBhY7Z6ijnFKdzU/+mL8EFBaKr7Vw1/FWcTBAMW0wLPJAGMPX38ZPVCVgLceWiEqeoqL2Q=="], + + "vite-node": ["vite-node@3.2.4", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg=="], + + "vite-plugin-html": ["vite-plugin-html@3.2.2", "", { "dependencies": { "@rollup/pluginutils": "^4.2.0", "colorette": "^2.0.16", "connect-history-api-fallback": "^1.6.0", "consola": "^2.15.3", "dotenv": "^16.0.0", "dotenv-expand": "^8.0.2", "ejs": "^3.1.6", "fast-glob": "^3.2.11", "fs-extra": "^10.0.1", "html-minifier-terser": "^6.1.0", "node-html-parser": "^5.3.3", "pathe": "^0.2.0" }, "peerDependencies": { "vite": ">=2.0.0" } }, "sha512-vb9C9kcdzcIo/Oc3CLZVS03dL5pDlOFuhGlZYDCJ840BhWl/0nGeZWf3Qy7NlOayscY4Cm/QRgULCQkEZige5Q=="], + + "vitest": ["vitest@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", "@vitest/mocker": "3.2.4", "@vitest/pretty-format": "^3.2.4", "@vitest/runner": "3.2.4", "@vitest/snapshot": "3.2.4", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "debug": "^4.4.1", "expect-type": "^1.2.1", "magic-string": "^0.30.17", "pathe": "^2.0.3", "picomatch": "^4.0.2", "std-env": "^3.9.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.14", "tinypool": "^1.1.1", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", "vite-node": "3.2.4", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "@vitest/browser": "3.2.4", "@vitest/ui": "3.2.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@types/debug", "@types/node", "@vitest/browser", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A=="], + + "vlq": ["vlq@0.2.3", "", {}, "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow=="], + + "warning": ["warning@4.0.3", "", { "dependencies": { "loose-envify": "^1.0.0" } }, "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w=="], + + "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], + + "whatwg-encoding": ["whatwg-encoding@3.1.1", "", { "dependencies": { "iconv-lite": "0.6.3" } }, "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ=="], + + "whatwg-fetch": ["whatwg-fetch@3.6.20", "", {}, "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg=="], + + "whatwg-mimetype": ["whatwg-mimetype@4.0.0", "", {}, "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg=="], + + "whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], + + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "which-boxed-primitive": ["which-boxed-primitive@1.1.1", "", { "dependencies": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", "is-number-object": "^1.1.1", "is-string": "^1.1.1", "is-symbol": "^1.1.1" } }, "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA=="], + + "which-builtin-type": ["which-builtin-type@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "function.prototype.name": "^1.1.6", "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", "is-date-object": "^1.1.0", "is-finalizationregistry": "^1.1.0", "is-generator-function": "^1.0.10", "is-regex": "^1.2.1", "is-weakref": "^1.0.2", "isarray": "^2.0.5", "which-boxed-primitive": "^1.1.0", "which-collection": "^1.0.2", "which-typed-array": "^1.1.16" } }, "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q=="], + + "which-collection": ["which-collection@1.0.2", "", { "dependencies": { "is-map": "^2.0.3", "is-set": "^2.0.3", "is-weakmap": "^2.0.2", "is-weakset": "^2.0.3" } }, "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw=="], + + "which-module": ["which-module@2.0.1", "", {}, "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="], + + "which-typed-array": ["which-typed-array@1.1.20", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg=="], + + "why-is-node-running": ["why-is-node-running@2.3.0", "", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" } }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="], + + "widest-line": ["widest-line@3.1.0", "", { "dependencies": { "string-width": "^4.0.0" } }, "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg=="], + + "winston": ["winston@3.5.1", "", { "dependencies": { "@dabh/diagnostics": "^2.0.2", "async": "^3.2.3", "is-stream": "^2.0.0", "logform": "^2.3.2", "one-time": "^1.0.0", "readable-stream": "^3.4.0", "safe-stable-stringify": "^2.3.1", "stack-trace": "0.0.x", "triple-beam": "^1.3.0", "winston-transport": "^4.4.2" } }, "sha512-tbRtVy+vsSSCLcZq/8nXZaOie/S2tPXPFt4be/Q3vI/WtYwm7rrwidxVw2GRa38FIXcJ1kUM6MOZ9Jmnk3F3UA=="], + + "winston-loki": ["winston-loki@6.1.4", "", { "dependencies": { "async-exit-hook": "2.0.1", "btoa": "^1.2.1", "protobufjs": "^7.2.4", "url-polyfill": "^1.1.12", "winston-transport": "^4.3.0" }, "optionalDependencies": { "snappy": "^7.2.2" } }, "sha512-/j/Zf7TGLjgSBck29BkPnpJlEnGQr5xqlx8A0N6LZnXYYYvyK7lFk6FPpWiD+VMO8xjaxOu1KNF9SzWaRDsigA=="], + + "winston-transport": ["winston-transport@4.5.0", "", { "dependencies": { "logform": "^2.3.2", "readable-stream": "^3.6.0", "triple-beam": "^1.3.0" } }, "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q=="], + + "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], + + "wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="], + + "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + + "write-file-atomic": ["write-file-atomic@3.0.3", "", { "dependencies": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", "signal-exit": "^3.0.2", "typedarray-to-buffer": "^3.1.5" } }, "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q=="], + + "ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="], + + "xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="], + + "y18n": ["y18n@4.0.3", "", {}, "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="], + + "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + + "yaml": ["yaml@1.10.2", "", {}, "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="], + + "yargs": ["yargs@15.4.1", "", { "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", "find-up": "^4.1.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", "yargs-parser": "^18.1.2" } }, "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A=="], + + "yargs-parser": ["yargs-parser@18.1.3", "", { "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } }, "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ=="], + + "yn": ["yn@3.1.1", "", {}, "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q=="], + + "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], + + "yoga-layout-prebuilt": ["yoga-layout-prebuilt@1.10.0", "", { "dependencies": { "@types/yoga-layout": "1.9.2" } }, "sha512-YnOmtSbv4MTf7RGJMK0FvZ+KD8OEe/J5BNnR0GHhD8J/XcG/Qvxgszm0Un6FTHWW4uHlTgP0IztiXQnGyIR45g=="], + + "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], + + "@ampproject/remapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + + "@aws-crypto/crc32/@aws-sdk/types": ["@aws-sdk/types@3.973.5", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ=="], + + "@aws-crypto/crc32/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + + "@aws-crypto/ie11-detection/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + + "@aws-crypto/sha256-browser/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + + "@aws-crypto/sha256-js/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + + "@aws-crypto/supports-web-crypto/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + + "@aws-crypto/util/@aws-sdk/types": ["@aws-sdk/types@3.973.5", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ=="], + + "@aws-crypto/util/@aws-sdk/util-utf8-browser": ["@aws-sdk/util-utf8-browser@3.259.0", "", { "dependencies": { "tslib": "^2.3.1" } }, "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw=="], + + "@aws-crypto/util/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + + "@aws-sdk/client-s3/fast-xml-parser": ["fast-xml-parser@3.19.0", "", { "bin": { "xml2js": "cli.js" } }, "sha512-4pXwmBplsCPv8FOY1WRakF970TjNGnGnfbOnLqjlYvMiF1SR3yOHyxMR/YCXpPTOspNF5gwudqktIP4VsWkvBg=="], + + "@aws-sdk/client-sts/fast-xml-parser": ["fast-xml-parser@3.19.0", "", { "bin": { "xml2js": "cli.js" } }, "sha512-4pXwmBplsCPv8FOY1WRakF970TjNGnGnfbOnLqjlYvMiF1SR3yOHyxMR/YCXpPTOspNF5gwudqktIP4VsWkvBg=="], + + "@babel/code-frame/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + + "@babel/core/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + + "@babel/core/json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], + + "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@babel/generator/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + + "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + + "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@discordjs/rest/discord-api-types": ["discord-api-types@0.18.1", "", {}, "sha512-hNC38R9ZF4uaujaZQtQfm5CdQO58uhdkoHQAVvMfIL0LgOSZeW575W8H6upngQOuoxWd8tiRII3LLJm9zuQKYg=="], + + "@discordjs/rest/form-data": ["form-data@4.0.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="], + + "@emotion/babel-plugin/source-map": ["source-map@0.5.7", "", {}, "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="], + + "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], + + "@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], + + "@eslint/eslintrc/js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], + + "@eslint/eslintrc/strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], + + "@grpc/proto-loader/yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], + + "@httptoolkit/websocket-stream/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], + + "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + + "@isaacs/cliui/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], + + "@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], + + "@isaacs/fs-minipass/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "@istanbuljs/load-nyc-config/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], + + "@istanbuljs/load-nyc-config/resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], + + "@jridgewell/gen-mapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + + "@jridgewell/remapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + + "@jridgewell/source-map/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + + "@kristiandupont/recase/ramda": ["ramda@0.30.1", "", {}, "sha512-tEF5I22zJnuclswcZMc8bDIrwRHRzf+NqVEmqg50ShAZMP7MWeR/RGDthfM/p+BlqvF2fXAzpn8i+SJcYD3alw=="], + + "@mapbox/node-pre-gyp/consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], + + "@napi-rs/snappy-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" } }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="], + + "@nivo/annotations/lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="], + + "@nivo/bar/lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="], + + "@nivo/colors/lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="], + + "@nivo/core/lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="], + + "@nivo/scales/d3-time": ["d3-time@1.1.0", "", {}, "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA=="], + + "@nivo/scales/lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="], + + "@octokit/auth-app/@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="], + + "@octokit/auth-oauth-app/@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="], + + "@octokit/auth-oauth-device/@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="], + + "@octokit/auth-oauth-user/@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="], + + "@octokit/auth-unauthenticated/@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="], + + "@octokit/core/@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="], + + "@octokit/endpoint/@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="], + + "@octokit/graphql/@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="], + + "@octokit/oauth-methods/@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="], + + "@octokit/request/@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="], + + "@octokit/request-error/@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="], + + "@restart/ui/@restart/hooks": ["@restart/hooks@0.5.1", "", { "dependencies": { "dequal": "^2.0.3" }, "peerDependencies": { "react": ">=16.8.0" } }, "sha512-EMoH04NHS1pbn07iLTjIjgttuqb7qu4+/EyhAx27MHpoENcB2ZdSsLTNxmKD+WEPnZigo62Qc8zjGnNxoSE/5Q=="], + + "@restart/ui/uncontrollable": ["uncontrollable@8.0.4", "", { "peerDependencies": { "react": ">=16.14.0" } }, "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ=="], + + "@rolldown/binding-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" } }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="], + + "@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], + + "@rollup/pluginutils/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "@types/minimatch/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="], + + "@types/rate-limit-redis/@types/express-rate-limit": ["@types/express-rate-limit@3.3.5", "", { "dependencies": { "@types/express": "*" } }, "sha512-v6M28DcbdATYvzTN5lFJhN2EP6BgY8MbTskcKJ/m5bmGuzFKHfbEVXF3po8U8ivOyyeT5o6HV0janPlFBBN5yg=="], + + "@types/superagent/form-data": ["form-data@4.0.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="], + + "@typescript-eslint/experimental-utils/eslint-scope": ["eslint-scope@5.1.1", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw=="], + + "@typescript-eslint/project-service/@typescript-eslint/types": ["@typescript-eslint/types@8.56.1", "", {}, "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw=="], + + "@typescript-eslint/type-utils/@typescript-eslint/types": ["@typescript-eslint/types@8.56.1", "", {}, "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw=="], + + "@typescript-eslint/type-utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.56.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.56.1", "@typescript-eslint/tsconfig-utils": "8.56.1", "@typescript-eslint/types": "8.56.1", "@typescript-eslint/visitor-keys": "8.56.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg=="], + + "@typescript-eslint/utils/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.56.1", "", { "dependencies": { "@typescript-eslint/types": "8.56.1", "@typescript-eslint/visitor-keys": "8.56.1" } }, "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w=="], + + "@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.56.1", "", {}, "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw=="], + + "@typescript-eslint/utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.56.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.56.1", "@typescript-eslint/tsconfig-utils": "8.56.1", "@typescript-eslint/types": "8.56.1", "@typescript-eslint/visitor-keys": "8.56.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg=="], + + "@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@2.1.0", "", {}, "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw=="], + + "@vitest/mocker/vite": ["vite@3.2.11", "", { "dependencies": { "esbuild": "^0.15.9", "postcss": "^8.4.18", "resolve": "^1.22.1", "rollup": "^2.79.1" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@types/node": ">= 14", "less": "*", "sass": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "sass", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-K/jGKL/PgbIgKCiJo5QbASQhFiV02X9Jh+Qq0AKCRCRKZtOTVi4t6wh75FDpGf2N9rYOnzH87OEFQNaFy6pdxQ=="], + + "ansi-escapes/type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="], + + "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "ast-v8-to-istanbul/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + + "aws-crt/@aws-sdk/util-utf8-browser": ["@aws-sdk/util-utf8-browser@3.259.0", "", { "dependencies": { "tslib": "^2.3.1" } }, "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw=="], + + "aws-crt/buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], + + "axios/form-data": ["form-data@4.0.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="], + + "babel-plugin-macros/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], + + "bl/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], + + "bms-table-loader/node-fetch": ["node-fetch@2.6.2", "", {}, "sha512-aLoxToI6RfZ+0NOjmWAgn9+LEd30YCkJKFSyWacNZdEKTit/ZMcKjGkTRo8uWEsnIb/hfKecNPEbln02PdWbcA=="], + + "bms-table-loader/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "body-parser/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "body-parser/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], + + "body-parser/qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="], + + "bullmq/lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="], + + "bullmq/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "bullmq/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + + "cheerio-select/css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="], + + "chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "color/color-convert": ["color-convert@3.1.3", "", { "dependencies": { "color-name": "^2.0.0" } }, "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg=="], + + "color-string/color-name": ["color-name@2.1.0", "", {}, "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg=="], + + "css-select/domhandler": ["domhandler@4.3.1", "", { "dependencies": { "domelementtype": "^2.2.0" } }, "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ=="], + + "css-select/domutils": ["domutils@2.8.0", "", { "dependencies": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", "domhandler": "^4.2.0" } }, "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A=="], + + "default-require-extensions/strip-bom": ["strip-bom@4.0.0", "", {}, "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w=="], + + "defaults/clone": ["clone@1.0.4", "", {}, "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg=="], + + "discord.js/@discordjs/builders": ["@discordjs/builders@0.11.0", "", { "dependencies": { "@sindresorhus/is": "^4.2.0", "discord-api-types": "^0.26.0", "ts-mixer": "^6.0.0", "tslib": "^2.3.1", "zod": "^3.11.6" } }, "sha512-ZTB8yJdJKrKlq44dpWkNUrAtEJEq0gqpb7ASdv4vmq6/mZal5kOv312hQ56I/vxwMre+VIkoHquNUAfnTbiYtg=="], + + "discord.js/@discordjs/collection": ["@discordjs/collection@0.4.0", "", {}, "sha512-zmjq+l/rV35kE6zRrwe8BHqV78JvIh2ybJeZavBi5NySjWXqN3hmmAKg7kYMMXSeiWtSsMoZ/+MQi0DiQWy2lw=="], + + "discord.js/discord-api-types": ["discord-api-types@0.26.1", "", {}, "sha512-T5PdMQ+Y1MEECYMV5wmyi9VEYPagEDEi4S0amgsszpWY0VB9JJ/hEvM6BgLhbdnKky4gfmZEXtEEtojN8ZKJQQ=="], + + "discord.js/form-data": ["form-data@4.0.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="], + + "dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + + "duplexify/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], + + "eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], + + "eslint-import-resolver-node/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], + + "eslint-module-utils/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], + + "eslint-plugin-import/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], + + "eslint-plugin-import/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "eslint-plugin-import/tsconfig-paths": ["tsconfig-paths@3.15.0", "", { "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg=="], + + "eslint-plugin-perfectionist/@typescript-eslint/types": ["@typescript-eslint/types@8.56.1", "", {}, "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw=="], + + "eslint-plugin-perfectionist/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="], + + "eslint-plugin-react/prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], + + "eslint-plugin-react/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@2.1.0", "", {}, "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw=="], + + "express/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "express-session/cookie": ["cookie@0.4.1", "", {}, "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA=="], + + "express-session/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "extract-pg-schema/pg": ["pg@8.17.2", "", { "dependencies": { "pg-connection-string": "^2.10.1", "pg-pool": "^3.11.0", "pg-protocol": "^1.11.0", "pg-types": "2.2.0", "pgpass": "1.0.5" }, "optionalDependencies": { "pg-cloudflare": "^1.3.0" }, "peerDependencies": { "pg-native": ">=3.0.1" }, "optionalPeers": ["pg-native"] }, "sha512-vjbKdiBJRqzcYw1fNU5KuHyYvdJ1qpcQg1CeBrHFqV1pWgHeVR6j/+kX0E1AAXfyuLUGY1ICrN2ELKA/z2HWzw=="], + + "extract-pg-schema/ramda": ["ramda@0.31.3", "", {}, "sha512-xKADKRNnqmDdX59PPKLm3gGmk1ZgNnj3k7DryqWwkamp4TJ6B36DdpyKEQ0EoEYmH2R62bV4Q+S0ym2z8N2f3Q=="], + + "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "filelist/minimatch": ["minimatch@5.1.9", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw=="], + + "finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "finalhandler/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="], + + "formidable/qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="], + + "formik/deepmerge": ["deepmerge@2.2.1", "", {}, "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA=="], + + "formik/lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="], + + "formik/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + + "hasha/type-fest": ["type-fest@0.8.1", "", {}, "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA=="], + + "hoist-non-react-statics/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + + "htmlparser2/entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="], + + "import-fresh/resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], + + "ink/chalk": ["chalk@3.0.0", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg=="], + + "ink/prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], + + "ink/scheduler": ["scheduler@0.18.0", "", { "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" } }, "sha512-agTSHR1Nbfi6ulI0kYNK0203joW2Y5W4po4l+v03tOoiJKpTBbxpNhWDvqc/4IcOw+KLmSiQLTasZ4cab2/UWQ=="], + + "ioredis/p-map": ["p-map@2.1.0", "", {}, "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw=="], + + "isomorphic-fetch/node-fetch": ["node-fetch@1.7.3", "", { "dependencies": { "encoding": "^0.1.11", "is-stream": "^1.0.1" } }, "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ=="], + + "istanbul-lib-instrument/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "istanbul-lib-report/make-dir": ["make-dir@4.0.0", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw=="], + + "istanbul-lib-source-maps/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + + "kanel/rimraf": ["rimraf@6.1.3", "", { "dependencies": { "glob": "^13.0.3", "package-json-from-dist": "^1.0.1" }, "bin": { "rimraf": "dist/esm/bin.mjs" } }, "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA=="], + + "knex/colorette": ["colorette@2.0.19", "", {}, "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ=="], + + "knex/commander": ["commander@10.0.1", "", {}, "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug=="], + + "knex/debug": ["debug@4.3.4", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ=="], + + "knex/lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="], + + "knex/pg-connection-string": ["pg-connection-string@2.6.2", "", {}, "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA=="], + + "knex/resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], + + "libtap/tap-parser": ["tap-parser@11.0.2", "", { "dependencies": { "events-to-array": "^1.0.1", "minipass": "^3.1.6", "tap-yaml": "^1.0.0" }, "bin": { "tap-parser": "bin/cmd.js" } }, "sha512-6qGlC956rcORw+fg7Fv1iCRAY8/bU9UabUAhs3mXRH6eRmVZcNPLheSXCYaVaYeSwx5xa/1HXZb1537YSvwDZg=="], + + "log-update/ansi-escapes": ["ansi-escapes@3.2.0", "", {}, "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ=="], + + "log-update/cli-cursor": ["cli-cursor@2.1.0", "", { "dependencies": { "restore-cursor": "^2.0.0" } }, "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw=="], + + "log-update/wrap-ansi": ["wrap-ansi@5.1.0", "", { "dependencies": { "ansi-styles": "^3.2.0", "string-width": "^3.0.0", "strip-ansi": "^5.0.0" } }, "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q=="], + + "loose-envify/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + + "make-dir/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "minizlib/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "mqtt/duplexify": ["duplexify@4.1.3", "", { "dependencies": { "end-of-stream": "^1.4.1", "inherits": "^2.0.3", "readable-stream": "^3.1.1", "stream-shift": "^1.0.2" } }, "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA=="], + + "mqtt/help-me": ["help-me@3.0.0", "", { "dependencies": { "glob": "^7.1.6", "readable-stream": "^3.6.0" } }, "sha512-hx73jClhyk910sidBB7ERlnhMlFsJJIBqSVMFDwPN8o2v9nmp5KgLq1Xz1Bf1fCMMZ6mPrX159iG0VLy/fPMtQ=="], + + "mqtt/split2": ["split2@3.2.2", "", { "dependencies": { "readable-stream": "^3.0.0" } }, "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg=="], + + "mqtt/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], + + "mqtt-packet/bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], + + "multer/mkdirp": ["mkdirp@0.5.6", "", { "dependencies": { "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="], + + "mv/mkdirp": ["mkdirp@0.5.6", "", { "dependencies": { "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="], + + "mv/rimraf": ["rimraf@2.4.5", "", { "dependencies": { "glob": "^6.0.1" }, "bin": { "rimraf": "./bin.js" } }, "sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ=="], + + "node-exports-info/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "node-mocks-http/depd": ["depd@1.1.2", "", {}, "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ=="], + + "nodemon/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], + + "nodemon/semver": ["semver@5.7.2", "", { "bin": { "semver": "bin/semver" } }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="], + + "nodemon/supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="], + + "nyc/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], + + "nyc/istanbul-lib-source-maps": ["istanbul-lib-source-maps@4.0.1", "", { "dependencies": { "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0", "source-map": "^0.6.1" } }, "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw=="], + + "nyc/resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], + + "nyc/test-exclude": ["test-exclude@6.0.0", "", { "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" } }, "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w=="], + + "parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], + + "path-scurry/lru-cache": ["lru-cache@11.2.6", "", {}, "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ=="], + + "path-scurry/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "pkg-dir/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], + + "postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + + "prop-types-extra/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + + "raw-body/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], + + "rc/strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], + + "react-async-script/prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], + + "react-bootstrap/prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], + + "react-google-recaptcha/prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], + + "react-markdown/prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], + + "react-reconciler/prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], + + "react-reconciler/scheduler": ["scheduler@0.18.0", "", { "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" } }, "sha512-agTSHR1Nbfi6ulI0kYNK0203joW2Y5W4po4l+v03tOoiJKpTBbxpNhWDvqc/4IcOw+KLmSiQLTasZ4cab2/UWQ=="], + + "react-router/path-to-regexp": ["path-to-regexp@1.9.0", "", { "dependencies": { "isarray": "0.0.1" } }, "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g=="], + + "react-router/prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], + + "react-router/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + + "react-router-bootstrap/prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], + + "react-router-dom/prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], + + "react-select/prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], + + "react-transition-group/prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], + + "readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "rechoir/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], + + "request/form-data": ["form-data@2.3.3", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", "mime-types": "^2.1.12" } }, "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ=="], + + "request/qs": ["qs@6.5.5", "", {}, "sha512-mzR4sElr1bfCaPJe7m8ilJ6ZXdDaGoObcYR0ZHSsktM/Lt21MVHj5De30GQH2eiZ1qGRTO7LCAzQsUeXTNexWQ=="], + + "request/uuid": ["uuid@3.4.0", "", { "bin": { "uuid": "./bin/uuid" } }, "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="], + + "require_optional/resolve-from": ["resolve-from@2.0.0", "", {}, "sha512-qpFcKaXsq8+oRoLilkwyc7zHGF5i9Q2/25NIgLQQ/+VVv9rU4qvr6nXVAw1DsnXJyQkZsR4Ytfbtg5ehfcUssQ=="], + + "require_optional/semver": ["semver@5.7.2", "", { "bin": { "semver": "bin/semver" } }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="], + + "rolldown/@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.9", "", {}, "sha512-w6oiRWgEBl04QkFZgmW+jnU1EC9b57Oihi2ot3HNWIQRqgHp5PnYDia5iZ5FF7rpa4EQdiqMDXjlqKGXBhsoXw=="], + + "safe-array-concat/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + + "safe-push-apply/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + + "send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "send/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="], + + "serve-static/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="], + + "serve-static/send": ["send@0.18.0", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "~1.2.1", "statuses": "2.0.1" } }, "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg=="], + + "simple-update-notifier/semver": ["semver@7.0.0", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A=="], + + "stack-utils/escape-string-regexp": ["escape-string-regexp@2.0.0", "", {}, "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="], + + "string-length/astral-regex": ["astral-regex@1.0.0", "", {}, "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg=="], + + "string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "strip-literal/js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="], + + "superagent/form-data": ["form-data@4.0.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="], + + "superagent/mime": ["mime@2.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg=="], + + "superagent/qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="], + + "tachi-common/@types/tap": ["@types/tap@15.0.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-MaP+EgZNFAGRvVjHWv8ldrLvYBn4PnmAlzY7IL3/RPAPkOXdggTSTgLFONbnTpdQTe8+ixYGAySKAm9ESlZm1A=="], + + "tachi-server/@types/tap": ["@types/tap@15.0.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-MaP+EgZNFAGRvVjHWv8ldrLvYBn4PnmAlzY7IL3/RPAPkOXdggTSTgLFONbnTpdQTe8+ixYGAySKAm9ESlZm1A=="], + + "tap-mocha-reporter/escape-string-regexp": ["escape-string-regexp@2.0.0", "", {}, "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="], + + "tap-mocha-reporter/tap-parser": ["tap-parser@11.0.2", "", { "dependencies": { "events-to-array": "^1.0.1", "minipass": "^3.1.6", "tap-yaml": "^1.0.0" }, "bin": { "tap-parser": "bin/cmd.js" } }, "sha512-6qGlC956rcORw+fg7Fv1iCRAY8/bU9UabUAhs3mXRH6eRmVZcNPLheSXCYaVaYeSwx5xa/1HXZb1537YSvwDZg=="], + + "tar/chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], + + "tar/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "tar/yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], + + "tar-stream/bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], + + "terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], + + "test-exclude/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], + + "test-exclude/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="], + + "treport/chalk": ["chalk@3.0.0", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg=="], + + "tsc-alias/commander": ["commander@9.0.0", "", {}, "sha512-JJfP2saEKbQqvW+FI93OYUB4ByV5cizMpFMiiJI8xDbBvQvSkIk0VvQdn1CZ8mqAO8Loq2h0gYTYtDFUZUeERw=="], + + "tsconfig-paths/@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="], + + "tsconfig-paths/json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": { "json5": "lib/cli.js" } }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="], + + "tsutils/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + + "typescript-eslint/@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.56.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.56.1", "@typescript-eslint/type-utils": "8.56.1", "@typescript-eslint/utils": "8.56.1", "@typescript-eslint/visitor-keys": "8.56.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.56.1", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A=="], + + "typescript-eslint/@typescript-eslint/parser": ["@typescript-eslint/parser@8.56.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.56.1", "@typescript-eslint/types": "8.56.1", "@typescript-eslint/typescript-estree": "8.56.1", "@typescript-eslint/visitor-keys": "8.56.1", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg=="], + + "typescript-eslint/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.56.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.56.1", "@typescript-eslint/tsconfig-utils": "8.56.1", "@typescript-eslint/types": "8.56.1", "@typescript-eslint/visitor-keys": "8.56.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg=="], + + "uvu/diff": ["diff@5.2.2", "", {}, "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A=="], + + "verror/core-util-is": ["core-util-is@1.0.2", "", {}, "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="], + + "vite-node/vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="], + + "vite-plugin-html/fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="], + + "vite-plugin-html/pathe": ["pathe@0.2.0", "", {}, "sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw=="], + + "vitest/vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="], + + "which-builtin-type/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + + "wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "yargs/cliui": ["cliui@6.0.0", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^6.2.0" } }, "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ=="], + + "yargs/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], + + "@aws-crypto/crc32/@aws-sdk/types/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "@aws-crypto/util/@aws-sdk/types/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "@aws-crypto/util/@aws-sdk/util-utf8-browser/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + + "@eslint/eslintrc/js-yaml/argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + + "@grpc/proto-loader/yargs/cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + + "@grpc/proto-loader/yargs/y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + + "@grpc/proto-loader/yargs/yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], + + "@httptoolkit/websocket-stream/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], + + "@httptoolkit/websocket-stream/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], + + "@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + + "@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "@istanbuljs/load-nyc-config/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], + + "@octokit/auth-app/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@25.1.0", "", {}, "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA=="], + + "@octokit/auth-oauth-app/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@25.1.0", "", {}, "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA=="], + + "@octokit/auth-oauth-device/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@25.1.0", "", {}, "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA=="], + + "@octokit/auth-oauth-user/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@25.1.0", "", {}, "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA=="], + + "@octokit/auth-unauthenticated/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@25.1.0", "", {}, "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA=="], + + "@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@25.1.0", "", {}, "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA=="], + + "@octokit/endpoint/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@25.1.0", "", {}, "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA=="], + + "@octokit/graphql/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@25.1.0", "", {}, "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA=="], + + "@octokit/oauth-methods/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@25.1.0", "", {}, "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA=="], + + "@octokit/request-error/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@25.1.0", "", {}, "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA=="], + + "@octokit/request/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@25.1.0", "", {}, "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA=="], + + "@types/minimatch/minimatch/brace-expansion": ["brace-expansion@5.0.4", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg=="], + + "@typescript-eslint/experimental-utils/eslint-scope/estraverse": ["estraverse@4.3.0", "", {}, "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="], + + "@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.56.1", "", { "dependencies": { "@typescript-eslint/types": "8.56.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw=="], + + "@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="], + + "@typescript-eslint/utils/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.56.1", "", { "dependencies": { "@typescript-eslint/types": "8.56.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw=="], + + "@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.56.1", "", { "dependencies": { "@typescript-eslint/types": "8.56.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw=="], + + "@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="], + + "@vitest/mocker/vite/esbuild": ["esbuild@0.15.18", "", { "optionalDependencies": { "@esbuild/android-arm": "0.15.18", "@esbuild/linux-loong64": "0.15.18", "esbuild-android-64": "0.15.18", "esbuild-android-arm64": "0.15.18", "esbuild-darwin-64": "0.15.18", "esbuild-darwin-arm64": "0.15.18", "esbuild-freebsd-64": "0.15.18", "esbuild-freebsd-arm64": "0.15.18", "esbuild-linux-32": "0.15.18", "esbuild-linux-64": "0.15.18", "esbuild-linux-arm": "0.15.18", "esbuild-linux-arm64": "0.15.18", "esbuild-linux-mips64le": "0.15.18", "esbuild-linux-ppc64le": "0.15.18", "esbuild-linux-riscv64": "0.15.18", "esbuild-linux-s390x": "0.15.18", "esbuild-netbsd-64": "0.15.18", "esbuild-openbsd-64": "0.15.18", "esbuild-sunos-64": "0.15.18", "esbuild-windows-32": "0.15.18", "esbuild-windows-64": "0.15.18", "esbuild-windows-arm64": "0.15.18" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q=="], + + "@vitest/mocker/vite/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], + + "@vitest/mocker/vite/rollup": ["rollup@2.80.0", "", { "optionalDependencies": { "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-cIFJOD1DESzpjOBl763Kp1AH7UE/0fcdHe6rZXUdQ9c50uvgigvW97u3IcSeBwOkgqL/PXPBktBCh0KEu5L8XQ=="], + + "bl/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], + + "bl/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], + + "body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "color/color-convert/color-name": ["color-name@2.1.0", "", {}, "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg=="], + + "css-select/domutils/dom-serializer": ["dom-serializer@1.4.1", "", { "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", "entities": "^2.0.0" } }, "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag=="], + + "discord.js/@discordjs/builders/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "duplexify/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], + + "duplexify/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], + + "eslint-plugin-import/tsconfig-paths/@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="], + + "eslint-plugin-import/tsconfig-paths/json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": { "json5": "lib/cli.js" } }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="], + + "eslint-plugin-perfectionist/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + + "eslint-plugin-react/prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + + "express-session/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "express/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "filelist/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + + "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "ink/prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + + "isomorphic-fetch/node-fetch/is-stream": ["is-stream@1.1.0", "", {}, "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ=="], + + "kanel/rimraf/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], + + "knex/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="], + + "log-update/cli-cursor/restore-cursor": ["restore-cursor@2.0.0", "", { "dependencies": { "onetime": "^2.0.0", "signal-exit": "^3.0.2" } }, "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q=="], + + "log-update/wrap-ansi/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="], + + "log-update/wrap-ansi/string-width": ["string-width@3.1.0", "", { "dependencies": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^5.1.0" } }, "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w=="], + + "mv/rimraf/glob": ["glob@6.0.4", "", { "dependencies": { "inflight": "^1.0.4", "inherits": "2", "minimatch": "2 || 3", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A=="], + + "nodemon/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="], + + "nyc/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], + + "pkg-dir/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], + + "react-async-script/prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + + "react-bootstrap/prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + + "react-google-recaptcha/prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + + "react-markdown/prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + + "react-reconciler/prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + + "react-router-bootstrap/prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + + "react-router-dom/prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + + "react-router/path-to-regexp/isarray": ["isarray@0.0.1", "", {}, "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ=="], + + "react-select/prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + + "react-transition-group/prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + + "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "serve-static/send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "test-exclude/glob/foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], + + "test-exclude/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], + + "test-exclude/glob/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="], + + "test-exclude/glob/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "test-exclude/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + + "test-exclude/minimatch/brace-expansion": ["brace-expansion@5.0.4", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg=="], + + "typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.56.1", "", { "dependencies": { "@typescript-eslint/types": "8.56.1", "@typescript-eslint/visitor-keys": "8.56.1" } }, "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w=="], + + "typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.56.1", "", { "dependencies": { "@typescript-eslint/types": "8.56.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw=="], + + "typescript-eslint/@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], + + "typescript-eslint/@typescript-eslint/parser/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.56.1", "", { "dependencies": { "@typescript-eslint/types": "8.56.1", "@typescript-eslint/visitor-keys": "8.56.1" } }, "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w=="], + + "typescript-eslint/@typescript-eslint/parser/@typescript-eslint/types": ["@typescript-eslint/types@8.56.1", "", {}, "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw=="], + + "typescript-eslint/@typescript-eslint/parser/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.56.1", "", { "dependencies": { "@typescript-eslint/types": "8.56.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw=="], + + "typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/types": ["@typescript-eslint/types@8.56.1", "", {}, "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw=="], + + "typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.56.1", "", { "dependencies": { "@typescript-eslint/types": "8.56.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw=="], + + "typescript-eslint/@typescript-eslint/typescript-estree/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="], + + "vite-plugin-html/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], + + "vite-plugin-html/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], + + "wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "yargs/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], + + "@grpc/proto-loader/yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "@grpc/proto-loader/yargs/cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "@istanbuljs/load-nyc-config/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], + + "@types/minimatch/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], + + "@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@5.0.4", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg=="], + + "@typescript-eslint/utils/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], + + "@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], + + "@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@5.0.4", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg=="], + + "@vitest/mocker/vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.15.18", "", { "os": "android", "cpu": "arm" }, "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw=="], + + "@vitest/mocker/vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.15.18", "", { "os": "linux", "cpu": "none" }, "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ=="], + + "kanel/rimraf/glob/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="], + + "kanel/rimraf/glob/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "log-update/cli-cursor/restore-cursor/onetime": ["onetime@2.0.1", "", { "dependencies": { "mimic-fn": "^1.0.0" } }, "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ=="], + + "log-update/wrap-ansi/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], + + "log-update/wrap-ansi/string-width/emoji-regex": ["emoji-regex@7.0.3", "", {}, "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA=="], + + "log-update/wrap-ansi/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@2.0.0", "", {}, "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w=="], + + "nyc/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], + + "pkg-dir/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], + + "serve-static/send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "test-exclude/glob/foreground-child/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + + "test-exclude/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + + "test-exclude/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + + "test-exclude/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager/@typescript-eslint/types": ["@typescript-eslint/types@8.56.1", "", {}, "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw=="], + + "typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys/@typescript-eslint/types": ["@typescript-eslint/types@8.56.1", "", {}, "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw=="], + + "typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], + + "typescript-eslint/@typescript-eslint/parser/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], + + "typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], + + "typescript-eslint/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@5.0.4", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg=="], + + "yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "yargs/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], + + "@grpc/proto-loader/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "@istanbuljs/load-nyc-config/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + + "@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "kanel/rimraf/glob/minimatch/brace-expansion": ["brace-expansion@5.0.4", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg=="], + + "log-update/cli-cursor/restore-cursor/onetime/mimic-fn": ["mimic-fn@1.2.0", "", {}, "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="], + + "log-update/wrap-ansi/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], + + "nyc/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + + "pkg-dir/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + + "typescript-eslint/@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "yargs/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + + "kanel/rimraf/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + } } diff --git a/typescript/api-parity/package.json b/typescript/api-parity/package.json new file mode 100644 index 000000000..c354ba6ba --- /dev/null +++ b/typescript/api-parity/package.json @@ -0,0 +1,20 @@ +{ + "name": "api-parity", + "version": "1.0.0", + "private": true, + "type": "module", + "license": "MIT", + "scripts": { + "test": "vitest run", + "test:watch": "vitest", + "typecheck": "tsc --noEmit" + }, + "devDependencies": { + "@types/node": "catalog:", + "@vitest/coverage-v8": "catalog:", + "vitest": "catalog:" + }, + "engines": { + "bun": ">=1.2.0" + } +} diff --git a/typescript/api-parity/src/index.ts b/typescript/api-parity/src/index.ts new file mode 100644 index 000000000..728a8d7e6 --- /dev/null +++ b/typescript/api-parity/src/index.ts @@ -0,0 +1,229 @@ +import { expect } from "vitest"; + +export interface ParityClientOptions { + /** + * Base URL of the running Tachi server, e.g. "http://localhost:8080". + * Do not include a trailing slash. + */ + baseUrl: string; + + /** + * Default headers sent with every request (e.g. Authorization). + */ + headers?: Record; +} + +type HttpMethod = "DELETE" | "GET" | "PATCH" | "POST" | "PUT"; + +interface ParityResponse { + status: number; + body: unknown; +} + +export interface ParityResult { + v1: ParityResponse; + v1mongo: ParityResponse; +} + +export interface RequestOptions { + /** JSON body to send (non-GET requests). */ + body?: unknown; + /** Per-request headers, merged with the client defaults. */ + headers?: Record; + /** Query string appended verbatim, e.g. "?page=1&limit=10". */ + query?: string; + /** + * Top-level keys to delete from both response bodies before comparing. + * Useful for non-deterministic fields like timestamps. + */ + ignoreFields?: string[]; +} + +async function fireRequest( + url: string, + method: HttpMethod, + headers: Record, + body: unknown, +): Promise { + const init: RequestInit = { + method, + headers: { + "Content-Type": "application/json", + ...headers, + }, + }; + + if (method !== "GET" && body !== undefined) { + init.body = JSON.stringify(body); + } + + const response = await fetch(url, init); + + let responseBody: unknown; + + const contentType = response.headers.get("content-type") ?? ""; + + if (contentType.includes("application/json")) { + responseBody = await response.json(); + } else { + responseBody = await response.text(); + } + + return { status: response.status, body: responseBody }; +} + +function stripFields(value: unknown, fields: string[]): unknown { + if (fields.length === 0 || typeof value !== "object" || value === null) { + return value; + } + + const copy = { ...value } as Record; + + for (const field of fields) { + delete copy[field]; + } + + return copy; +} + +export class ParityRequest { + private readonly clientOptions: ParityClientOptions; + private readonly method: HttpMethod; + private readonly path: string; + private options: RequestOptions; + + constructor( + clientOptions: ParityClientOptions, + method: HttpMethod, + path: string, + options: RequestOptions = {}, + ) { + this.clientOptions = clientOptions; + this.method = method; + this.path = path; + this.options = options; + } + + withBody(body: unknown): this { + this.options = { ...this.options, body }; + return this; + } + + withHeaders(headers: Record): this { + this.options = { ...this.options, headers: { ...this.options.headers, ...headers } }; + return this; + } + + withQuery(query: string): this { + this.options = { ...this.options, query }; + return this; + } + + /** + * Ignore these top-level keys in the response body when comparing. + * Useful for non-deterministic values like `serverTime`. + */ + ignoringFields(...fields: string[]): this { + this.options = { + ...this.options, + ignoreFields: [...(this.options.ignoreFields ?? []), ...fields], + }; + return this; + } + + /** + * Fire the request at both /api/v1 and /api/v1mongo and return the raw + * results without asserting anything. Useful when you need to inspect the + * responses before deciding what to assert. + */ + async fetch(): Promise { + const { baseUrl } = this.clientOptions; + const { body, query = "", ignoreFields: _ignore } = this.options; + + const mergedHeaders = { + ...this.clientOptions.headers, + ...this.options.headers, + }; + + const suffix = `${this.path}${query}`; + + const [v1, v1mongo] = await Promise.all([ + fireRequest(`${baseUrl}/api/v1${suffix}`, this.method, mergedHeaders, body), + fireRequest(`${baseUrl}/api/v1mongo${suffix}`, this.method, mergedHeaders, body), + ]); + + return { v1, v1mongo }; + } + + /** + * Fire the request at both /api/v1 and /api/v1mongo and assert that the + * status codes and response bodies are identical. + * + * Throws (via vitest's `expect`) if they differ. + */ + async check(): Promise { + const result = await this.fetch(); + const { ignoreFields = [] } = this.options; + + const suffix = `${this.path}${this.options.query ?? ""}`; + + expect(result.v1.status, `${this.method} ${suffix} — status code mismatch`).toEqual( + result.v1mongo.status, + ); + + expect( + stripFields(result.v1.body, ignoreFields), + `${this.method} ${suffix} — response body mismatch`, + ).toEqual(stripFields(result.v1mongo.body, ignoreFields)); + + return result; + } +} + +export class ParityClient { + private readonly options: ParityClientOptions; + + constructor(options: ParityClientOptions) { + this.options = options; + } + + private request(method: HttpMethod, path: string, options?: RequestOptions): ParityRequest { + return new ParityRequest(this.options, method, path, options); + } + + get(path: string, options?: RequestOptions): ParityRequest { + return this.request("GET", path, options); + } + + post(path: string, options?: RequestOptions): ParityRequest { + return this.request("POST", path, options); + } + + put(path: string, options?: RequestOptions): ParityRequest { + return this.request("PUT", path, options); + } + + patch(path: string, options?: RequestOptions): ParityRequest { + return this.request("PATCH", path, options); + } + + delete(path: string, options?: RequestOptions): ParityRequest { + return this.request("DELETE", path, options); + } +} + +/** + * Create a parity client pointed at a running Tachi server. + * + * @example + * const api = createParityClient({ baseUrl: "http://localhost:8080" }); + * + * // With default auth: + * const authedApi = createParityClient({ + * baseUrl: "http://localhost:8080", + * headers: { Authorization: "Bearer my-api-token" }, + * }); + */ +export function createParityClient(options: ParityClientOptions): ParityClient { + return new ParityClient(options); +} diff --git a/typescript/api-parity/tests/activity.test.ts b/typescript/api-parity/tests/activity.test.ts new file mode 100644 index 000000000..bc683f317 --- /dev/null +++ b/typescript/api-parity/tests/activity.test.ts @@ -0,0 +1,9 @@ +import { describe } from "vitest"; +import { api } from "./setup" +import { it } from "vitest"; + +describe("GET /activity", () => { + it("returns identical global activity feed", async () => { + await api.get("/activity").check(); + }); +}); diff --git a/typescript/api-parity/tests/config.test.ts b/typescript/api-parity/tests/config.test.ts new file mode 100644 index 000000000..cfb9d4f7f --- /dev/null +++ b/typescript/api-parity/tests/config.test.ts @@ -0,0 +1,9 @@ +import { describe } from "vitest"; +import { api } from "./setup" +import { it } from "vitest"; + +describe("GET /config/game-support", () => { + it("returns identical game support config", async () => { + await api.get("/config/game-support").check(); + }); +}); diff --git a/typescript/api-parity/tests/games.test.ts b/typescript/api-parity/tests/games.test.ts new file mode 100644 index 000000000..2818c6bb2 --- /dev/null +++ b/typescript/api-parity/tests/games.test.ts @@ -0,0 +1,63 @@ +import { describe } from "vitest"; +import { api } from "./setup" +import { it } from "vitest"; + +describe("GET /games", () => { + it("returns identical game list", async () => { + await api.get("/games").check(); + }); +}); + +describe("GET /games/:game", () => { + it("iidx — returns identical game info", async () => { + await api.get("/games/iidx").check(); + }); +}); + +describe("GET /games/:game/:playtype", () => { + it("iidx/SP — returns identical playtype info", async () => { + await api.get("/games/iidx/SP").check(); + }); +}); + +describe("GET /games/:game/:playtype/charts", () => { + it("iidx/SP — returns identical chart list", async () => { + await api.get("/games/iidx/SP/charts").check(); + }); +}); + +describe("GET /games/:game/:playtype/songs/:songID", () => { + it("iidx/SP song 1 — returns identical song", async () => { + await api.get("/games/iidx/SP/songs/1").check(); + }); +}); + +describe("GET /games/:game/:playtype/folders", () => { + it("iidx/SP — returns identical folder list", async () => { + await api.get("/games/iidx/SP/folders").check(); + }); +}); + +describe("GET /games/:game/:playtype/tables", () => { + it("iidx/SP — returns identical table list", async () => { + await api.get("/games/iidx/SP/tables").check(); + }); +}); + +describe("GET /games/:game/:playtype/targets/goals", () => { + it("iidx/SP — returns identical goal list", async () => { + await api.get("/games/iidx/SP/targets/goals").check(); + }); +}); + +describe("GET /games/:game/:playtype/targets/quests", () => { + it("iidx/SP — returns identical quest list", async () => { + await api.get("/games/iidx/SP/targets/quests").check(); + }); +}); + +describe("GET /games/:game/:playtype/targets/questlines", () => { + it("iidx/SP — returns identical questline list", async () => { + await api.get("/games/iidx/SP/targets/questlines").check(); + }); +}); diff --git a/typescript/api-parity/tests/imports.test.ts b/typescript/api-parity/tests/imports.test.ts new file mode 100644 index 000000000..9af805e23 --- /dev/null +++ b/typescript/api-parity/tests/imports.test.ts @@ -0,0 +1,12 @@ +import { describe } from "vitest"; +import { api } from "./setup" +import { it } from "vitest"; + +describe("GET /imports/:importID", () => { + // Replace with a real importID from your test dataset. + const IMPORT_ID = "placeholder-import-id"; + + it("returns identical import document", async () => { + await api.get(`/imports/${IMPORT_ID}`).check(); + }); +}); diff --git a/typescript/api-parity/tests/scores.test.ts b/typescript/api-parity/tests/scores.test.ts new file mode 100644 index 000000000..3e6fe43b9 --- /dev/null +++ b/typescript/api-parity/tests/scores.test.ts @@ -0,0 +1,16 @@ +import { describe } from "vitest"; +import { api } from "./setup" +import { it } from "vitest"; + +describe("GET /scores/:scoreID", () => { + // Replace with a real scoreID from your test dataset. + const SCORE_ID = "placeholder-score-id"; + + it("returns identical score document", async () => { + await api.get(`/scores/${SCORE_ID}`).check(); + }); + + it("returns identical score document with related data", async () => { + await api.get(`/scores/${SCORE_ID}/related`).check(); + }); +}); diff --git a/typescript/api-parity/tests/search.test.ts b/typescript/api-parity/tests/search.test.ts new file mode 100644 index 000000000..67dbc82db --- /dev/null +++ b/typescript/api-parity/tests/search.test.ts @@ -0,0 +1,9 @@ +import { describe } from "vitest"; +import { api } from "./setup" +import { it } from "vitest"; + +describe("GET /search", () => { + it("returns identical search results for a query", async () => { + await api.get("/search").withQuery("?search=freedom").check(); + }); +}); diff --git a/typescript/api-parity/tests/sessions.test.ts b/typescript/api-parity/tests/sessions.test.ts new file mode 100644 index 000000000..13a75714a --- /dev/null +++ b/typescript/api-parity/tests/sessions.test.ts @@ -0,0 +1,16 @@ +import { describe } from "vitest"; +import { api } from "./setup" +import { it } from "vitest"; + +describe("GET /sessions/:sessionID", () => { + // Replace with a real sessionID from your test dataset. + const SESSION_ID = "placeholder-session-id"; + + it("returns identical session document", async () => { + await api.get(`/sessions/${SESSION_ID}`).check(); + }); + + it("returns identical session scores", async () => { + await api.get(`/sessions/${SESSION_ID}/scores`).check(); + }); +}); diff --git a/typescript/api-parity/tests/setup.ts b/typescript/api-parity/tests/setup.ts new file mode 100644 index 000000000..3ec1ccaaa --- /dev/null +++ b/typescript/api-parity/tests/setup.ts @@ -0,0 +1,20 @@ +/** + * Shared test setup for parity tests. + * + * Environment variables: + * TACHI_SERVER - Base URL of the running server, e.g. http://localhost:8080 + * TACHI_AUTH_TOKEN - Optional API token sent as `Authorization: Bearer ` + */ +import { createParityClient, type ParityClient } from "../src/index"; + +const BASE_URL = process.env["TACHI_SERVER"]; +const AUTH_TOKEN = process.env["TACHI_AUTH_TOKEN"]; + +if (!BASE_URL) { + throw new Error("TACHI_SERVER environment variable is required."); +} + +export const api: ParityClient = createParityClient({ + baseUrl: BASE_URL, + headers: AUTH_TOKEN ? { Authorization: `Bearer ${AUTH_TOKEN}` } : undefined, +}); diff --git a/typescript/api-parity/tests/status.test.ts b/typescript/api-parity/tests/status.test.ts new file mode 100644 index 000000000..94c567488 --- /dev/null +++ b/typescript/api-parity/tests/status.test.ts @@ -0,0 +1,32 @@ +import { describe } from "vitest"; +import { api } from "./setup" +import { it } from "vitest"; + +describe("GET /status", () => { + it("returns identical responses", async () => { + // serverTime will always differ between the two parallel calls. + await api.get("/status").ignoringFields("serverTime").check(); + }); + + it("echoes query param identically", async () => { + await api + .get("/status") + .withQuery("?echo=parity-check") + .ignoringFields("serverTime") + .check(); + }); +}); + +describe("POST /status", () => { + it("returns identical responses", async () => { + await api.post("/status").ignoringFields("serverTime").check(); + }); + + it("echoes body param identically", async () => { + await api + .post("/status") + .withBody({ echo: "parity-check" }) + .ignoringFields("serverTime") + .check(); + }); +}); diff --git a/typescript/api-parity/tests/users.test.ts b/typescript/api-parity/tests/users.test.ts new file mode 100644 index 000000000..5e87d9faf --- /dev/null +++ b/typescript/api-parity/tests/users.test.ts @@ -0,0 +1,75 @@ +import { describe } from "vitest"; +import { api } from "./setup" +import { it } from "vitest"; + +describe("GET /users", () => { + it("returns identical user list", async () => { + await api.get("/users").check(); + }); +}); + +describe("GET /users/:userID", () => { + it("user 1 — returns identical user document", async () => { + await api.get("/users/1").check(); + }); +}); + +describe("GET /users/:userID/games/:game/:playtype", () => { + it("user 1 iidx/SP — returns identical game stats", async () => { + await api.get("/users/1/games/iidx/SP").check(); + }); +}); + +describe("GET /users/:userID/games/:game/:playtype/scores", () => { + it("user 1 iidx/SP — returns identical score list", async () => { + await api.get("/users/1/games/iidx/SP/scores").check(); + }); +}); + +describe("GET /users/:userID/games/:game/:playtype/pbs", () => { + it("user 1 iidx/SP — returns identical PB list", async () => { + await api.get("/users/1/games/iidx/SP/pbs").check(); + }); +}); + +describe("GET /users/:userID/games/:game/:playtype/sessions", () => { + it("user 1 iidx/SP — returns identical session list", async () => { + await api.get("/users/1/games/iidx/SP/sessions").check(); + }); +}); + +describe("GET /users/:userID/games/:game/:playtype/folders", () => { + it("user 1 iidx/SP — returns identical folder list", async () => { + await api.get("/users/1/games/iidx/SP/folders").check(); + }); +}); + +describe("GET /users/:userID/games/:game/:playtype/tables", () => { + it("user 1 iidx/SP — returns identical table list", async () => { + await api.get("/users/1/games/iidx/SP/tables").check(); + }); +}); + +describe("GET /users/:userID/games/:game/:playtype/targets", () => { + it("user 1 iidx/SP — returns identical targets", async () => { + await api.get("/users/1/games/iidx/SP/targets").check(); + }); +}); + +describe("GET /users/:userID/games/:game/:playtype/rivals", () => { + it("user 1 iidx/SP — returns identical rival list", async () => { + await api.get("/users/1/games/iidx/SP/rivals").check(); + }); +}); + +describe("GET /users/:userID/games/:game/:playtype/most-played", () => { + it("user 1 iidx/SP — returns identical most-played", async () => { + await api.get("/users/1/games/iidx/SP/most-played").check(); + }); +}); + +describe("GET /users/:userID/imports", () => { + it("user 1 — returns identical import list", async () => { + await api.get("/users/1/imports").check(); + }); +}); diff --git a/typescript/api-parity/tsconfig.json b/typescript/api-parity/tsconfig.json new file mode 100644 index 000000000..1e65f62b7 --- /dev/null +++ b/typescript/api-parity/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "module": "Preserve", + "moduleResolution": "bundler" + }, + "include": ["src", "tests", "vitest.config.ts"] +} diff --git a/typescript/api-parity/vitest.config.ts b/typescript/api-parity/vitest.config.ts new file mode 100644 index 000000000..5bdee0020 --- /dev/null +++ b/typescript/api-parity/vitest.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + include: ["tests/**/*.test.ts"], + }, +}); diff --git a/typescript/server/src/main.ts b/typescript/server/src/main.ts index 3b2aa0b79..96e01a12e 100644 --- a/typescript/server/src/main.ts +++ b/typescript/server/src/main.ts @@ -5,7 +5,7 @@ import { VERSION_PRETTY } from "#lib/constants/version"; import { HandleSIGTERMGracefully } from "#lib/handlers/sigterm"; import { log } from "#lib/log/log.js"; import { Env, ServerConfig, TachiConfig } from "#lib/setup/config"; -import { AddNewUser } from "#server/router/api/v1/auth/auth"; +import { AddNewUser } from "#server/router/api/v1/auth/auth.js"; import server from "#server/server"; import db, { monkDB } from "#services/mongo/db"; import { UpdateIndexes } from "#services/mongo/indexes"; diff --git a/typescript/server/src/server/router/api/v1/users/_userID/games/@gameSpecificRoutes/bms/router.ts b/typescript/server/src/server/router/api/v1/users/_userID/games/@gameSpecificRoutes/bms/router.ts index 580c831a1..334400566 100644 --- a/typescript/server/src/server/router/api/v1/users/_userID/games/@gameSpecificRoutes/bms/router.ts +++ b/typescript/server/src/server/router/api/v1/users/_userID/games/@gameSpecificRoutes/bms/router.ts @@ -4,7 +4,7 @@ import { HandleBMSTableHeaderRequest, HandleBMSTableHTMLRequest, } from "#lib/game-specific/custom-bms-tables"; -import { ValidatePlaytypeFromParamFor } from "#server/router/api/v1/games/_game/_playtype/middleware"; +import { ValidatePlaytypeFromParamFor } from "#server/router/api/v1/games/_game/_playtype/middleware.js"; import db from "#services/mongo/db"; import { AssignToReqTachiData, GetTachiData, GetUGPT, GetUser } from "#utils/req-tachi-data"; import { type RequestHandler, Router } from "express"; diff --git a/typescript/server/src/server/router/api/v1/users/_userID/games/@gameSpecificRoutes/iidx/router.ts b/typescript/server/src/server/router/api/v1/users/_userID/games/@gameSpecificRoutes/iidx/router.ts index b367cf443..7574c74af 100644 --- a/typescript/server/src/server/router/api/v1/users/_userID/games/@gameSpecificRoutes/iidx/router.ts +++ b/typescript/server/src/server/router/api/v1/users/_userID/games/@gameSpecificRoutes/iidx/router.ts @@ -14,7 +14,7 @@ import { import { ResolveSongAndChart } from "#lib/score-import/import-types/common/batch-manual/converter"; import { EAM_VERSION_NAMES } from "#lib/score-import/import-types/common/eamusement-iidx-csv/parser"; import { AggressiveRateLimitMiddleware } from "#server/middleware/rate-limiter"; -import { ValidatePlaytypeFromParamFor } from "#server/router/api/v1/games/_game/_playtype/middleware"; +import { ValidatePlaytypeFromParamFor } from "#server/router/api/v1/games/_game/_playtype/middleware.js"; import db from "#services/mongo/db"; import { GetUser } from "#utils/req-tachi-data"; import { Router } from "express"; diff --git a/typescript/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/router.ts b/typescript/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/router.ts index 9a36e136c..89f23f3f2 100644 --- a/typescript/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/router.ts +++ b/typescript/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/router.ts @@ -2,7 +2,7 @@ import { CreateActivityRouteHandler } from "#lib/activity/activity"; import { ONE_MONTH, ONE_WEEK, ONE_YEAR } from "#lib/constants/time"; import { log } from "#lib/log/log.js"; import prValidate from "#server/middleware/prudence-validate"; -import { PasswordCompare, ValidatePassword } from "#server/router/api/v1/auth/auth"; +import { PasswordCompare, ValidatePassword } from "#server/router/api/v1/auth/auth.js"; import db from "#services/mongo/db"; import { IsString } from "#utils/misc"; import { GetTachiData, GetUGPT } from "#utils/req-tachi-data"; diff --git a/typescript/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/showcase/router.ts b/typescript/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/showcase/router.ts index bffd7f22c..4caee3adb 100644 --- a/typescript/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/showcase/router.ts +++ b/typescript/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/showcase/router.ts @@ -2,7 +2,7 @@ import { EvaluateShowcaseStat } from "#lib/showcase/evaluator"; import { GetRelatedStatDocuments } from "#lib/showcase/get-related"; import { EvaluateUsersStatsShowcase } from "#lib/showcase/get-stats"; import { RequirePermissions } from "#server/middleware/auth"; -import { RequireAuthedAsUser } from "#server/router/api/v1/users/_userID/middleware"; +import { RequireAuthedAsUser } from "#server/router/api/v1/users/_userID/middleware.js"; import db from "#services/mongo/db"; import { IsRecord } from "#utils/misc"; import { FormatPrError } from "#utils/prudence"; diff --git a/typescript/server/src/server/router/api/v1postgres/activity/router.ts b/typescript/server/src/server/router/api/v1postgres/activity/router.ts new file mode 100644 index 000000000..b7270577b --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/activity/router.ts @@ -0,0 +1,47 @@ +import { GetRecentActivityForMultipleGames } from "#lib/activity/activity"; +import { TachiConfig } from "#lib/setup/config"; +import { Router } from "express"; +import { GetGameGroupConfig } from "tachi-common"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Retrieve *all* activity across every game on the site. + * + * @param session - See CreateActivityRouteHandler + * @param startTime - See CreateActivityRouteHandler + * + * @name GET /api/v1/activity + */ +router.get("/", async (req, res) => { + const qStartTime = req.query.startTime as string | undefined; + + const startTime = qStartTime ? Number(qStartTime) : null; + + if (Number.isNaN(startTime)) { + return res.status(400).json({ + success: false, + description: `Invalid startTime, got a non number.`, + }); + } + + const gpts = []; + + for (const game of TachiConfig.GAMES) { + const playtypes = GetGameGroupConfig(game).playtypes; + + for (const playtype of playtypes) { + gpts.push({ game, playtype, query: {} }); + } + } + + const data = await GetRecentActivityForMultipleGames(gpts, undefined, startTime); + + return res.status(200).json({ + success: true, + description: `Returned global activity.`, + body: data, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/admin/router.test.ts b/typescript/server/src/server/router/api/v1postgres/admin/router.test.ts new file mode 100644 index 000000000..3f67cf330 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/admin/router.test.ts @@ -0,0 +1,132 @@ +import { ONE_MINUTE } from "#lib/constants/time"; +import { ChangeRootLogLevel, GetLogLevel } from "#lib/log/log.js"; +import { Env, ServerConfig } from "#lib/setup/config"; +import db from "#services/mongo/db"; +import { CreateFakeAuthCookie } from "#test-utils/fake-auth"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { TestingIIDXSPScore } from "#test-utils/test-data"; +import { Sleep } from "#utils/misc"; +import deepmerge from "deepmerge"; +import { type ScoreDocument, UserAuthLevels } from "tachi-common"; +import t from "tap"; + +const LOG_LEVEL = Env.LOG_LEVEL; + +t.test("POST /api/v1/admin/change-log-level", async (t) => { + t.beforeEach(async () => { + ChangeRootLogLevel(LOG_LEVEL); + await db.users.update({ id: 1 }, { $set: { authLevel: UserAuthLevels.ADMIN } }); + }); + + const auth = await CreateFakeAuthCookie(mockApi); + + t.test("Should require an admin authlevel", async (t) => { + await db.users.update({ id: 1 }, { $set: { authLevel: UserAuthLevels.USER } }); + + const res = await mockApi.post("/api/v1/admin/change-log-level").set("Cookie", auth).send({ + noReset: true, + logLevel: "crit", + }); + + t.equal(res.statusCode, 403); + + t.end(); + }); + + t.test("Should change the log level on the server.", async (t) => { + const res = await mockApi.post("/api/v1/admin/change-log-level").set("Cookie", auth).send({ + noReset: true, + logLevel: "crit", + }); + + t.equal(res.statusCode, 200); + t.equal(GetLogLevel(), "crit"); + + t.end(); + }); + + t.test("Should reject invalid log levels", async (t) => { + const res = await mockApi.post("/api/v1/admin/change-log-level").set("Cookie", auth).send({ + noReset: true, + logLevel: "invalid", + }); + + t.equal(res.statusCode, 400); + t.equal(GetLogLevel(), LOG_LEVEL); + + t.end(); + }); + + t.test("Should set a timer that lasts duration minutes.", async (t) => { + const res = await mockApi.post("/api/v1/admin/change-log-level").set("Cookie", auth).send({ + duration: 0.05, + logLevel: "warn", + }); + + t.equal(res.statusCode, 200); + t.equal(GetLogLevel(), "warn"); + + // wait a bit + await Sleep(ONE_MINUTE * 0.06); + + t.equal(GetLogLevel(), LOG_LEVEL); + + t.end(); + }); + + t.end(); +}); + +t.test("POST /api/v1/admin/delete-score", async (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(async () => { + await db.users.update({ id: 1 }, { $set: { authLevel: UserAuthLevels.ADMIN } }); + }); + + const auth = await CreateFakeAuthCookie(mockApi); + + t.test("Should require an admin authlevel", async (t) => { + await db.users.update({ id: 1 }, { $set: { authLevel: UserAuthLevels.USER } }); + + const res = await mockApi + .post("/api/v1/admin/delete-score") + .set({ + Cookie: auth, + }) + .send({ + scoreID: "deleteme", + }); + + t.equal(res.statusCode, 403); + + t.end(); + }); + + t.test("Should delete another user's score.", async (t) => { + await db.scores.insert( + deepmerge(TestingIIDXSPScore, { + scoreID: "deleteme", + }), + ); + + const res = await mockApi + .post("/api/v1/admin/delete-score") + .set({ + Cookie: auth, + }) + .send({ + scoreID: "deleteme", + }); + + t.equal(res.statusCode, 200); + + const dbScore = await db.scores.findOne({ scoreID: "deleteme" }); + + t.equal(dbScore, null, "Should remove the score from the database."); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/admin/router.ts b/typescript/server/src/server/router/api/v1postgres/admin/router.ts new file mode 100644 index 000000000..70c32e522 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/admin/router.ts @@ -0,0 +1,422 @@ +import { SYMBOL_TACHI_API_AUTH } from "#lib/constants/tachi"; +import { log } from "#lib/log/log.js"; +import { SendSiteAnnouncementNotification } from "#lib/notifications/notification-wrappers"; +import { UpdateGoalsForUser } from "#lib/score-import/framework/goals/goals"; +import { UpdateQuestsForUser } from "#lib/score-import/framework/quests/quests"; +import { DeleteMultipleScores, DeleteScore } from "#lib/score-mutation/delete-scores"; +import { TachiConfig } from "#lib/setup/config"; +import prValidate from "#server/middleware/prudence-validate"; +import db from "#services/mongo/db"; +import { RecalcAllScores, UpdateAllPBs } from "#utils/calculations/recalc-scores"; +import { RecalcSessions } from "#utils/calculations/recalc-sessions"; +import { IsValidPlaytype } from "#utils/misc"; +import DestroyUserGamePlaytypeData from "#utils/reset-state/destroy-ugpt"; +import { GetScoresFromSession } from "#utils/session"; +import { GetUserWithID, ResolveUser } from "#utils/user"; +import { type RequestHandler, Router } from "express"; +import { p } from "prudence"; +import { + type GameGroup, + type GoalSubscriptionDocument, + type integer, + type Playtype, + UserAuthLevels, +} from "tachi-common"; + +const router: Router = Router({ mergeParams: true }); + +const RequireAdminLevel: RequestHandler = async (req, res, next) => { + if (req[SYMBOL_TACHI_API_AUTH].userID === null) { + return res.status(401).json({ + success: false, + description: `You are not authenticated.`, + }); + } + + const userDoc = await GetUserWithID(req[SYMBOL_TACHI_API_AUTH].userID); + + if (!userDoc) { + log.error( + `Api Token ${req[SYMBOL_TACHI_API_AUTH].token} is assigned to ${req[SYMBOL_TACHI_API_AUTH].userID}, who does not exist?`, + ); + + return res.status(500).json({ + success: false, + description: `An internal error has occured.`, + }); + } + + if (userDoc.authLevel !== UserAuthLevels.ADMIN) { + return res.status(403).json({ + success: false, + description: `You are not authorised to perform this.`, + }); + } + + next(); +}; + +router.use(RequireAdminLevel); + +/** + * Resynchronises all PBs that match the given query or users. + * + * @param userIDs - Optionally, An array of integers of users to resync. + * @param filter - Optionally, the set of scores to resync. + * + * @name POST /api/v1/admin/resync-pbs + */ +router.post( + "/resync-pbs", + prValidate({ + userIDs: p.optional([p.isPositiveInteger]), + filter: "*object", + }), + async (req, res) => { + const body = req.safeBody as { + filter?: object; + userIDs?: Array; + }; + + await UpdateAllPBs(body.userIDs, body.filter); + + return res.status(200).json({ + success: true, + description: `Done.`, + body: {}, + }); + }, +); + +/** + * Force Delete anyones score. + * + * @param scoreID - The scoreID to delete. + * + * @name POST /api/v1/admin/delete-score + */ +router.post("/delete-score", prValidate({ scoreID: "string" }), async (req, res) => { + const body = req.safeBody as { scoreID: string }; + + const score = await db.scores.findOne({ scoreID: body.scoreID }); + + if (!score) { + return res.status(404).json({ + success: false, + description: `This score does not exist.`, + }); + } + + await DeleteScore(score); + + return res.status(200).json({ + success: true, + description: `Removed score.`, + body: {}, + }); +}); + +/** + * Force Delete anyones session. + * + * @param sessionID - The sessionID to delete. + * + * @name POST /api/v1/admin/delete-session + */ +router.post("/delete-session", prValidate({ sessionID: "string" }), async (req, res) => { + const body = req.safeBody as { sessionID: string }; + + const session = await db.sessions.findOne({ scoreID: body.sessionID }); + + if (!session) { + return res.status(404).json({ + success: false, + description: `This session does not exist.`, + }); + } + + const scores = await GetScoresFromSession(session); + + await DeleteMultipleScores(scores); + + return res.status(200).json({ + success: true, + description: `Removed session.`, + body: {}, + }); +}); + +/** + * Destroys a users UGPT profile and forces a leaderboard recalc. + * + * @param userID - The U... + * @param game - The G... + * @param playtype - And the PT to delete. + * + * @name POST /api/v1/admin/destroy-ugpt + */ +router.post( + "/destroy-ugpt", + prValidate({ + userID: p.isInteger, + game: p.isIn(TachiConfig.GAMES), + playtype: (self, parent) => { + if (typeof self !== "string") { + return "Expected a string for a playtype."; + } + + if (!IsValidPlaytype(parent.game as GameGroup, self)) { + return `Invalid playtype of ${self} for game ${parent.game as GameGroup}.`; + } + + return true; + }, + }), + async (req, res) => { + const { userID, game, playtype } = req.safeBody as { + game: GameGroup; + playtype: Playtype; + userID: integer; + }; + + const ugpt = await db["game-stats"].findOne({ + userID, + game, + playtype, + }); + + if (!ugpt) { + return res.status(404).json({ + success: false, + description: `No stats for ${userID} (${game} ${playtype}) exist.`, + }); + } + + await DestroyUserGamePlaytypeData(userID, game, playtype); + + return res.status(200).json({ + success: true, + description: `Completely destroyed UGPT for ${userID} (${game} ${playtype}).`, + body: {}, + }); + }, +); + +/** + * Destroy a chart and all of its scores (and sessions). + * + * @param chartID - The chartID to delete. + * @param game - The game this chart is for. Necessary for doing lookups. + * + * @name POST /api/v1/admin/destroy-chart + */ +router.post( + "/destroy-chart", + prValidate({ chartID: "string", game: p.isIn(TachiConfig.GAMES) }), + async (req, res) => { + const body = req.safeBody as { + chartID: string; + game: GameGroup; + }; + + const { game, chartID } = body; + + const scores = await db.scores.find({ + chartID, + }); + + await DeleteMultipleScores(scores); + + await db.anyCharts[game].remove({ + chartID, + }); + + await db["personal-bests"].remove({ + chartID, + }); + + return res.status(200).json({ + success: true, + description: `Obliterated chart.`, + body: {}, + }); + }, +); + +/** + * Perform a site recalc on this set of scores. + * + * @name POST /api/v1/admin/recalc + */ +router.post("/recalc", async (req, res) => { + const filter = req.safeBody; + + await RecalcAllScores(filter); + + const scoreIDs = ( + await db.scores.find(filter, { + projection: { + scoreID: 1, + }, + }) + ).map((e) => e.scoreID); + + await RecalcSessions({ + scoreIDs: { $in: scoreIDs }, + }); + + return res.status(200).json({ + success: true, + description: `Recalced scores.`, + body: { + scoresRecalced: scoreIDs.length, + }, + }); +}); + +/** + * Send an announcement to the site. + * + * @name POST /api/v1/admin/announcement + */ +router.post( + "/announcement", + prValidate({ + game: p.optional(p.isIn(TachiConfig.GAMES)), + playtype: "*string", + title: "string", + }), + async (req, res) => { + const { game, playtype, title } = req.safeBody as { + game?: GameGroup; + playtype?: string; + title: string; + }; + + let maybePlaytype: Playtype | undefined; + + if (game && playtype) { + if (!IsValidPlaytype(game, playtype)) { + return res.status(400).json({ + success: false, + description: `Invalid playtype '${playtype}' for game '${game}'.`, + }); + } + + maybePlaytype = playtype; + } + + await SendSiteAnnouncementNotification(title, game, maybePlaytype); + + return res.status(200).json({ + success: true, + description: `Sent notification '${title}'.`, + body: {}, + }); + }, +); + +/** + * Make this user a Tachi supporter. + * + * @name POST /api/v1/admin/supporter/:userID + */ +router.post("/supporter/:userID", async (req, res) => { + const user = await ResolveUser(req.params.userID); + + if (!user) { + return res.status(404).json({ + success: false, + description: `This user does not exist.`, + }); + } + + await db.users.update({ id: user.id }, { $set: { isSupporter: true } }); + + return res.status(200).json({ + success: true, + description: `Done.`, + body: {}, + }); +}); + +/** + * Un-Make this user a Tachi supporter. + * + * @name POST /api/v1/admin/supporter/:userID + */ +router.delete("/supporter/:userID", async (req, res) => { + const user = await ResolveUser(req.params.userID); + + if (!user) { + return res.status(404).json({ + success: false, + description: `This user does not exist.`, + }); + } + + await db.users.update({ id: user.id }, { $set: { isSupporter: false } }); + + return res.status(200).json({ + success: true, + description: `Done.`, + body: {}, + }); +}); + +/** + * Reprocess all goals for every user. This should be used to un-screw the site + * if the server goes down or peoples goals fall out of sync. Obviously, this + * should never happen, but the error handling around this stuff is really wacky. + * + * @name POST /api/v1/admin/reprocess-all-goals + */ +router.post("/reprocess-all-goals", async (req, res) => { + const ugpts = await db["game-stats"].find({}); + + const promises = []; + + for (const ugpt of ugpts) { + promises.push(async () => { + const goalSubs = await db["goal-subs"].find({ + game: ugpt.game, + playtype: ugpt.playtype, + userID: ugpt.userID, + }); + + const goalSubsMap = new Map(); + + for (const gSub of goalSubs) { + goalSubsMap.set(gSub.goalID, gSub); + } + + const goals = await db.goals.find({ + goalID: { $in: goalSubs.map((e) => e.goalID) }, + }); + + await UpdateGoalsForUser(goals, goalSubsMap, ugpt.userID, log); + + const allQuestSubs = await db["quest-subs"].find({ + game: ugpt.game, + playtype: ugpt.playtype, + userID: ugpt.userID, + }); + + const quests = await db.quests.find({ + questID: { $in: allQuestSubs.map((e) => e.questID) }, + }); + + await UpdateQuestsForUser(quests, allQuestSubs, ugpt.game, ugpt.userID, log); + }); + } + + await Promise.all(promises); + + return res.status(200).json({ + success: true, + description: "Reprocessed all goals.", + body: {}, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/auth/auth.test.ts b/typescript/server/src/server/router/api/v1postgres/auth/auth.test.ts new file mode 100644 index 000000000..0d3359bab --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/auth/auth.test.ts @@ -0,0 +1,93 @@ +import db from "#services/mongo/db"; +import { MockJSONFetch } from "#test-utils/mock-fetch"; +import ResetDBState from "#test-utils/resets"; +import t from "tap"; + +import { AddNewInvite, ReinstateInvite, ValidateCaptcha } from "./auth"; + +t.test("#ReinstateInvite", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should change the 'consumed' property of an invite to true.", async (t) => { + // mock insert + const inviteDoc = await db.invites.insert({ + code: "foobar", + consumed: true, + createdBy: 1, + createdAt: 1, + consumedAt: 2, + consumedBy: 2, + }); + + const response = await ReinstateInvite(inviteDoc.code); + + t.equal(response.nModified, 1, "Should modify one document"); + + const invite2 = await db.invites.findOne({ + // lol + code: inviteDoc.code, + }); + + t.equal(invite2!.consumed, false, "Should no longer be consumed"); + t.equal(invite2!.consumedAt, null, "Should revoke when it was consumed."); + t.equal(invite2!.consumedBy, null, "Should revoke who it was consumed by."); + + t.end(); + }); + + t.end(); +}); + +t.test("#AddNewInvite", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should create a new invite from a given user", async (t) => { + const userDoc = await db.users.findOne({ id: 1 }); + + const result = await AddNewInvite(userDoc!); + + t.equal(result.createdBy, userDoc!.id, "Invite should be created by the requesting user."); + t.equal(result.consumed, false, "Invite should not be consumed."); + + // was created +/- 6 seconds from now. This is perhaps too lenient, but we're only really testing its just around now ish. + t.ok(Math.abs(result.createdAt - Date.now()) <= 6000, "Invite was created roughly now."); + + t.match(result.code, /^[0-9a-f]{40}$/u, "Invite code should be a 40 character hex string."); + }); + + t.end(); +}); + +t.test("#ValidateCaptcha", async (t) => { + t.equal( + await ValidateCaptcha( + "200", + "bar", + MockJSONFetch({ + "https://www.google.com/recaptcha/api/siteverify?secret=unused&response=200&remoteip=bar": + { + success: true, + }, + }), + ), + true, + "Validates captcha when sucess return is true", + ); + + t.equal( + await ValidateCaptcha( + "400", + "bar", + MockJSONFetch({ + "https://www.google.com/recaptcha/api/siteverify?secret=unused&response=400&remoteip=bar": + { + success: false, + }, + }), + ), + false, + "Invalidates captcha when success return is not true", + ); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/auth/auth.ts b/typescript/server/src/server/router/api/v1postgres/auth/auth.ts new file mode 100644 index 000000000..c07dc4368 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/auth/auth.ts @@ -0,0 +1,193 @@ +import type { PrivateUserInfoDocument } from "#utils/types"; + +import { log } from "#lib/log/log.js"; +import { Env, ServerConfig } from "#lib/setup/config"; +import db from "#services/mongo/db"; +import nodeFetch from "#utils/fetch"; +import { Random20Hex } from "#utils/misc"; +import { CreateURLWithParams } from "#utils/url"; +import { FormatUserDoc } from "#utils/user"; +import bcrypt from "bcryptjs"; +import { p } from "prudence"; +import { + type integer, + UserAuthLevels, + type UserDocument, + type UserSettingsDocument, +} from "tachi-common"; + +const BCRYPT_SALT_ROUNDS = 12; + +export const ValidatePassword = (self: unknown) => + (typeof self === "string" && self.length >= 8) || "Passwords must be 8 characters or more."; + +const LAZY_EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/u; + +export const ValidateEmail = p.regex(LAZY_EMAIL_REGEX); + +/** + * Compares a plaintext string of a users password to a hash. + * @param plaintext The provided user input. + * @param password The hash to compare against. + */ +export function PasswordCompare(plaintext: string, password: string) { + return bcrypt.compare(plaintext, password); +} + +export function ReinstateInvite(code: string) { + log.info(`Reinstated Invite ${code}`); + return db.invites.update( + { + code, + }, + { + $set: { + consumed: false, + consumedAt: null, + consumedBy: null, + }, + }, + ); +} + +export async function AddNewInvite(user: UserDocument) { + const code = Random20Hex(); + + const result = await db.invites.insert({ + code, + consumed: false, + createdBy: user.id, + createdAt: Date.now(), + consumedAt: null, + consumedBy: null, + }); + + log.info(`User ${FormatUserDoc(user)} created an invite.`); + + return result; +} + +export const DEFAULT_USER_SETTINGS: UserSettingsDocument["preferences"] = { + developerMode: false, + advancedMode: false, + invisible: false, + contentiousContent: false, + deletableScores: false, +}; + +export function HashPassword(plaintext: string) { + return bcrypt.hash(plaintext, BCRYPT_SALT_ROUNDS); +} + +export async function AddNewUser( + username: string, + plaintext: string, + email: string, + userID: integer, +) { + const hashedPassword = await HashPassword(plaintext); + + log.debug(`Hashed password for ${username}.`); + + const userDoc: UserDocument = { + id: userID, + username, + usernameLowercase: username.toLowerCase(), + about: "I'm a fairly nondescript person.", + socialMedia: {}, + status: null, + customBannerLocation: null, + customPfpLocation: null, + joinDate: Date.now(), + lastSeen: Date.now(), + authLevel: UserAuthLevels.USER, + badges: [], + }; + + // all created users on a dev instance should be admins, for convenience. + if (Env.NODE_ENV === "dev") { + userDoc.authLevel = UserAuthLevels.ADMIN; + } + + const res = await db.users.insert(userDoc); + + const settingsRes = await InsertDefaultUserSettings(userID); + + await InsertPrivateUserInfo(userID, hashedPassword, email); + + return { newUser: res, newSettings: settingsRes }; +} + +export function InsertPrivateUserInfo(userID: integer, hashedPassword: string, email: string) { + const privateInfo: PrivateUserInfoDocument = { + userID, + email, + password: hashedPassword, + }; + + return db["user-private-information"].insert(privateInfo); +} + +export function InsertDefaultUserSettings(userID: integer) { + log.debug(`Inserting default settings for ${userID}.`); + const UserSettingsDocument: UserSettingsDocument = { + userID, + following: [], + preferences: DEFAULT_USER_SETTINGS, + }; + + return db["user-settings"].insert(UserSettingsDocument); +} + +export async function ValidateCaptcha( + recaptcha: string, + remoteAddr: string | undefined, + fetch = nodeFetch, +) { + const url = CreateURLWithParams(`https://www.google.com/recaptcha/api/siteverify`, { + secret: ServerConfig.CAPTCHA_SECRET_KEY, + response: recaptcha, + remoteip: remoteAddr ?? "", + }); + + const googleCaptchaRes: unknown = await fetch(url.href).then((r) => r.json()); + + const err = p( + googleCaptchaRes, + { + success: "boolean", + }, + {}, + { allowExcessKeys: true }, + ); + + if (err) { + log.warn( + { googleCaptchaRes, err }, + `Google ReCaptcha returned something without a success property? Assuming this captcha check failed.`, + ); + return false; + } + + // asserted above + const gcr = googleCaptchaRes as { success: boolean }; + + if (!gcr.success) { + log.debug({ gcr }, `Failed GCaptcha response`); + } + + return gcr.success; +} + +export function MountAuthCookie( + req: Express.Request, + user: UserDocument, + settings: UserSettingsDocument, +) { + req.session.tachi = { + user, + settings, + }; + + req.session.cookie.maxAge = 3.154e10; +} diff --git a/typescript/server/src/server/router/api/v1postgres/auth/router.test.ts b/typescript/server/src/server/router/api/v1postgres/auth/router.test.ts new file mode 100644 index 000000000..56c7ee714 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/auth/router.test.ts @@ -0,0 +1,378 @@ +import { ClearTestingRateLimitCache } from "#server/middleware/rate-limiter"; +import db from "#services/mongo/db"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { Sleep } from "#utils/misc"; +import t from "tap"; + +import { PasswordCompare } from "./auth"; + +t.test("POST /api/v1/auth/login", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(ClearTestingRateLimitCache); + + t.test("Should log a user in with right credentials", async (t) => { + const res = await mockApi.post("/api/v1/auth/login").send({ + username: "test_zkldi", + "!password": "password", + captcha: "foo", + }); + + t.equal(res.status, 200); + t.equal(res.body.success, true); + t.strictSame(res.body.body, { + userID: 1, + }); + + const cookie = res.headers["set-cookie"]; + + const stat = await mockApi.get("/api/v1/status").set("Cookie", cookie); + + t.ok(stat.body.body.permissions.length > 0); + + t.end(); + }); + + t.test("Should return 200 if user already logged in", async (t) => { + const res = await mockApi.post("/api/v1/auth/login").send({ + username: "test_zkldi", + "!password": "password", + captcha: "foo", + }); + + const cookie = res.headers["set-cookie"]; + + const res2 = await mockApi + .post("/api/v1/auth/login") + .send({ + username: "test_zkldi", + "!password": "password", + captcha: "foo", + }) + .set("Cookie", cookie); + + // even if they have a login already going, just let them log in. + t.equal(res2.status, 200); + + t.end(); + }); + + t.test("Should return 403 if password invalid", async (t) => { + const res = await mockApi.post("/api/v1/auth/login").send({ + username: "test_zkldi", + "!password": "invalid_password", + captcha: "foo", + }); + + t.equal(res.status, 403); + + t.end(); + }); + + t.test("Should return 404 if user invalid", async (t) => { + const res = await mockApi.post("/api/v1/auth/login").send({ + username: "invalid_user", + "!password": "password", + captcha: "foo", + }); + + t.equal(res.status, 404); + + t.end(); + }); + + t.test("Should return 400 if no password", async (t) => { + const res = await mockApi.post("/api/v1/auth/login").send({ + username: "invalid_user", + captcha: "foo", + }); + + t.equal(res.status, 400); + + t.end(); + }); + + t.test("Should return 400 if no username", async (t) => { + const res = await mockApi.post("/api/v1/auth/login").send({ + "!password": "password", + captcha: "foo", + }); + + t.equal(res.status, 400); + + t.end(); + }); + + t.test("Should return 400 if no captcha", async (t) => { + const res = await mockApi.post("/api/v1/auth/login").send({ + "!password": "password", + username: "test_zkldi", + }); + + t.equal(res.status, 400); + + t.end(); + }); + + t.end(); +}); + +t.test("POST /api/v1/auth/register", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(ClearTestingRateLimitCache); + + t.beforeEach(() => + db.invites.insert({ + code: "code", + createdBy: 1, + createdAt: 0, + consumed: false, + consumedAt: null, + consumedBy: null, + }), + ); + + t.test("Should register a new user.", async (t) => { + const res = await mockApi.post("/api/v1/auth/register").send({ + username: "foo", + "!password": "password", + email: "foo@bar.com", + captcha: "1", + inviteCode: "code", + }); + + t.equal(res.statusCode, 200); + t.equal(res.body.success, true); + t.equal(res.body.body.username, "foo"); + + const doc = await db.users.findOne({ username: "foo" }); + + t.not(doc, null); + + t.end(); + }); + + t.test("Should disallow users with matching names.", async (t) => { + const res = await mockApi.post("/api/v1/auth/register").send({ + username: "test_zkldi", + "!password": "password", + email: "foo@bar.com", + captcha: "1", + inviteCode: "code", + }); + + t.equal(res.statusCode, 409); + t.equal(res.body.success, false); + + t.end(); + }); + + t.test("Should disallow users with matching names case insensitively.", async (t) => { + const res = await mockApi.post("/api/v1/auth/register").send({ + username: "test_zKLdi", + "!password": "password", + email: "foo@bar.com", + captcha: "1", + inviteCode: "code", + }); + + t.equal(res.statusCode, 409); + t.equal(res.body.success, false); + + t.end(); + }); + + t.test("Should disallow email if it is already used.", async (t) => { + const res = await mockApi.post("/api/v1/auth/register").send({ + username: "foo", + "!password": "password", + + // this is our test docs email, apparently. + email: "thepasswordis@password.com", + captcha: "1", + inviteCode: "code", + }); + + t.equal(res.statusCode, 409); + t.equal(res.body.success, false); + + t.end(); + }); + + t.test("Should disallow invalid emails.", async (t) => { + const res = await mockApi.post("/api/v1/auth/register").send({ + username: "foo", + "!password": "password", + email: "nonsense+email", + captcha: "1", + inviteCode: "code", + }); + + t.equal(res.statusCode, 400); + t.equal(res.body.success, false); + + t.end(); + }); + + t.test("Should disallow short passwords.", async (t) => { + const res = await mockApi.post("/api/v1/auth/register").send({ + username: "foo", + "!password": "pass", + email: "foo@bar.com", + captcha: "1", + inviteCode: "code", + }); + + t.equal(res.statusCode, 400); + t.equal(res.body.success, false); + + t.end(); + }); + + t.test("Should disallow invalid usernames.", async (t) => { + const res = await mockApi.post("/api/v1/auth/register").send({ + username: "3foo", + "!password": "password", + email: "foo@bar.com", + captcha: "1", + inviteCode: "code", + }); + + t.equal(res.statusCode, 400); + t.equal(res.body.success, false); + + const res2 = await mockApi.post("/api/v1/auth/register").send({ + username: "f", + "!password": "password", + email: "foo@bar.com", + captcha: "1", + inviteCode: "code", + }); + + t.equal(res2.statusCode, 400); + t.equal(res2.body.success, false); + + t.end(); + }); + + t.test("Should recover from a fatal error without breaking state.", async (t) => { + // this will cause a userID collision + await db.counters.update({ counterName: "users" }, { $set: { value: 1 } }); + + const res = await mockApi.post("/api/v1/auth/register").send({ + username: "foo", + "!password": "password", + email: "foo@bar.com", + captcha: "1", + inviteCode: "code", + }); + + t.equal(res.statusCode, 500); + + const counter = await db.counters.findOne({ counterName: "users" }); + + // value should not stay incremented + t.equal(counter?.value, 1); + + const invite = await db.invites.findOne({ code: "code" }); + + // invite should not be consumed + t.equal(invite?.consumed, false); + + t.end(); + }); + + t.end(); +}); + +t.test("POST /api/v1/auth/forgot-password", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(ClearTestingRateLimitCache); + + t.test("Should create a code to reset a password with.", async (t) => { + const res = await mockApi.post("/api/v1/auth/forgot-password").send({ + email: "thepasswordis@password.com", + }); + + t.equal(res.statusCode, 202, "Should return 202 immediately."); + + t.strictSame(res.body.body, {}, "Should have no body."); + + // We have to wait for this operation to complete, otherwise, this isn't going to work. + // Note that 3seconds is a bit excessive, but better safe than + // sorry! + await Sleep(3_000); + + const dbRes = await db["password-reset-codes"].findOne({ + userID: 1, + }); + + t.not(dbRes, null, "Should exist and save a code to the database."); + + t.end(); + }); + + t.test( + "Should not create a code to reset a password with if the email does not exist.", + async (t) => { + const res = await mockApi.post("/api/v1/auth/forgot-password").send({ + email: "bademail@example.com", + }); + + t.equal(res.statusCode, 202, "Should return 202 immediately."); + + t.strictSame(res.body.body, {}, "Should have no body."); + + await Sleep(3_000); + + const dbRes = await db["password-reset-codes"].findOne({ + userID: 1, + }); + + t.equal(dbRes, null, "Should not bother sending a code to the database."); + + t.end(); + }, + ); + + t.end(); +}); + +t.test("POST /api/v1/auth/reset-password", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(ClearTestingRateLimitCache); + + t.test("Should reset a users password if they have a valid code.", async (t) => { + await db["password-reset-codes"].insert({ + code: "SECRET_CODE", + createdOn: Date.now(), + userID: 1, + }); + + const res = await mockApi.post("/api/v1/auth/reset-password").send({ + code: "SECRET_CODE", + "!password": "newpassword", + }); + + t.equal(res.statusCode, 200); + + const dbRes = await db["password-reset-codes"].findOne({ + code: "SECRET_CODE", + }); + + t.equal(dbRes, null, "Codes MUST be destroyed after use."); + + const privateInfo = await db["user-private-information"].findOne({ + userID: 1, + }); + + t.ok( + await PasswordCompare("newpassword", privateInfo!.password), + "Password must be updated to 'newpassword'", + ); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/auth/router.ts b/typescript/server/src/server/router/api/v1postgres/auth/router.ts new file mode 100644 index 000000000..18ba98810 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/auth/router.ts @@ -0,0 +1,575 @@ +import type { integer } from "tachi-common"; + +import { SendEmail } from "#lib/email/client"; +import { EmailFormatResetPassword, EmailFormatVerifyEmail } from "#lib/email/formats"; +import { log } from "#lib/log/log.js"; +import { Env, ServerConfig, TachiConfig } from "#lib/setup/config"; +import prValidate from "#server/middleware/prudence-validate"; +import { + AggressiveRateLimitMiddleware, + HyperAggressiveRateLimitMiddleware, +} from "#server/middleware/rate-limiter"; +import db from "#services/mongo/db"; +import { DecrementCounterValue, GetNextCounterValue } from "#utils/db"; +import { Random20Hex } from "#utils/misc"; +import { + CheckIfEmailInUse, + FormatUserDoc, + GetSettingsForUser, + GetUserCaseInsensitive, + GetUserPrivateInfo, + GetUserWithID, + GetUserWithIDGuaranteed, +} from "#utils/user"; +import { Router } from "express"; +import { p } from "prudence"; + +import { + AddNewUser, + HashPassword, + InsertDefaultUserSettings, + MountAuthCookie, + PasswordCompare, + ReinstateInvite, + ValidateCaptcha, + ValidateEmail, + ValidatePassword, +} from "./auth"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Logs in a user. + * @name POST /api/v1/auth/login + */ +router.post( + "/login", + AggressiveRateLimitMiddleware, + prValidate( + { + username: p.regex(/^[a-zA-Z_-][a-zA-Z0-9_-]{2,20}$/u), + "!password": ValidatePassword, + captcha: "string", + }, + { + username: + "Invalid username. Usernames cannot start with a number, and must be between 2 and 20 characters.", + captcha: "Please fill out the captcha.", + }, + undefined, + "debug", + ), + async (req, res) => { + if (req.session.tachi?.user.id !== undefined) { + // Dual logins should destroy the users session and recreate it. + req.session.tachi = undefined; + } + + const body = req.safeBody as { + "!password": string; + captcha: string; + username: string; + }; + + log.debug(`Received login request with username ${body.username} (${req.ip})`); + + /* istanbul ignore next */ + if (Env.NODE_ENV === "production" || Env.NODE_ENV === "staging") { + log.debug("Validating captcha..."); + const validCaptcha = await ValidateCaptcha(body.captcha, req.socket.remoteAddress); + + if (!validCaptcha) { + log.debug("Captcha failed."); + return res.status(400).json({ + success: false, + description: `Captcha failed.`, + }); + } + + log.debug("Captcha validated!"); + } else { + log.warn("Skipped captcha check because not in production."); + } + + const requestedUser = await GetUserCaseInsensitive(body.username); + + if (!requestedUser) { + log.debug(`Invalid username for login ${body.username}.`); + return res.status(404).json({ + success: false, + description: `This user does not exist.`, + }); + } + + const privateInfo = await GetUserPrivateInfo(requestedUser.id); + + if (!privateInfo) { + log.error( + { requestedUser }, + `State desync for user ${FormatUserDoc( + requestedUser, + )}. This user has no password/email information?`, + ); + + return res.status(500).json({ + success: false, + description: `An internal server error has occured.`, + }); + } + + const passwordMatch = await PasswordCompare(body["!password"], privateInfo.password); + + if (!passwordMatch) { + log.debug("Invalid password provided."); + return res.status(403).json({ + success: false, + description: `Invalid password.`, + }); + } + + const user = await GetUserWithID(requestedUser.id); + + if (!user) { + log.error({ requestedUser }, `User logged in as someone who does not exist?`); + return res.status(500).json({ + success: false, + description: `An internal server error has occured.`, + }); + } + + let settings = await GetSettingsForUser(requestedUser.id); + + if (!settings) { + log.warn(`User ${FormatUserDoc(user)} has no settings. Inserting default settings.`); + settings = await InsertDefaultUserSettings(user.id); + } + + MountAuthCookie(req, user, settings); + + log.debug(`${FormatUserDoc(requestedUser)} Logged in.`); + + return res.status(200).json({ + success: true, + description: `Successfully logged in as ${FormatUserDoc(requestedUser)}`, + body: { + userID: requestedUser.id, + }, + }); + }, +); + +/** + * Registers a new user. + * @name POST /api/v1/auth/register + */ +router.post( + "/register", + AggressiveRateLimitMiddleware, + prValidate( + { + username: p.regex(/^[a-zA-Z_-][a-zA-Z0-9_-]{2,20}$/u), + "!password": ValidatePassword, + email: ValidateEmail, + inviteCode: "*string", + captcha: "string", + }, + { + username: + "Usernames must be between 3 and 20 characters long, can only contain alphanumeric characters and cannot start with a number.", + email: "Invalid email.", + inviteCode: "Invalid invite code.", + captcha: "Please fill out the captcha.", + }, + undefined, + "debug", + ), + async (req, res) => { + if (!TachiConfig.SIGNUPS_ENABLED) { + return res.status(501).json({ + success: false, + description: `Signups are not currently enabled.`, + }); + } + + const body = req.safeBody as { + "!password": string; + captcha: string; + email: string; + inviteCode?: string; + username: string; + }; + + // force lowercase for emails to avoid case-confusion in lookups... + body.email = body.email.toLowerCase(); + + if (body.inviteCode === undefined && ServerConfig.INVITE_CODE_CONFIG) { + return res.status(400).json({ + success: false, + description: `No invite code given, yet the server uses invites.`, + }); + } + + log.debug(`received register request with username ${body.username} (${req.ip})`); + + /* istanbul ignore next */ + if (Env.NODE_ENV === "production" || Env.NODE_ENV === "staging") { + log.debug("Validating captcha..."); + const validCaptcha = await ValidateCaptcha(body.captcha, req.socket.remoteAddress); + + if (!validCaptcha) { + log.debug("Captcha failed."); + return res.status(400).json({ + success: false, + description: `Captcha failed.`, + }); + } + + log.debug("Captcha validated."); + } else { + log.warn("Skipped captcha check because not in production."); + } + + const existingUser = await GetUserCaseInsensitive(body.username); + + if (existingUser) { + log.debug(`Invalid username ${body.username}, already in use.`); + return res.status(409).json({ + success: false, + description: "This username is already in use.", + }); + } + + const existingEmail = await CheckIfEmailInUse(body.email); + + if (existingEmail) { + log.info(`User attempted to sign up with email that was already in use.`); + return res.status(409).json({ + success: false, + description: `This email is already in use.`, + }); + } + + let hasInsertedUserID: integer | null = null; + + try { + const userID = await GetNextCounterValue("users"); + + if (ServerConfig.INVITE_CODE_CONFIG) { + const inviteCodeDoc = await db.invites.findOneAndUpdate( + { + code: body.inviteCode, + consumed: false, + }, + { + $set: { + consumed: true, + consumedAt: Date.now(), + consumedBy: userID, + }, + }, + ); + + if (!inviteCodeDoc) { + log.info(`Invalid invite code given: ${body.inviteCode}.`); + return res.status(401).json({ + success: false, + description: `This invite code is not valid.`, + }); + } + + log.info(`Consumed invite ${inviteCodeDoc.code}.`); + } + + // if we get to this point, We're good to create the user. + + const { newUser, newSettings } = await AddNewUser( + body.username, + body["!password"], + body.email, + userID, + ); + + hasInsertedUserID = newUser.id; + + // re-fetch the user like this so we guaranteeably omit the private fields. + const user = await GetUserWithIDGuaranteed(newUser.id); + + MountAuthCookie(req, user, newSettings); + + // If we have an EMAIL_CONFIG set, send out + // authentication emails. + // Otherwise, don't bother; this is equivalent to + // automatically verifying all users' emails. + if (ServerConfig.EMAIL_CONFIG) { + const resetEmailCode = Random20Hex(); + + await db["verify-email-codes"].insert({ + code: resetEmailCode, + userID, + email: body.email, + }); + + const { text, html } = EmailFormatVerifyEmail(user.username, resetEmailCode); + + void SendEmail(body.email, "Email Verification", html, text); + } + + return res.status(200).json({ + success: true, + description: `Successfully created account ${body.username}!`, + body: user, + }); + } catch (err) { + log.error({ err }, `Bailed on user creation ${body.username}.`); + + if (ServerConfig.INVITE_CODE_CONFIG && body.inviteCode !== undefined) { + await ReinstateInvite(body.inviteCode); + } + + if (hasInsertedUserID !== null) { + log.warn( + `Removing user ${body.username} (#${hasInsertedUserID}), as their document was created, but creation still failed.`, + ); + await db.users.remove({ username: body.username }); + await db["user-settings"].remove({ userID: hasInsertedUserID }); + await db["user-private-information"].remove({ userID: hasInsertedUserID }); + } + + await DecrementCounterValue("users"); + + return res.status(500).json({ + success: false, + description: "An internal server error has occured.", + }); + } + }, +); + +/** + * Verifies the provided email according to the code provided. + * + * @param code - The emailCode set in the /register function. + * + * @name POST /api/v1/auth/verify-email + */ +router.post( + "/verify-email", + AggressiveRateLimitMiddleware, + prValidate({ + code: "string", + }), + async (req, res) => { + const body = req.safeBody as { + code: string; + }; + + const code = await db["verify-email-codes"].findOne({ + code: body.code, + }); + + if (!code) { + return res.status(400).json({ + success: false, + description: `This email code is invalid.`, + }); + } + + await db["verify-email-codes"].remove({ + code: body.code, + }); + + return res.status(200).json({ + success: true, + description: `Verified email!`, + body: {}, + }); + }, +); + +/** + * Resend a verification email, for when they fall through the + * cracks. + * + * @param email - The email to send a verification email to. + * + * @name POST /api/v1/auth/resend-verify-email + */ +router.post("/resend-verify-email", HyperAggressiveRateLimitMiddleware, async (req, res) => { + // Immediately send a response so the existence of emails + // cannot be timing attacked out. + res.status(200).json({ + success: true, + description: `Sent an email if the email address has not been verified.`, + body: {}, + }); + + const user = req.session.tachi?.user; + + if (!user) { + return; + } + + const userID = user.id; + + const verifyInfo = await db["verify-email-codes"].findOne({ userID }); + + if (!verifyInfo) { + log.warn(`Attempted to send reset email to ${userID}, but no verifyInfo was set for them.`); + return; + } + + // Send the email again. + + const { text, html } = EmailFormatVerifyEmail(user.username, verifyInfo.code); + + void SendEmail(verifyInfo.email, "Email Verification", html, text); +}); + +/** + * Logs out the requesting user. + * @name POST /api/v1/auth/logout + */ +router.post("/logout", (req, res) => { + if (req.session.tachi?.user.id === undefined) { + return res.status(409).json({ + success: false, + description: `You are not logged in.`, + }); + } + + req.session.destroy(() => 0); + + return res.status(200).json({ + success: true, + description: `Logged Out.`, + body: {}, + }); +}); + +/** + * Creates a password reset code for a user. The user will then + * be able to trigger POST /reset-password with that code. + * + * @param email - The email associated with the account you want to reset. + * + * @name POST /api/v1/auth/forgot-password + */ +router.post( + "/forgot-password", + HyperAggressiveRateLimitMiddleware, + prValidate({ email: "string" }), + async (req, res) => { + if (!ServerConfig.EMAIL_CONFIG && Env.NODE_ENV !== "test") { + return res.status(501).json({ + success: false, + description: `This server does not support password resets.`, + }); + } + + const body = req.safeBody as { + email: string; + }; + + body.email = body.email.toLowerCase(); + + log.debug(`received password reset request for ${body.email}.`); + + // For timing attack and infosec reasons, we can't do anything but **immediately** return here. + res.status(202).json({ + success: true, + description: "A code has been sent to your email.", + body: {}, + }); + + const userPrivateInfo = await db["user-private-information"].findOne({ + email: body.email, + }); + + if (userPrivateInfo) { + const user = await db.users.findOne({ id: userPrivateInfo.userID }); + + if (!user) { + log.error( + `User ${userPrivateInfo.userID} has private information but no real account.`, + ); + return; + } + + const code = `M${Random20Hex()}`; + + log.debug(`Created password reset code for ${FormatUserDoc(user)}.`); + + await db["password-reset-codes"].insert({ + code, + userID: user.id, + createdOn: Date.now(), + }); + + const { html, text } = EmailFormatResetPassword(user.username, code, req.ip); + + void SendEmail(userPrivateInfo.email, "Reset Password", html, text); + } else { + log.info( + `Silently rejected password reset request for ${body.email}, as no user has this email.`, + ); + } + }, +); + +/** + * Takes a code generated from /forgot-password, a new password, + * and performs the reset for the user. + * + * @param password - The users new password. + * @param code - The code to use to reset this password. + * + * @name POST /api/v1/auth/reset-password + */ +router.post( + "/reset-password", + AggressiveRateLimitMiddleware, + prValidate({ + code: "string", + "!password": ValidatePassword, + }), + async (req, res) => { + const body = req.safeBody as { + "!password": string; + code: string; + }; + + const code = await db["password-reset-codes"].findOneAndDelete({ + code: body.code, + }); + + if (!code) { + return res.status(404).json({ + success: false, + description: `Invalid Reset Code.`, + }); + } + + const encryptedPassword = await HashPassword(body["!password"]); + + await db["user-private-information"].update( + { + userID: code.userID, + }, + { + $set: { + password: encryptedPassword, + }, + }, + ); + + log.info(`User ${code.userID} reset their password.`); + + return res.status(200).json({ + success: true, + description: `Reset your password.`, + body: {}, + }); + }, +); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/clients/middleware.test.ts b/typescript/server/src/server/router/api/v1postgres/clients/middleware.test.ts new file mode 100644 index 000000000..fa4f24029 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/clients/middleware.test.ts @@ -0,0 +1,124 @@ +import { SYMBOL_TACHI_DATA } from "#lib/constants/tachi"; +import { expressRequestMock } from "#test-utils/mock-request"; +import ResetDBState from "#test-utils/resets"; +import t from "tap"; + +import { GetClientFromID, RequireOwnershipOfClient } from "./middleware"; + +t.test("#GetClientFromID", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should assign the client to req[@@TachiData] if exists.", async (t) => { + const { req } = await expressRequestMock(GetClientFromID, { + params: { + clientID: "OAUTH2_CLIENT_ID", + }, + [SYMBOL_TACHI_DATA]: {}, + }); + + t.strictSame( + req[SYMBOL_TACHI_DATA]?.apiClientDoc, + { + clientID: "OAUTH2_CLIENT_ID", + + // clientSecret: "OAUTH2_CLIENT_SECRET", + name: "Test_Service", + author: 1, + requestedPermissions: ["customise_profile"], + redirectUri: "https://example.com/callback", + webhookUri: null, + apiKeyTemplate: null, + apiKeyFilename: null, + }, + "Should assign clientDoc with secret omitted.", + ); + + t.end(); + }); + + t.test("Should return 404 if client does not exist.", async (t) => { + const { res } = await expressRequestMock(GetClientFromID, { + params: { + clientID: "NONSENSE", + }, + [SYMBOL_TACHI_DATA]: {}, + }); + + t.equal(res.statusCode, 404); + + t.hasStrict(res._getJSONData(), { + success: false, + description: "This client does not exist.", + }); + + t.end(); + }); + + t.end(); +}); + +t.test("#RequireOwnershipOfClient", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return 401 if the user has no authentication.", async (t) => { + const { res } = await expressRequestMock(RequireOwnershipOfClient, { + safeBody: { + __terribleHackOauth2ClientDoc: { + author: 1, + }, + }, + [SYMBOL_TACHI_DATA]: {}, + session: {}, + }); + + t.equal(res.statusCode, 401); + + t.end(); + }); + + t.test("Should return 403 if the user does not own this client.", async (t) => { + const { res } = await expressRequestMock(RequireOwnershipOfClient, { + safeBody: { + __terribleHackOauth2ClientDoc: { + author: 1, + }, + }, + session: { + tachi: { + user: { + id: 2, + }, + }, + }, + [SYMBOL_TACHI_DATA]: {}, + }); + + t.equal(res.statusCode, 403); + + t.end(); + }); + + t.test("Should continue if this is their session.", async (t) => { + const { res } = await expressRequestMock(RequireOwnershipOfClient, { + safeBody: { + __terribleHackOauth2ClientDoc: { + author: 1, + }, + }, + session: { + tachi: { + user: { + id: 1, + }, + }, + }, + [SYMBOL_TACHI_DATA]: {}, + }); + + t.equal(res.statusCode, 200); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/clients/middleware.ts b/typescript/server/src/server/router/api/v1postgres/clients/middleware.ts new file mode 100644 index 000000000..93de2eb4e --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/clients/middleware.ts @@ -0,0 +1,68 @@ +import type { RequestHandler } from "express"; +import type { TachiAPIClientDocument } from "tachi-common"; + +import { Env } from "#lib/setup/config"; +import db from "#services/mongo/db"; +import { AssignToReqTachiData, GetTachiData } from "#utils/req-tachi-data"; + +export const GetClientFromID: RequestHandler = async (req, res, next) => { + const client = await db["api-clients"].findOne( + { + clientID: req.params.clientID, + }, + { + projection: { + clientSecret: 0, + }, + }, + ); + + if (!client) { + return res.status(404).json({ + success: false, + description: `This client does not exist.`, + }); + } + + AssignToReqTachiData(req, { apiClientDoc: client }); + + next(); +}; + +export const RequireOwnershipOfClient: RequestHandler = (req, res, next) => { + let client: Omit; + + // @hack + // Sadly, expMiddlewareMock doesn't support mounting symbol props on + // request. To hack around this for testing, we perform this hack. + // There's an open issue for this here: https://github.com/i-like-robots/express-request-mock/issues/19 + /* istanbul ignore next */ + if ( + Env.NODE_ENV === "test" && + (req.safeBody.__terribleHackOauth2ClientDoc as TachiAPIClientDocument | undefined) + ) { + // obviously a glaring hack and security flaw - this only applies + // in testing. + client = req.safeBody.__terribleHackOauth2ClientDoc as TachiAPIClientDocument; + } else { + client = GetTachiData(req, "apiClientDoc"); + } + + const user = req.session.tachi?.user; + + if (!user) { + return res.status(401).json({ + success: false, + description: `You are not authenticated (for a session-level request, atleast).`, + }); + } + + if (user.id !== client.author) { + return res.status(403).json({ + success: false, + description: `You are not authorized to perform this action.`, + }); + } + + next(); +}; diff --git a/typescript/server/src/server/router/api/v1postgres/clients/router.test.ts b/typescript/server/src/server/router/api/v1postgres/clients/router.test.ts new file mode 100644 index 000000000..d0f9b08c9 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/clients/router.test.ts @@ -0,0 +1,468 @@ +import type { APITokenDocument, TachiAPIClientDocument } from "tachi-common"; + +import { ServerConfig } from "#lib/setup/config"; +import db from "#services/mongo/db"; +import { CreateFakeAuthCookie } from "#test-utils/fake-auth"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import t from "tap"; + +const clientDataset: Array = [ + { + author: 1, + clientID: "CLIENT_1", + clientSecret: "SECRET_1", + name: "foo", + redirectUri: "example.com", + requestedPermissions: ["customise_profile"], + webhookUri: null, + apiKeyFilename: null, + apiKeyTemplate: null, + }, + { + author: 1, + clientID: "CLIENT_2", + clientSecret: "SECRET_2", + name: "bar", + redirectUri: "example.com", + requestedPermissions: ["customise_profile"], + webhookUri: null, + apiKeyFilename: null, + apiKeyTemplate: null, + }, + { + author: 2, + clientID: "CLIENT_3", + clientSecret: "SECRET_3", + name: "baz", + redirectUri: "example.com", + requestedPermissions: ["customise_profile"], + webhookUri: null, + apiKeyFilename: null, + apiKeyTemplate: null, + }, +]; + +t.test("GET /api/v1/clients", async (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(async () => { + await db["api-clients"].remove({}); + await db["api-clients"].insert(clientDataset); + }); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should retrieve your clients.", async (t) => { + const res = await mockApi.get("/api/v1/clients").set("Cookie", cookie); + + t.equal(res.statusCode, 200); + + // note: force sort alphabetically so this isn't dependent on + // mongodb natural order. + t.strictSame( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + res.body.body.sort((a: any, b: any) => a.name - b.name), + [ + { + author: 1, + clientID: "CLIENT_1", + clientSecret: "SECRET_1", + name: "foo", + redirectUri: "example.com", + requestedPermissions: ["customise_profile"], + webhookUri: null, + apiKeyFilename: null, + apiKeyTemplate: null, + }, + { + author: 1, + clientID: "CLIENT_2", + clientSecret: "SECRET_2", + name: "bar", + redirectUri: "example.com", + requestedPermissions: ["customise_profile"], + webhookUri: null, + apiKeyFilename: null, + apiKeyTemplate: null, + }, + ], + ); + + t.end(); + }); + + t.test("Requires self-key level authentication.", async (t) => { + const res = await mockApi.get("/api/v1/clients"); + + t.equal(res.statusCode, 401); + + const res2 = await mockApi + .get("/api/v1/clients") + .set("Authorization", "Bearer fake_api_token"); + + t.equal(res2.statusCode, 401); + + t.end(); + }); + + t.end(); +}); + +t.test("POST /api/v1/clients/create", async (t) => { + t.beforeEach(ResetDBState); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should create a new client.", async (t) => { + const res = await mockApi + .post("/api/v1/clients/create") + .send({ + name: "Hello World", + redirectUri: "https://example.com/callback", + permissions: ["customise_profile"], + webhookUri: null, + apiKeyTemplate: null, + apiKeyFilename: null, + }) + .set("Cookie", cookie); + + t.equal(res.statusCode, 200); + + const dbRes = await db["api-clients"].findOne({ clientID: res.body.body.clientID }); + + t.not(dbRes, null, "Should be saved in the database."); + + t.strictSame(dbRes?.requestedPermissions, ["customise_profile"]); + + t.end(); + }); + + t.test("Should validate names to be between 3 and 80 characters.", async (t) => { + const res = await mockApi + .post("/api/v1/clients/create") + .send({ + name: "2", + redirectUri: "https://example.com/callback", + permissions: ["customise_profile"], + webhookUri: null, + apiKeyTemplate: null, + apiKeyFilename: null, + }) + .set("Cookie", cookie); + + t.equal(res.statusCode, 400); + + const res2 = await mockApi + .post("/api/v1/clients/create") + .send({ + name: "2".repeat(100), + redirectUri: "https://example.com/callback", + permissions: ["customise_profile"], + webhookUri: null, + apiKeyTemplate: null, + apiKeyFilename: null, + }) + .set("Cookie", cookie); + + t.equal(res2.statusCode, 400); + + t.end(); + }); + + t.test("Should validate urls to be between 3 and 80 characters.", async (t) => { + const res = await mockApi + .post("/api/v1/clients/create") + .send({ + name: "Hello World", + redirectUri: "ftp://example.com/callback", + permissions: ["customise_profile"], + webhookUri: null, + apiKeyTemplate: null, + apiKeyFilename: null, + }) + .set("Cookie", cookie); + + t.equal(res.statusCode, 400); + + t.end(); + }); + + t.test("Should validate permissions.", async (t) => { + const res = await mockApi + .post("/api/v1/clients/create") + .send({ + name: "Hello World", + redirectUri: "http://example.com/callback", + permissions: ["permission_that_doesnt_exist"], + webhookUri: null, + apiKeyTemplate: null, + apiKeyFilename: null, + }) + .set("Cookie", cookie); + + t.equal(res.statusCode, 400); + + t.end(); + }); + + // Currently skipped as its difficult to mock user auth level. + t.skip("Should cap a user at OAUTH_CLIENT_CAP.", async (t) => { + for (let i = 0; i < ServerConfig.OAUTH_CLIENT_CAP; i++) { + // eslint-disable-next-line no-await-in-loop + await mockApi + .post("/api/v1/clients/create") + .send({ + name: "Hello World", + redirectUri: "https://example.com/callback", + permissions: ["customise_profile"], + webhookUri: null, + apiKeyTemplate: null, + apiKeyFilename: null, + }) + .set("Cookie", cookie); + } + + const res = await mockApi + .post("/api/v1/clients/create") + .send({ + name: "Hello World", + redirectUri: "https://example.com/callback", + permissions: ["customise_profile"], + webhookUri: null, + apiKeyTemplate: null, + apiKeyFilename: null, + }) + .set("Cookie", cookie); + + t.equal(res.statusCode, 400); + + const dbCount = await db["api-clients"].count({ author: 1 }); + + t.equal(dbCount, ServerConfig.OAUTH_CLIENT_CAP); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/clients/:clientID", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return information about the client at that ID.", async (t) => { + const res = await mockApi.get("/api/v1/clients/OAUTH2_CLIENT_ID"); + + t.strictSame(res.body.body, { + clientID: "OAUTH2_CLIENT_ID", + + // clientSecret: "OAUTH2_CLIENT_SECRET", MUST NOT have secret! + name: "Test_Service", + author: 1, + requestedPermissions: ["customise_profile"], + redirectUri: "https://example.com/callback", + webhookUri: null, + apiKeyTemplate: null, + apiKeyFilename: null, + }); + + t.end(); + }); + + t.test("Should return 404 if client doesn't exist.", async (t) => { + const res = await mockApi.get("/api/v1/clients/BAD_CLIENT"); + + t.equal(res.statusCode, 404); + + t.end(); + }); + + t.end(); +}); + +t.test("PATCH /api/v1/clients/:clientID", async (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(async () => { + await db["api-clients"].remove({}); + await db["api-clients"].insert(clientDataset); + }); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should be able to modify a clients name.", async (t) => { + const res = await mockApi + .patch("/api/v1/clients/CLIENT_1") + .send({ name: "NEW NAME" }) + .set("Cookie", cookie); + + t.equal(res.statusCode, 200); + + t.equal(res.body.body.name, "NEW NAME"); + + const dbRes = await db["api-clients"].findOne({ + clientID: "CLIENT_1", + }); + + t.equal(dbRes?.name, "NEW NAME"); + + t.end(); + }); + + t.test("Should be able to modify a clients webhookUri.", async (t) => { + const res = await mockApi + .patch("/api/v1/clients/CLIENT_1") + .send({ webhookUri: "https://example.com" }) + .set("Cookie", cookie); + + t.equal(res.statusCode, 200); + + t.equal(res.body.body.webhookUri, "https://example.com"); + + const dbRes = await db["api-clients"].findOne({ + clientID: "CLIENT_1", + }); + + t.equal(dbRes?.webhookUri, "https://example.com"); + + t.end(); + }); + + t.test("Must validate name to be between 3 and 80 characters.", async (t) => { + const res = await mockApi + .patch("/api/v1/clients/CLIENT_1") + .send({ name: "2" }) + .set("Cookie", cookie); + + t.equal(res.statusCode, 400); + + const res2 = await mockApi + .patch("/api/v1/clients/CLIENT_1") + .send({ name: "2".repeat(100) }) + .set("Cookie", cookie); + + t.equal(res2.statusCode, 400); + + t.end(); + }); + + t.test("Must provide name to modify.", async (t) => { + const res = await mockApi.patch("/api/v1/clients/CLIENT_1").send({}).set("Cookie", cookie); + + t.equal(res.statusCode, 400); + + t.end(); + }); + + t.test("Must be owner of client.", async (t) => { + const res = await mockApi + .patch("/api/v1/clients/CLIENT_3") + .send({ name: "foo" }) + .set("Cookie", cookie); + + t.equal(res.statusCode, 403); + + const res2 = await mockApi.patch("/api/v1/clients/CLIENT_3").send({ name: "foo" }); + + t.equal(res2.statusCode, 401); + + t.end(); + }); + + t.end(); +}); + +t.test("POST /api/v1/clients/:clientID/reset-secret", async (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(async () => { + await db["api-clients"].remove({}); + await db["api-clients"].insert(clientDataset); + }); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should reset the client's secret.", async (t) => { + const res = await mockApi + .post("/api/v1/clients/CLIENT_1/reset-secret") + .set("Cookie", cookie); + + t.equal(res.statusCode, 200); + + t.not(res.body.body.clientSecret, "SECRET_1", "Should return the new secret."); + + const dbRes = await db["api-clients"].findOne({ + clientID: "CLIENT_1", + }); + + t.not(dbRes?.clientSecret, "SECRET_1", "Should change secret to anything else."); + + t.end(); + }); + + t.test("Must be owner of client.", async (t) => { + const res = await mockApi + .post("/api/v1/clients/CLIENT_3/reset-secret") + .set("Cookie", cookie); + + t.equal(res.statusCode, 403); + + const res2 = await mockApi.post("/api/v1/clients/CLIENT_3/reset-secret"); + + t.equal(res2.statusCode, 401); + + t.end(); + }); + + t.end(); +}); + +t.test("DELETE /api/v1/clients/:clientID", async (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(async () => { + await db["api-clients"].remove({}); + await db["api-clients"].insert(clientDataset); + }); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should destroy the client and all associated api keys.", async (t) => { + await db["api-tokens"].insert([ + { + fromAPIClient: "CLIENT_1", + token: "foo", + userID: 1, + }, + { + fromAPIClient: "CLIENT_1", + token: "bar", + userID: 1, + }, + ] as Array); + + const res = await mockApi.delete("/api/v1/clients/CLIENT_1").set("Cookie", cookie); + + t.equal(res.statusCode, 200); + + const dbRes = await db["api-clients"].findOne({ clientID: "CLIENT_1" }); + + t.equal(dbRes, null, "Should no longer exist."); + + const dbCount = await db["api-tokens"].count({ fromOAuth2Client: "CLIENT_1" }); + + t.equal(dbCount, 0, "Should have destroyed all related api tokens."); + + t.end(); + }); + + t.test("Must be owner of client.", async (t) => { + const res = await mockApi.delete("/api/v1/clients/CLIENT_3").set("Cookie", cookie); + + t.equal(res.statusCode, 403); + + const res2 = await mockApi.delete("/api/v1/clients/CLIENT_3"); + + t.equal(res2.statusCode, 401); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/clients/router.ts b/typescript/server/src/server/router/api/v1postgres/clients/router.ts new file mode 100644 index 000000000..6baea9023 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/clients/router.ts @@ -0,0 +1,356 @@ +import { log } from "#lib/log/log.js"; +import { ServerConfig } from "#lib/setup/config"; +import prValidate from "#server/middleware/prudence-validate"; +import db from "#services/mongo/db"; +import { DedupeArr, DeleteUndefinedProps, IsValidURL, Random20Hex } from "#utils/misc"; +import { optNull } from "#utils/prudence"; +import { GetTachiData } from "#utils/req-tachi-data"; +import { FormatUserDoc } from "#utils/user"; +import { Router } from "express"; +import { p } from "prudence"; +import { + ALL_PERMISSIONS, + type APIPermissions, + type TachiAPIClientDocument, + UserAuthLevels, +} from "tachi-common"; + +import { GetClientFromID, RequireOwnershipOfClient } from "./middleware"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Retrieve the clients you created. Must be performed with a session-level request. + * + * @warn This also returns the client_secrets! Those *have* to be kept secret. + * + * @name GET /api/v1/clients + */ +router.get("/", async (req, res) => { + const user = req.session.tachi?.user; + + if (!user) { + return res.status(401).json({ + success: false, + description: `You are not authenticated (for a session-level request, atleast).`, + }); + } + + const clients = await db["api-clients"].find({ + author: user.id, + }); + + return res.status(200).json({ + success: true, + description: `Returned ${clients.length} clients.`, + body: clients, + }); +}); + +/** + * Create a new API Client. Requires session-level auth. + * + * @param name - A string that identifies this client. + * @param redirectUri - The redirectUri this client uses. + * @param webhookUri - Optionally, a webhookUri to call with webhook events. + * @param apiKeyTemplate - Optionally, a static format to apply when doing static auth. + * @param apiKeyFilename - Optionally, a filename to automatically download the template to, when doing + * static flow. + * @param permissions - An array of APIPermissions this client is expected to use. + * + * @name POST /api/v1/clients/create + */ +router.post( + "/create", + prValidate({ + name: p.isBoundedString(3, 80), + redirectUri: "?string", + webhookUri: "?string", + apiKeyTemplate: (self) => { + if (self === null) { + return true; + } + + if (typeof self !== "string") { + return "Expected a string."; + } + + if (!self.includes("%%TACHI_KEY%%")) { + return "Must contain %%TACHI_KEY%% as part of the template."; + } + + return true; + }, + apiKeyFilename: "?string", + permissions: [p.isIn(Object.keys(ALL_PERMISSIONS))], + }), + async (req, res) => { + if (!req.session.tachi?.user) { + return res.status(401).json({ + success: false, + description: `You are not authenticated.`, + }); + } + + const body = req.safeBody as { + apiKeyFilename: string | null; + apiKeyTemplate: string | null; + name: string; + permissions: Array; + redirectUri: string | null; + webhookUri: string | null; + }; + + const existingClients = await db["api-clients"].find({ + author: req.session.tachi.user.id, + }); + + // Note: Admins are excluded from the API client cap. + if ( + req.session.tachi.user.authLevel !== UserAuthLevels.ADMIN && + existingClients.length >= ServerConfig.OAUTH_CLIENT_CAP + ) { + return res.status(400).json({ + success: false, + description: `You have created too many API clients. The current cap is ${ServerConfig.OAUTH_CLIENT_CAP}.`, + }); + } + + const permissions = DedupeArr(body.permissions); + + if (permissions.length === 0) { + return res.status(400).json({ + success: false, + description: `Invalid permissions -- Need to require atleast one.`, + }); + } + + if (body.redirectUri !== null && !IsValidURL(body.redirectUri)) { + return res.status(400).json({ + success: false, + description: `Invalid Redirect URL.`, + }); + } + + if (body.webhookUri !== null && !IsValidURL(body.webhookUri)) { + return res.status(400).json({ + success: false, + description: `Invalid Webhook URL.`, + }); + } + + const clientID = `CI${Random20Hex()}`; + const clientSecret = `CS${Random20Hex()}`; + + const clientDoc: TachiAPIClientDocument = { + clientID, + clientSecret, + requestedPermissions: permissions, + name: body.name, + author: req.session.tachi.user.id, + redirectUri: body.redirectUri, + webhookUri: body.webhookUri ?? null, + apiKeyFilename: body.apiKeyFilename ?? null, + apiKeyTemplate: body.apiKeyTemplate ?? null, + }; + + await db["api-clients"].insert(clientDoc); + + log.info( + `User ${FormatUserDoc(req.session.tachi.user)} created a new API Client ${ + body.name + } (${clientID}).`, + ); + + return res.status(200).json({ + success: true, + description: `Created a new API client.`, + body: clientDoc, + }); + }, +); + +/** + * Retrieves information about the client at this ID. + * + * @name GET /api/v1/clients/:clientID + */ +router.get("/:clientID", GetClientFromID, (req, res) => { + const client = GetTachiData(req, "apiClientDoc"); + + return res.status(200).json({ + success: true, + description: `Retrieved client ${client.name}.`, + body: client, + }); +}); + +/** + * Update an existing client. The requester must be the owner of this + * client, and must also be making a session-level request. + * + * @param name - Change the name of this client. + * @param webhookUri - Change a bound webhookUri for this client. + * @param redirectUri - Change a bound redirectUri for this client. + * @param apiKeyFormat - Change the APIKeyFormat for this client. + * @param apiKeyFilename - Change the APIKeyFilename for this client. + * + * @name PATCH /api/v1/clients/:clientID + */ +router.patch( + "/:clientID", + GetClientFromID, + RequireOwnershipOfClient, + prValidate({ + name: p.optional(p.isBoundedString(3, 80)), + apiKeyTemplate: optNull((self) => { + if (typeof self !== "string") { + return "Expected a string."; + } + + if (!self.includes("%%TACHI_KEY%%")) { + return "Must contain a %%TACHI_KEY%% placeholder."; + } + + return true; + }), + apiKeyFilename: optNull(p.isBoundedString(3, 80)), + webhookUri: optNull((self) => { + if (typeof self !== "string") { + return "Expected a string."; + } + + const res = IsValidURL(self); + + if (!res) { + return "Invalid URL."; + } + + return true; + }), + redirectUri: optNull((self) => { + if (typeof self !== "string") { + return "Expected a string."; + } + + const res = IsValidURL(self); + + if (!res) { + return "Invalid URL."; + } + + return true; + }), + }), + async (req, res) => { + const body = req.safeBody as { + apiKeyFilename?: string | null; + apiKeyTemplate?: string | null; + name?: string; + permissions?: Array; + redirectUri?: string | null; + webhookUri?: string | null; + }; + + const client = GetTachiData(req, "apiClientDoc"); + + DeleteUndefinedProps(req.safeBody); + + if (Object.keys(req.safeBody).length === 0) { + return res.status(400).json({ + success: false, + description: `No changes to make.`, + }); + } + + const newClient = await db["api-clients"].findOneAndUpdate( + { + clientID: client.clientID, + }, + { + $set: req.safeBody, + }, + ); + + log.info( + `API Client ${client.name} (${client.clientID}) has been renamed to ${body.name}.`, + ); + + return res.status(200).json({ + success: true, + description: `Updated client.`, + body: newClient, + }); + }, +); + +/** + * Resets the clientSecret for this client. + * This will NOT invalidate any existing tokens, as per oauth2 spec. + * + * @name POST /api/v1/clients/:clientID/reset-secret + */ +router.post( + "/:clientID/reset-secret", + GetClientFromID, + RequireOwnershipOfClient, + async (req, res) => { + const client = GetTachiData(req, "apiClientDoc"); + const clientName = `${client.name} (${client.clientID})`; + + log.info(`received request to reset client secret for ${clientName}`); + + const newSecret = Random20Hex(); + + const newClient = await db["api-clients"].findOneAndUpdate( + { + clientID: client.clientID, + }, + { + $set: { clientSecret: newSecret }, + }, + ); + + log.info(`Reset secret for ${clientName}.`); + + return res.status(200).json({ + success: true, + description: `Reset secret.`, + body: newClient, + }); + }, +); + +/** + * Delete this client. Must be authorized at a session-request level. + * + * @name DELETE /api/v1/clients/:clientID + */ +router.delete("/:clientID", GetClientFromID, RequireOwnershipOfClient, async (req, res) => { + const client = GetTachiData(req, "apiClientDoc"); + + const clientName = `${client.name} (${client.clientID})`; + + log.info(`received request to destroy API Client ${client.name} (${client.clientID})`); + + log.debug(`Removing API Client ${clientName}.`); + await db["api-clients"].remove({ + clientID: client.clientID, + }); + log.info(`Removed API Client ${clientName}.`); + + log.debug(`Removing all associated api tokens.`); + const result = await db["api-tokens"].remove({ + fromOAuth2Client: client.clientID, + }); + + log.info(`Removed ${result.deletedCount} api tokens from ${clientName}.`); + + return res.status(200).json({ + success: true, + description: `Deleted ${clientName}.`, + body: {}, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/config/router.test.ts b/typescript/server/src/server/router/api/v1postgres/config/router.test.ts new file mode 100644 index 000000000..69978af64 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/config/router.test.ts @@ -0,0 +1,31 @@ +import { ServerConfig, TachiConfig } from "#lib/setup/config"; +import mockApi from "#test-utils/mock-api"; +import t from "tap"; + +t.test("GET /api/v1/config", async (t) => { + const res = await mockApi.get("/api/v1/config"); + + t.strictSame(res.body.body, TachiConfig, "Should return TachiConfig info"); + + t.end(); +}); + +t.test("GET /api/v1/config/beatoraja-queue-size", async (t) => { + const res = await mockApi.get("/api/v1/config/beatoraja-queue-size"); + + t.equal( + res.body.body, + ServerConfig.BEATORAJA_QUEUE_SIZE, + "Should return integer equal to BEATORAJA_QUEUE_SIZE.", + ); + + t.end(); +}); + +t.test("GET /api/v1/config/max-rivals", async (t) => { + const res = await mockApi.get("/api/v1/config/max-rivals"); + + t.equal(res.body.body, ServerConfig.MAX_RIVALS, "Should return integer equal to MAX_RIVALS."); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/config/router.ts b/typescript/server/src/server/router/api/v1postgres/config/router.ts new file mode 100644 index 000000000..5d4aa9d8e --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/config/router.ts @@ -0,0 +1,47 @@ +import { ServerConfig, TachiConfig } from "#lib/setup/config"; +import { RequireBokutachi } from "#server/middleware/type-require"; +import { Router } from "express"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Returns Tachi Configuration info, such as server name, type, supported games + * and more. + * + * @name GET /api/v1/config + */ +router.get("/", (req, res) => + res.status(200).json({ + success: true, + description: `Returned configuration info.`, + body: TachiConfig, + }), +); + +/** + * Returns the value of the BEATORAJA_QUEUE_SIZE. + * + * @name GET /api/v1/config/beatoraja-queue-size + */ +router.get("/beatoraja-queue-size", RequireBokutachi, (req, res) => + res.status(200).json({ + success: true, + description: `Returned BEATORAJA_QUEUE_SIZE.`, + body: ServerConfig.BEATORAJA_QUEUE_SIZE, + }), +); + +/** + * Returns the maximum amount of rivals a user can have on this instance. + * + * @name GET /api/v1/config/max-rivals + */ +router.get("/max-rivals", (req, res) => + res.status(200).json({ + success: true, + description: `Returned MAX_RIVALS.`, + body: ServerConfig.MAX_RIVALS, + }), +); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/games/@gameSpecificRoutes/bms/router.test.ts b/typescript/server/src/server/router/api/v1postgres/games/@gameSpecificRoutes/bms/router.test.ts new file mode 100644 index 000000000..06f7f4403 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/@gameSpecificRoutes/bms/router.test.ts @@ -0,0 +1,88 @@ +import { ServerConfig } from "#lib/setup/config"; +import db from "#services/mongo/db"; +import mockApi from "#test-utils/mock-api"; +import t from "tap"; + +t.test("GET /api/v1/games/bms/:playtype/custom-tables/:tableUrlName", async (t) => { + await db.tables.insert({ + default: false, + description: "EC difficulties according to Sieglinde.", + + // stubbed folders + folders: ["sieglinde_folder"], + game: "bms", + inactive: false, + playtype: "7K", + tableID: "bms-7K-sgl-EC", + title: "Sieglinde EC", + }); + + await db.folders.insert({ + folderID: "sieglinde_folder", + game: "bms", + playtype: "7K", + inactive: false, + searchTerms: [], + title: "Mock Sieglinde Folder", + + // this table contains all charts. silly mock. + data: {}, + type: "charts", + }); + + t.test("html compatibility return should point to the right file", async (t) => { + const res = await mockApi.get("/api/v1/games/bms/7K/custom-tables/sieglindeEC"); + + const content = //u.exec(res.text); + + if (content) { + const maybeMatch = content[1]; + + t.equal( + maybeMatch, + `${ServerConfig.OUR_URL}/api/v1/games/bms/7K/custom-tables/sieglindeEC/header.json`, + ); + } else { + t.fail(`Didn't match regexp for having a bmstable header?`); + } + + t.end(); + }); + + t.test("Should point to the right file.", async (t) => { + const res = await mockApi.get("/api/v1/games/bms/7K/custom-tables/sieglindeEC/header.json"); + + t.equal( + res.body.data_url, + `${ServerConfig.OUR_URL}/api/v1/games/bms/7K/custom-tables/sieglindeEC/body.json`, + ); + + t.end(); + }); + + t.test("`body.json` should return an array.", async (t) => { + const res = await mockApi.get("/api/v1/games/bms/7K/custom-tables/sieglindeEC/body.json"); + + t.equal(Array.isArray(res.body), true); + + t.end(); + }); + + t.test("Invalid Table", async (t) => { + const res = await mockApi.get("/api/v1/games/bms/7K/custom-tables/fake-table"); + + t.equal(res.statusCode, 404); + + t.end(); + }); + + t.test("Invalid Playtype", async (t) => { + const res = await mockApi.get("/api/v1/games/bms/14K/custom-tables/sieglindeEC"); + + t.equal(res.statusCode, 404); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/games/@gameSpecificRoutes/bms/router.ts b/typescript/server/src/server/router/api/v1postgres/games/@gameSpecificRoutes/bms/router.ts new file mode 100644 index 000000000..450a30175 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/@gameSpecificRoutes/bms/router.ts @@ -0,0 +1,158 @@ +import type { Playtypes } from "tachi-common"; + +import { + CUSTOM_TACHI_BMS_TABLES, + HandleBMSTableBodyRequest, + HandleBMSTableHeaderRequest, + HandleBMSTableHTMLRequest, + type TachiBMSTable, +} from "#lib/game-specific/custom-bms-tables"; +import db from "#services/mongo/db"; +import { AssignToReqTachiData, GetTachiData } from "#utils/req-tachi-data"; +import { type RequestHandler, Router } from "express"; + +import { ValidatePlaytypeFromParamFor } from "../../_game/_playtype/middleware"; + +const router: Router = Router({ mergeParams: true }); + +const FindCustomBMSTable: RequestHandler = (req, res, next) => { + const { playtype, tableUrlName } = req.params; + + // find the table + const customTable = CUSTOM_TACHI_BMS_TABLES.find((t) => t.urlName === tableUrlName); + + if (!customTable) { + return res.status(404).json({ + success: false, + description: `No such table with the ID '${tableUrlName}' exists.`, + }); + } + + if (customTable.playtype && customTable.playtype !== playtype) { + return res.status(404).json({ + success: false, + description: `The table '${tableUrlName}' exists, but is for ${customTable.playtype}, not ${playtype}.`, + }); + } + + if (customTable.forSpecificUser === true) { + return res.status(404).json({ + success: false, + description: `The table '${tableUrlName}' exists, but is user-specific. You should be fetching this table from /api/v1/users/:userID instead of /api/v1/games.`, + }); + } + + AssignToReqTachiData(req, { customBMSTable: customTable }); + + next(); +}; + +/** + * List all custom BMS tables this instance of Tachi is emitting. + * + * @name GET /api/v1/games/bms/:playtype/custom-tables + */ +router.get("/:playtype/custom-tables", ValidatePlaytypeFromParamFor("bms"), (req, res) => { + const tables: Array< + Pick + > = []; + + for (const table of CUSTOM_TACHI_BMS_TABLES.filter( + (e) => e.playtype === req.params.playtype || e.playtype === null, + )) { + tables.push({ + forSpecificUser: table.forSpecificUser, + urlName: table.urlName, + tableName: table.tableName, + symbol: table.symbol, + description: table.description, + }); + } + + return res.status(200).json({ + success: true, + description: `Found ${tables.length} custom table(s).`, + body: tables, + }); +}); + +/** + * Return some HTML for this custom table. + * + * @note Since this is the GPT route, trying to fetch user specific custom tables + * will result in a 404. This applies for all subsequent :tableUrlName routes. + * + * @name GET /api/v1/games/bms/:playtype/custom-tables/:tableUrlName + */ +router.get( + "/:playtype/custom-tables/:tableUrlName", + ValidatePlaytypeFromParamFor("bms"), + FindCustomBMSTable, + (req, res) => { + const customTable = GetTachiData(req, "customBMSTable"); + + // This handles returning a response for us. + return HandleBMSTableHTMLRequest(customTable, req, res); + }, +); + +/** + * Return the header.json for this custom table. + * + * @name GET /api/v1/games/bms/:playtype/custom-tables/:tableUrlName/header.json + */ +router.get( + "/:playtype/custom-tables/:tableUrlName/header.json", + ValidatePlaytypeFromParamFor("bms"), + FindCustomBMSTable, + (req, res) => { + const customTable = GetTachiData(req, "customBMSTable"); + + // This handles returning a response for us. + return HandleBMSTableHeaderRequest(customTable, req, res); + }, +); + +/** + * Return the body.json for this custom table. + * + * @name GET /api/v1/games/bms/:playtype/custom-tables/:tableUrlName/body.json + */ +router.get( + "/:playtype/custom-tables/:tableUrlName/body.json", + ValidatePlaytypeFromParamFor("bms"), + FindCustomBMSTable, + (req, res) => { + const customTable = GetTachiData(req, "customBMSTable"); + + // This handles returning a response for us. + return HandleBMSTableBodyRequest(customTable, req, res); + }, +); + +/** + * Return *all* the charts that have defined sieglinde values for this game. + * + * @name GET /api/v1/games/bms/:playtype/sieglinde-charts + */ +router.get("/:playtype/sieglinde-charts", ValidatePlaytypeFromParamFor("bms"), async (req, res) => { + const playtype = req.params.playtype as Playtypes["bms"]; + + const charts = await db.charts.bms.find({ + playtype, + $or: [{ "data.sglEC": { $gt: 0 } }, { "data.sglHC": { $gt: 0 } }], + }); + + const songs = await db.songs.bms.find({ id: { $in: charts.map((e) => e.songID) } }); + + return res.status(200).json({ + success: true, + description: `Found ${charts.length} chart(s).`, + body: { + songs, + charts, + }, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/games/@gameSpecificRoutes/iidx/router.ts b/typescript/server/src/server/router/api/v1postgres/games/@gameSpecificRoutes/iidx/router.ts new file mode 100644 index 000000000..655b92a25 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/@gameSpecificRoutes/iidx/router.ts @@ -0,0 +1,74 @@ +import { + CUSTOM_TACHI_IIDX_PLAYLISTS, + type TachiIIDXPlaylist, +} from "#lib/game-specific/iidx-playlists"; +import { Router } from "express"; + +import { ValidatePlaytypeFromParamFor } from "../../_game/_playtype/middleware"; + +const router: Router = Router({ mergeParams: true }); + +/** + * List all the playlists we have available. + * + * @name GET /api/v1/games/iidx/:playtype/playlists + */ +router.get("/:playtype/playlists", ValidatePlaytypeFromParamFor("iidx"), (req, res) => { + const playlists = CUSTOM_TACHI_IIDX_PLAYLISTS.filter( + (e) => e.playtype === null || e.playtype === req.params.playtype, + ); + + const body = []; + + for (const playlist of playlists) { + body.push({ + forSpecificUser: playlist.forSpecificUser, + urlName: playlist.urlName, + playlistName: playlist.playlistName, + description: playlist.description, + }); + } + + return res.status(200).json({ + success: true, + description: `Found ${playlists.length} playlist(s)`, + body: playlists, + }); +}); + +/** + * Retrieve this playlist. + * + * @name GET /api/v1/games/iidx/:playtype/playlists/:playlistID + */ +router.get( + "/:playtype/playlists/:playlistID", + ValidatePlaytypeFromParamFor("iidx"), + async (req, res) => { + const playlist: TachiIIDXPlaylist | undefined = CUSTOM_TACHI_IIDX_PLAYLISTS.find( + (e) => + (e.playtype === null || e.playtype === req.params.playtype) && + e.urlName === req.params.playlistID, + ); + + if (!playlist) { + return res.status(404).json({ + success: false, + description: `No such playlist '${req.params.playlistID}' exists for '${req.params.playtype}'.`, + }); + } + + if (playlist.forSpecificUser === true) { + return res.status(404).json({ + success: false, + description: `This playlist is for a specific user. Use the /users/:userID endpoint instead.`, + }); + } + + const body = await playlist.getPlaylists(req.params.playtype as "DP" | "SP"); + + return res.status(200).json(body); + }, +); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/games/@gameSpecificRoutes/router.ts b/typescript/server/src/server/router/api/v1postgres/games/@gameSpecificRoutes/router.ts new file mode 100644 index 000000000..04783afdf --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/@gameSpecificRoutes/router.ts @@ -0,0 +1,14 @@ +// This file is special. These routes are "gptSpecific". They only apply to certain games +// and playtypes. This is for things like - say - custom BMS tables. + +import { Router } from "express"; + +import bmsRouter from "./bms/router"; +import iidxRouter from "./iidx/router"; + +const router: Router = Router({ mergeParams: true }); + +router.use("/bms", bmsRouter); +router.use("/iidx", iidxRouter); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/charts/_chartID/middleware.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/charts/_chartID/middleware.ts new file mode 100644 index 000000000..f51db76e0 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/charts/_chartID/middleware.ts @@ -0,0 +1,28 @@ +import type { RequestHandler } from "express"; + +import db from "#services/mongo/db"; +import { AssignToReqTachiData, GetGPT } from "#utils/req-tachi-data"; + +export const ValidateAndGetChart: RequestHandler = async (req, res, next) => { + const { game, playtype } = GetGPT(req); + + const chart = await db.anyCharts[game].findOne({ + chartID: req.params.chartID, + + // technically redundant, but we're under playtypes here URL wise. + // this means we cant match an SP chart when we're under IIDX SP, for + // example. + playtype, + }); + + if (!chart) { + return res.status(404).json({ + success: false, + description: `The chart ${req.params.chartID} does not exist.`, + }); + } + + AssignToReqTachiData(req, { chartDoc: chart }); + + next(); +}; diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/charts/_chartID/router.test.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/charts/_chartID/router.test.ts new file mode 100644 index 000000000..8d591af51 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/charts/_chartID/router.test.ts @@ -0,0 +1,98 @@ +import type { PBScoreDocument, UserDocument } from "tachi-common"; + +import db from "#services/mongo/db"; +import { dmf } from "#test-utils/misc.js"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { Testing511SPA, TestingIIDXSPScorePB } from "#test-utils/test-data"; +import t from "tap"; + +t.test("GET /api/v1/games/:game/:playtype/charts/:chartID", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return the chart at this ID", async (t) => { + const res = await mockApi.get(`/api/v1/games/iidx/SP/charts/${Testing511SPA.chartID}`); + + t.hasStrict(res.body.body, { + song: { + id: 1, + }, + chart: { + chartID: Testing511SPA.chartID, + }, + }); + t.end(); + }); + + t.test("Should return 404 if the chart doesnt exist", async (t) => { + const res = await mockApi.get(`/api/v1/games/iidx/SP/charts/FAKECHART`); + + t.equal(res.statusCode, 404); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/games/:game/:playtype/charts/:chartID/pbs", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return the best PBs on that chart.", async (t) => { + await db["personal-bests"].insert([ + TestingIIDXSPScorePB, + dmf(TestingIIDXSPScorePB, { + userID: 2, + rankingData: { rank: 2 }, + scoreData: { score: 123 }, + }), + dmf(TestingIIDXSPScorePB, { + chartID: "other_chart", + }) as PBScoreDocument, + ]); + + await db.users.insert({ + id: 2, + username: "foo", + usernameLowercase: "foo", + } as UserDocument); + + const res = await mockApi.get(`/api/v1/games/iidx/SP/charts/${Testing511SPA.chartID}/pbs`); + + t.equal(res.body.body.pbs.length, 2); + t.equal(res.body.body.users.length, 2); + + t.strictSame( + res.body.body.pbs.map((e: PBScoreDocument) => e.chartID), + [Testing511SPA.chartID, Testing511SPA.chartID], + ); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/games/:game/:playtype/charts/:chartID/playcount", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return the total playcount on this chart.", async (t) => { + const pbs: Array = []; + + for (let i = 1; i <= 132; i++) { + pbs.push(dmf(TestingIIDXSPScorePB, { userID: i }) as PBScoreDocument); + } + + await db["personal-bests"].insert(pbs); + + const res = await mockApi.get( + `/api/v1/games/iidx/SP/charts/${Testing511SPA.chartID}/playcount`, + ); + + t.equal(res.body.body.count, 132); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/charts/_chartID/router.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/charts/_chartID/router.ts new file mode 100644 index 000000000..1ca909242 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/charts/_chartID/router.ts @@ -0,0 +1,182 @@ +import type { FilterQuery } from "mongodb"; + +import { log } from "#lib/log/log.js"; +import { SearchUsersRegExp } from "#lib/search/search"; +import db from "#services/mongo/db"; +import { IsString } from "#utils/misc"; +import { GetTachiData } from "#utils/req-tachi-data"; +import { ParseStrPositiveNonZeroInt } from "#utils/string-checks"; +import { GetUsersWithIDs } from "#utils/user"; +import { Router } from "express"; +import { type FolderDocument, FormatChart } from "tachi-common"; + +import { ValidateAndGetChart } from "./middleware"; + +const router: Router = Router({ mergeParams: true }); + +router.use(ValidateAndGetChart); + +/** + * Returns the chart (and the parent song) at this chart ID. + * + * @name GET /api/v1/games/:game/:playtype/charts/:chartID + */ +router.get("/", async (req, res) => { + const chart = GetTachiData(req, "chartDoc"); + const game = GetTachiData(req, "game"); + + const song = await db.anySongs[game].findOne({ + id: chart.songID, + }); + + if (!song) { + log.error( + `Song ${chart.songID} does not exist, yet chart ${chart.chartID} has it as a parent?`, + ); + + return res.status(500).json({ + success: false, + description: `An internal server error has occured.`, + }); + } + + return res.status(200).json({ + success: true, + description: `Returned ${FormatChart(game, song, chart)}.`, + body: { + song, + chart, + }, + }); +}); + +/** + * Returns any folders that contain this chart. + * + * @param inactive - Also include inactive folders. + * + * @name GET /api/v1/games/:game/:playtype/charts/:chartID/folders + */ +router.get("/folders", async (req, res) => { + const chart = GetTachiData(req, "chartDoc"); + + const folderIDs = await db["folder-chart-lookup"].find( + { + chartID: chart.chartID, + }, + { + projection: { + folderID: 1, + }, + }, + ); + + const query: FilterQuery = { + folderID: { $in: folderIDs.map((e) => e.folderID) }, + }; + + if (req.query.inactive === undefined) { + query.inactive = false; + } + + const folders = await db.folders.find(query); + + return res.status(200).json({ + success: true, + description: `Found ${folders.length} folders that contain this chart.`, + body: folders, + }); +}); + +/** + * Returns the total amount of unique players that have played this chart. + * + * @name GET /api/v1/games/:game/:playtype/charts/:chartID/playcount + */ +router.get("/playcount", async (req, res) => { + const chart = GetTachiData(req, "chartDoc"); + + const count = await db["personal-bests"].count({ chartID: chart.chartID }); + + return res.status(200).json({ + success: true, + description: `Counted scores for chart.`, + body: { + count, + }, + }); +}); + +/** + * Returns the personal bests for this chart in batches of 100. + * These are returned sorted by their ranking. + * + * @param startRanking - The ranking to start iterating from - defaults to 1. + * + * @name GET /api/v1/games/:game/:playtype/charts/:chartID/pbs + */ +router.get("/pbs", async (req, res) => { + const chart = GetTachiData(req, "chartDoc"); + + const startRanking = ParseStrPositiveNonZeroInt(req.query.startRanking) ?? 1; + + const pbs = await db["personal-bests"].find( + { + chartID: chart.chartID, + "rankingData.rank": { $gte: startRanking }, + }, + { + limit: 100, + sort: { + "rankingData.rank": 1, + }, + }, + ); + + const users = await GetUsersWithIDs(pbs.map((e) => e.userID)); + + return res.status(200).json({ + success: true, + description: `Returned ${pbs.length} scores.`, + body: { + pbs, + users, + }, + }); +}); + +/** + * Searches the PBs on this chart for the given user(s). + * + * @param search - The user to search for + * + * @name GET /api/v1/games/:game/:playtype/charts/:chartID/pbs/search + */ +router.get("/pbs/search", async (req, res) => { + const chart = GetTachiData(req, "chartDoc"); + + if (!IsString(req.query.search)) { + return res.status(400).json({ + success: false, + description: `Invalid parameter for search.`, + }); + } + + const users = await SearchUsersRegExp(req.query.search); + + const pbs = await db["personal-bests"].find({ + chartID: chart.chartID, + userID: { $in: users.map((e) => e.id) }, + }); + + return res.status(200).json({ + success: true, + description: `Returned ${pbs.length} scores.`, + body: { + pbs, + users, + }, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/charts/router.test.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/charts/router.test.ts new file mode 100644 index 000000000..291187b2d --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/charts/router.test.ts @@ -0,0 +1,220 @@ +import db from "#services/mongo/db"; +import { mkFakePBIIDXSP } from "#test-utils/misc"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { LoadTachiIIDXData, Testing511SPA } from "#test-utils/test-data"; +import t from "tap"; + +t.test("GET /api/v1/games/:game/:playtype/charts", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(LoadTachiIIDXData); + + t.test("Should return the most popular charts if no param is set.", async (t) => { + await db["personal-bests"].insert([ + mkFakePBIIDXSP({ + chartID: Testing511SPA.chartID, + userID: 1, + }), + mkFakePBIIDXSP({ + chartID: Testing511SPA.chartID, + userID: 2, + }), + mkFakePBIIDXSP({ + chartID: Testing511SPA.chartID, + userID: 3, + }), + mkFakePBIIDXSP({ + // gambol hyper + songID: 7, + chartID: "fc7edc6bcfa701a261c89c999ddbba3e2195597b", + userID: 1, + }), + ]); + + const res = await mockApi.get("/api/v1/games/iidx/SP/charts"); + + t.hasStrict(res.body.body.charts[0], { + __playcount: 3, + chartID: Testing511SPA.chartID, + }); + + t.hasStrict(res.body.body.charts[1], { + __playcount: 1, + chartID: "fc7edc6bcfa701a261c89c999ddbba3e2195597b", + }); + + t.equal(res.body.body.charts.length, 100); + + t.end(); + }); + + t.test("Should search charts if a search param is set.", async (t) => { + await db["personal-bests"].insert([ + mkFakePBIIDXSP({ + // gambol hyper + songID: 7, + chartID: "fc7edc6bcfa701a261c89c999ddbba3e2195597b", + userID: 1, + }), + ]); + + const res = await mockApi.get("/api/v1/games/iidx/SP/charts?search=gambol"); + + t.hasStrict(res.body.body.charts[0], { + __playcount: 1, + chartID: "fc7edc6bcfa701a261c89c999ddbba3e2195597b", + }); + + // gambol has SPB, SPN and SPH + t.equal(res.body.body.charts.length, 3); + + t.end(); + }); + + t.test( + "Should only return charts the requester has played if requesterHasPlayed is set.", + async (t) => { + await db["personal-bests"].insert([ + mkFakePBIIDXSP({ + // gambol hyper + songID: 7, + chartID: "fc7edc6bcfa701a261c89c999ddbba3e2195597b", + userID: 2, + }), + mkFakePBIIDXSP({ + songID: 1, + chartID: Testing511SPA.chartID, + userID: 1, + }), + ]); + + const res = await mockApi + .get("/api/v1/games/iidx/SP/charts?requesterHasPlayed=true") + .set("Authorization", "Bearer fake_api_token"); + + t.hasStrict(res.body.body.charts[0], { + __playcount: 1, + chartID: Testing511SPA.chartID, + }); + + // The user has played 5.1.1., but not anything else loaded in the db. + // note that this endpoint works on played songs, rather than played charts. + t.equal(res.body.body.charts.length, 4); + + t.end(); + }, + ); + + t.test( + "Should only return charts the requester has played if requesterHasPlayed is set, and work with searches at the same time.", + async (t) => { + await db["personal-bests"].insert([ + mkFakePBIIDXSP({ + // gambol hyper + songID: 7, + chartID: "fc7edc6bcfa701a261c89c999ddbba3e2195597b", + userID: 1, + }), + mkFakePBIIDXSP({ + songID: 1, + chartID: Testing511SPA.chartID, + userID: 1, + }), + ]); + + const res = await mockApi + .get("/api/v1/games/iidx/SP/charts?requesterHasPlayed=true&search=gambol") + .set("Authorization", "Bearer fake_api_token"); + + t.hasStrict(res.body.body.charts[0], { + __playcount: 1, + chartID: "fc7edc6bcfa701a261c89c999ddbba3e2195597b", + }); + + // gambol has SPB, SPN and SPH, but only SPH has been played by the requester + // although 5.1.1 has been played by the requester, it should not match the + // search. + t.equal(res.body.body.charts.length, 3); + + t.end(); + }, + ); + + t.end(); +}); + +t.test("POST /api/v1/games/:game/:playtype/charts/resolve", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(LoadTachiIIDXData); + + t.test("Should resolve a chart using tachiSongID matchType.", async (t) => { + const res = await mockApi.post("/api/v1/games/iidx/SP/charts/resolve").send({ + matchType: "tachiSongID", + identifier: "1", + difficulty: "ANOTHER", + }); + + t.equal(res.statusCode, 200); + t.equal(res.body.success, true); + t.equal(res.body.body.chart.chartID, Testing511SPA.chartID); + t.equal(res.body.body.song.id, 1); + t.equal(res.body.body.song.title, "5.1.1."); + + t.end(); + }); + + t.test("Should resolve a chart using songTitle matchType.", async (t) => { + const res = await mockApi.post("/api/v1/games/iidx/SP/charts/resolve").send({ + matchType: "songTitle", + identifier: "5.1.1.", + difficulty: "ANOTHER", + }); + + t.equal(res.statusCode, 200); + t.equal(res.body.success, true); + t.equal(res.body.body.chart.chartID, Testing511SPA.chartID); + t.equal(res.body.body.song.id, 1); + + t.end(); + }); + + t.test("Should return 404 when chart cannot be resolved.", async (t) => { + const res = await mockApi.post("/api/v1/games/iidx/SP/charts/resolve").send({ + matchType: "tachiSongID", + identifier: "99999", + difficulty: "ANOTHER", + }); + + t.equal(res.statusCode, 404); + t.equal(res.body.success, false); + t.match(res.body.description, /Could not resolve this chart/u); + + t.end(); + }); + + t.test("Should return 400 for invalid request body.", async (t) => { + const res = await mockApi.post("/api/v1/games/iidx/SP/charts/resolve").send({ + matchType: "invalidMatchType", + identifier: "1", + }); + + t.equal(res.statusCode, 400); + t.equal(res.body.success, false); + + t.end(); + }); + + t.test("Should return 400 when required fields are missing.", async (t) => { + const res = await mockApi.post("/api/v1/games/iidx/SP/charts/resolve").send({ + matchType: "tachiSongID", + // missing identifier + }); + + t.equal(res.statusCode, 400); + t.equal(res.body.success, false); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/charts/router.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/charts/router.ts new file mode 100644 index 000000000..547cde4b9 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/charts/router.ts @@ -0,0 +1,164 @@ +import { SYMBOL_TACHI_API_AUTH } from "#lib/constants/tachi"; +import { log } from "#lib/log/log.js"; +import { ResolveSongAndChart } from "#lib/score-import/import-types/common/batch-manual/converter"; +import { SearchSpecificGameSongs } from "#lib/search/search"; +import prValidate from "#server/middleware/prudence-validate"; +import db from "#services/mongo/db"; +import { IsString } from "#utils/misc"; +import { FindChartsOnPopularity } from "#utils/queries/charts"; +import { GetGPT } from "#utils/req-tachi-data"; +import { Router } from "express"; +import { + type ChartDocument, + type integer, + type MatchTypeResolver, + type UGPTSettingsDocument, +} from "tachi-common"; +import { PR_RESOLVER } from "tachi-common/lib/schemas"; + +import chartIDRouter from "./_chartID/router"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Searches for charts on this game - if no search parameter is given, + * returns the 100 most popular charts for this game. + * + * @param search - The song title to match on. + * @param noIntelligentOmit - If present, will not perform intelligent + * chart omissions from results. + * @param requesterHasPlayed - If present, will only return charts the + * requesting user has a PB on. If this request doesn't belong to a user, + * this returns 401. + * + * @name GET /api/v1/games/:game/:playtype/charts + */ +router.get("/", async (req, res) => { + const { game, playtype } = GetGPT(req); + + let songIDs: Array | undefined; + + if (IsString(req.query.search)) { + const songs = await SearchSpecificGameSongs(game, req.query.search, 100); + + songIDs = songs.map((e) => e.id); + } + + if (IsString(req.query.requesterHasPlayed)) { + const userID = req[SYMBOL_TACHI_API_AUTH].userID; + + if (userID === null) { + return res.status(401).json({ + success: false, + description: `You must be authorised as a user to use the requesterHasPlayed option.`, + }); + } + + const playedSongs = ( + await db["personal-bests"].find( + { userID, game, playtype }, + { projection: { songID: 1 } }, + ) + ).map((e) => e.songID); + + if (songIDs) { + songIDs = songIDs.filter((e) => playedSongs.includes(e)); + } else { + songIDs = playedSongs; + } + } + + const skip = 0; + const limit = 100; + + let charts = (await FindChartsOnPopularity( + game, + playtype, + + // if empty, we want the set of all songs. Otherwise, constrict input. + songIDs, + skip, + limit, + "personal-bests", + )) as Array; + + // @optimisable + // could use songIDs from above instead of refetching + // but this is not very expensive. + const songs = await db.anySongs[game].find({ + id: { $in: charts.map((e) => e.songID) }, + }); + + // Edge case. + // If the game is IIDX and the player does not want + // to see 2dxtra charts, we need to remove them from the + // result of a search. + // + // Since most players will have this off, this is not a significant + // performance hit. + if (game === "iidx" && req.query.noIntelligentOmit === undefined) { + if (req[SYMBOL_TACHI_API_AUTH].userID === null) { + charts = charts.filter( + (e) => (e as ChartDocument<"iidx:DP" | "iidx:SP">).data["2dxtraSet"] === null, + ); + } else { + const iidxSettings = (await db["game-settings"].findOne({ + userID: req[SYMBOL_TACHI_API_AUTH].userID, + game, + playtype, + })) as UGPTSettingsDocument<"iidx:DP" | "iidx:SP"> | null; + + if (!iidxSettings?.preferences.gameSpecific.display2DXTra) { + charts = charts.filter( + (e) => (e as ChartDocument<"iidx:DP" | "iidx:SP">).data["2dxtraSet"] === null, + ); + } + } + } + + return res.status(200).json({ + success: true, + description: `Returned ${charts.length} charts.`, + body: { + charts, + songs, + }, + }); +}); + +/** + * Use the tachi "resolve" engine to identify a chart instead of + * using the Tachi IDs. Used to get a chart. + * + * @name POST /api/v1/users/:userID/games/:game/:playtype/pbs/resolve + */ +router.post("/resolve", prValidate(PR_RESOLVER), async (req, res) => { + const { game, playtype } = GetGPT(req); + + const safeBody = { + ...req.safeBody, + game, + playtype, + } as unknown as MatchTypeResolver; + const got = await ResolveSongAndChart(safeBody, log); + + if (!got) { + return res.status(404).json({ + success: false, + description: `Could not resolve this chart with details: ${safeBody.matchType}:${safeBody.identifier} (Extra specifiers: version=${safeBody.version}, artist=${safeBody.artist})`, + }); + } + + return res.status(200).json({ + success: true, + description: "Successfully retrieved chart info.", + body: { + chart: got.chart, + song: got.song, + }, + }); +}); + +router.use("/:chartID", chartIDRouter); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/folders/middleware.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/folders/middleware.ts new file mode 100644 index 000000000..8d0c5a2b6 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/folders/middleware.ts @@ -0,0 +1,21 @@ +import type { RequestHandler } from "express"; + +import db from "#services/mongo/db"; +import { AssignToReqTachiData, GetGPT } from "#utils/req-tachi-data"; + +export const GetFolderFromParam: RequestHandler = async (req, res, next) => { + const { game, playtype } = GetGPT(req); + + const folder = await db.folders.findOne({ folderID: req.params.folderID, game, playtype }); + + if (!folder) { + return res.status(404).json({ + success: false, + description: `This folder does not exist.`, + }); + } + + AssignToReqTachiData(req, { folderDoc: folder }); + + next(); +}; diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/folders/router.test.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/folders/router.test.ts new file mode 100644 index 000000000..95a89b2c6 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/folders/router.test.ts @@ -0,0 +1,80 @@ +import type { FolderDocument } from "tachi-common"; + +import db from "#services/mongo/db"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { Testing511SPA } from "#test-utils/test-data"; +import { CreateFolderChartLookup } from "#utils/folder"; +import deepmerge from "deepmerge"; +import t from "tap"; + +const mockFolder: FolderDocument = { + folderID: "foo", + game: "iidx", + playtype: "SP", + title: "12", + data: { + level: "10", + }, + type: "charts", + searchTerms: [], + inactive: false, +}; + +t.test("GET /api/v1/games/:game/:playtype/folders", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should search the folders for this game.", async (t) => { + await db.folders.insert([ + deepmerge(mockFolder, {}), + deepmerge(mockFolder, { folderID: "bar", playtype: "DP" }), + deepmerge(mockFolder, { folderID: "baz", game: "bms" }), + ]); + + const res = await mockApi.get("/api/v1/games/iidx/SP/folders?search=12"); + + t.equal(res.body.body.length, 1); + t.equal(res.body.body[0].folderID, "foo"); + + t.end(); + }); + + t.test("Should return 400 if no search parameter is given.", async (t) => { + const res = await mockApi.get("/api/v1/games/iidx/SP/folders"); + + t.equal(res.statusCode, 400); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/games/:game/:playtype/folders/:folderID", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return the folder at this ID.", async (t) => { + await db.folders.insert(deepmerge(mockFolder, {})); + await CreateFolderChartLookup(mockFolder, true); + + const res = await mockApi.get("/api/v1/games/iidx/SP/folders/foo"); + + t.equal(res.body.body.folder.folderID, "foo"); + t.equal(res.body.body.songs.length, 1); + t.equal(res.body.body.charts.length, 1); + t.equal(res.body.body.songs[0].id, 1); + t.equal(res.body.body.charts[0].chartID, Testing511SPA.chartID); + + t.end(); + }); + + t.test("Should return 404 if the folder does not exist.", async (t) => { + const res = await mockApi.get("/api/v1/games/iidx/SP/folders/bar"); + + t.equal(res.statusCode, 404); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/folders/router.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/folders/router.ts new file mode 100644 index 000000000..84f50e565 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/folders/router.ts @@ -0,0 +1,71 @@ +import { SearchCollection } from "#lib/search/search"; +import db from "#services/mongo/db"; +import { GetFolderCharts } from "#utils/folder"; +import { IsString } from "#utils/misc"; +import { GetGPT, GetTachiData } from "#utils/req-tachi-data"; +import { Router } from "express"; + +import { GetFolderFromParam } from "./middleware"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Search the folders for this GPT. + * + * @param search - The query to search for. + * @param inactive - Also show inactive folders, such as those on old versions. + * + * @name GET /api/v1/games/:game/:playtype/folders + */ +router.get("/", async (req, res) => { + const { game, playtype } = GetGPT(req); + + if (!IsString(req.query.search)) { + return res.status(400).json({ + success: false, + description: `Invalid value for search.`, + }); + } + + // if inactive is passed, we need this to be undefined so that + // mongodb returns both inactive and active folders. + // Otherwise, only return active folders. + const inactive = req.query.inactive === undefined ? false : undefined; + + const folders = await SearchCollection( + db.folders, + req.query.search, + "folders", + { game, playtype, inactive }, + 100, + ); + + return res.status(200).json({ + success: true, + description: `Returned ${folders.length} folders.`, + body: folders, + }); +}); + +/** + * Get the folder at this ID, alongside its charts and songs. + * + * @name GET /api/v1/games/:game/:playtype/folders/:folderID + */ +router.get("/:folderID", GetFolderFromParam, async (req, res) => { + const folder = GetTachiData(req, "folderDoc"); + + const { songs, charts } = await GetFolderCharts(folder, {}, true); + + return res.status(200).json({ + success: true, + description: `Returned data for folder ${folder.title}`, + body: { + songs, + charts, + folder, + }, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/middleware.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/middleware.ts new file mode 100644 index 000000000..e69cfd65b --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/middleware.ts @@ -0,0 +1,38 @@ +import type { RequestHandler } from "express"; + +import { AssignToReqTachiData, GetTachiData } from "#utils/req-tachi-data"; +import { type GameGroup, GetGameGroupConfig, type Playtype } from "tachi-common"; + +export const ValidatePlaytypeFromParam: RequestHandler = (req, res, next) => { + const game = GetTachiData(req, "game"); + + const gameConfig = GetGameGroupConfig(game); + + if (!gameConfig.playtypes.includes(req.params.playtype as Playtype)) { + return res.status(400).json({ + success: false, + description: `The playtype ${req.params.playtype} is not supported.`, + }); + } + + AssignToReqTachiData(req, { playtype: req.params.playtype as Playtype }); + + next(); +}; + +export const ValidatePlaytypeFromParamFor = + (game: GameGroup): RequestHandler => + (req, res, next) => { + const gameConfig = GetGameGroupConfig(game); + + if (!gameConfig.playtypes.includes(req.params.playtype as Playtype)) { + return res.status(400).json({ + success: false, + description: `The playtype ${req.params.playtype} is not supported.`, + }); + } + + AssignToReqTachiData(req, { playtype: req.params.playtype as Playtype }); + + next(); + }; diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/router.test.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/router.test.ts new file mode 100644 index 000000000..d8ba31ba6 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/router.test.ts @@ -0,0 +1,165 @@ +import db from "#services/mongo/db"; +import { mkFakeGameStats, mkFakeUser } from "#test-utils/misc"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { FakeOtherUser } from "#test-utils/test-data"; +import dm from "deepmerge"; +import { GetGamePTConfig, type UserDocument, type UserGameStats } from "tachi-common"; +import t from "tap"; + +t.test("GET /api/v1/games/:game/:playtype", (t) => { + t.test("Should return information about the game:playtype.", async (t) => { + const res = await mockApi.get("/api/v1/games/iidx/SP"); + + t.hasStrict(GetGamePTConfig("iidx", "SP"), res.body.body.config); + + t.equal(res.body.body.chartCount, 1); + t.equal(res.body.body.playerCount, 1); + t.equal(res.body.body.scoreCount, 1); + + t.end(); + }); + + t.test("Should reject invalid playtypes for this game.", async (t) => { + const res = await mockApi.get("/api/v1/games/iidx/Single"); + + t.equal(res.statusCode, 400); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/games/:game/:playtype/leaderboard", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return the leaderboards for this game", async (t) => { + const res = await mockApi.get("/api/v1/games/iidx/SP/leaderboard"); + + t.equal(res.statusCode, 200); + t.equal(res.body.body.gameStats.length, 1); + t.equal(res.body.body.users.length, 1); + + t.hasStrict(res.body.body, { + gameStats: [ + { + userID: 1, + game: "iidx", + playtype: "SP", + }, + ], + users: [ + { + id: 1, + }, + ], + }); + + t.end(); + }); + + t.test("Should reject unknown alg", async (t) => { + const res = await mockApi.get("/api/v1/games/iidx/SP/leaderboard?alg=naiveRating"); + + t.equal(res.statusCode, 400); + + t.end(); + }); + + t.test("Should use provided algorithm to resort results.", async (t) => { + await db["game-stats"].insert([ + { + userID: 2, + game: "iidx", + playtype: "SP", + ratings: { + BPI: 100, + }, + }, + { + userID: 3, + game: "iidx", + playtype: "SP", + ratings: { + BPI: 50, + }, + }, + ] as Array); + + await db.users.insert([ + FakeOtherUser, + dm(FakeOtherUser, { + username: "foo", + usernameLowercase: "foo", + id: 3, + }) as UserDocument, + ]); + + const res = await mockApi.get("/api/v1/games/iidx/SP/leaderboard?alg=BPI"); + + t.strictSame( + res.body.body.gameStats.map((e: UserGameStats) => e.userID), + [2, 3, 1], + ); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/games/:game/:playtype/players", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(async () => { + await db.users.insert([ + mkFakeUser(2, { usernameLowercase: "scrimblo" }), + mkFakeUser(3, { usernameLowercase: "scrimblo_2" }), + mkFakeUser(4, { usernameLowercase: "scrimblo_3" }), + mkFakeUser(5, { usernameLowercase: "cloudy" }), + ]); + + await db["game-stats"].insert([ + mkFakeGameStats(2), + mkFakeGameStats(3, { game: "iidx", playtype: "DP" }), + mkFakeGameStats(4, { game: "bms", playtype: "7K" }), + mkFakeGameStats(5), + ]); + }); + + t.test("Should find the users where this game has been played.", async (t) => { + const res = await mockApi.get("/api/v1/games/iidx/SP/players?search=scrimblo"); + + t.hasStrict(res.body.body, [{ id: 2 }]); + t.equal(res.body.body.length, 1); + + t.end(); + }); + + t.test("Should definitely honour the search parameter.", async (t) => { + const res = await mockApi.get("/api/v1/games/iidx/SP/players?search=nobody"); + + t.strictSame(res.body.body, []); + + t.end(); + }); + + t.test("Should definitely honour the GPT.", async (t) => { + const res = await mockApi.get("/api/v1/games/iidx/DP/players?search=scrimblo"); + + t.hasStrict(res.body.body, [{ id: 3 }]); + t.equal(res.body.body.length, 1); + + t.end(); + }); + + t.test("Should require the search parameter.", async (t) => { + const res = await mockApi.get("/api/v1/games/iidx/DP/players"); + + t.equal(res.statusCode, 400); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/router.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/router.ts new file mode 100644 index 000000000..a1488b1fb --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/router.ts @@ -0,0 +1,285 @@ +import type { FindOptions } from "monk"; + +import { CreateActivityRouteHandler } from "#lib/activity/activity"; +import { ONE_HOUR } from "#lib/constants/time"; +import { SearchUsersRegExp } from "#lib/search/search"; +import prValidate from "#server/middleware/prudence-validate"; +import db from "#services/mongo/db"; +import { GetRelevantSongsAndCharts } from "#utils/db"; +import { IsString } from "#utils/misc"; +import { GetGPT } from "#utils/req-tachi-data"; +import { + CheckStrProfileAlg, + CheckStrScoreAlg, + ParseStrPositiveNonZeroInt, +} from "#utils/string-checks"; +import { GetUsersWithIDs } from "#utils/user"; +import { Router } from "express"; +import NodeCache from "node-cache"; +import { + FormatGameGroup, + type GameGroup, + GetGamePTConfig, + type integer, + type Playtype, + type UserGameStats, +} from "tachi-common"; + +import chartsRouter from "./charts/router"; +import foldersRouter from "./folders/router"; +import { ValidatePlaytypeFromParam } from "./middleware"; +import songIDRouter from "./songs/_songID/router"; +import tablesRouter from "./tables/router"; +import targetsRouter from "./targets/router"; + +const router: Router = Router({ mergeParams: true }); + +router.use(ValidatePlaytypeFromParam); + +const gptStatCache = new NodeCache(); + +async function GetGameStats( + game: GameGroup, + playtype: Playtype, +): Promise<{ chartCount: integer; playerCount: integer; scoreCount: integer }> { + const cacheRes = gptStatCache.get(`${game}:${playtype}`); + + if (cacheRes === undefined) { + const [scoreCount, playerCount, chartCount] = await Promise.all([ + db.scores.count({ + game, + playtype, + }), + db["game-stats"].count({ + game, + playtype, + }), + db.anyCharts[game].count({ playtype }), + ]); + + gptStatCache.set(`${game}:${playtype}`, { scoreCount, playerCount, chartCount }, ONE_HOUR); + + return { scoreCount, playerCount, chartCount }; + } + + return cacheRes as { chartCount: integer; playerCount: integer; scoreCount: integer }; +} + +/** + * Returns the configuration for this game along with some statistics. + * + * @name GET /api/v1/games/:game/:playtype + */ +router.get("/", async (req, res) => { + const { game, playtype } = GetGPT(req); + + const { scoreCount, playerCount, chartCount } = await GetGameStats(game, playtype); + + return res.status(200).json({ + success: true, + description: `Retrieved information about ${FormatGameGroup(game, playtype)}`, + body: { + config: GetGamePTConfig(game, playtype), + scoreCount, + playerCount, + chartCount, + }, + }); +}); + +/** + * Returns user-game-stats for this game in batches of 500. + * This is sorted by the games default-sorting-statistic. + * + * @param alg - An alternative algorithm to use instead of the gpts default. + * @param limit - How many users to return at most. Defaults (and is limited to) 500. + * + * @name GET /api/v1/games/:game/:playtype/leaderboard + */ +router.get("/leaderboard", async (req, res) => { + const { game, playtype } = GetGPT(req); + const gptConfig = GetGamePTConfig(game, playtype); + + const limit = ParseStrPositiveNonZeroInt(req.query.limit) ?? 100; + + if (limit > 500) { + return res.status(400).json({ + success: false, + description: `Invalid limit. Limit is capped at 500.`, + }); + } + + let alg = gptConfig.defaultProfileRatingAlg; + + if (IsString(req.query.alg)) { + const temp = CheckStrProfileAlg(game, playtype, req.query.alg); + + if (temp === null) { + return res.status(400).json({ + success: false, + description: `Invalid value of ${ + req.query.alg + } for alg. Expected one of ${Object.keys(gptConfig.profileRatingAlgs).join(", ")}`, + }); + } + + alg = temp; + } + + const options: FindOptions = { + sort: { + [`ratings.${alg}`]: -1, + }, + limit, + }; + + const gameStats = await db["game-stats"].find( + { + game, + playtype, + }, + options, + ); + + const users = await GetUsersWithIDs(gameStats.map((e) => e.userID)); + + return res.status(200).json({ + success: true, + description: `Returned ${gameStats.length} user's game stats.`, + body: { + gameStats, + users, + }, + }); +}); + +/** + * Returns the best scores for this game. + * + * @param alg - An alternative algorithm to use instead of the gpts default. + * @param limit - How many scores to return. + * + * @name GET /api/v1/games/:game/:playtype/pb-leaderboard + */ +router.get("/pb-leaderboard", async (req, res) => { + const { game, playtype } = GetGPT(req); + const gptConfig = GetGamePTConfig(game, playtype); + + const limit = ParseStrPositiveNonZeroInt(req.query.limit) ?? 50; + + if (limit > 50) { + return res.status(400).json({ + success: false, + description: `Cannot specify a limit higher than 50.`, + }); + } + + let alg = gptConfig.defaultScoreRatingAlg; + + if (IsString(req.query.alg)) { + const temp = CheckStrScoreAlg(game, playtype, req.query.alg); + + if (temp === null) { + return res.status(400).json({ + success: false, + description: `Invalid value of ${ + req.query.alg + } for alg. Expected one of ${Object.keys(gptConfig.profileRatingAlgs).join(", ")}`, + }); + } + + alg = temp; + } + + const pbs = await db["personal-bests"].find( + { + game, + playtype, + }, + { + sort: { + [`calculatedData.${alg}`]: -1, + }, + limit, + }, + ); + + const users = await GetUsersWithIDs(pbs.map((e) => e.userID)); + + const { songs, charts } = await GetRelevantSongsAndCharts(pbs, game); + + return res.status(200).send({ + success: true, + description: `Successfully returned ${pbs.length} pbs.`, + body: { + pbs, + songs, + charts, + users, + }, + }); +}); + +/** + * Search users that have played this game. + * + * @param search - The username to search for. + * + * @name GET /api/v1/games/:game/:playtype/players + */ +router.get( + "/players", + prValidate({ + search: "string", + }), + async (req, res) => { + const { game, playtype } = GetGPT(req); + + const { search } = req.query as { + search: string; + }; + + const users = await SearchUsersRegExp(search); + + const gameStats = await db["game-stats"].find({ + userID: { $in: users.map((e) => e.id) }, + game, + playtype, + }); + + const thoseWithStats = gameStats.map((e) => e.userID); + + const gptPlayers = users.filter((e) => thoseWithStats.includes(e.id)); + + return res.status(200).json({ + success: true, + description: `Found ${gptPlayers.length} user(s)`, + body: gptPlayers, + }); + }, +); + +/** + * Retrieve activity for this GPT. + * + * @name GET /api/v1/games/:game/:playtype/activity + */ +router.get("/activity", (req, res) => { + const { game, playtype } = GetGPT(req); + + const route = CreateActivityRouteHandler({ + game, + playtype, + }); + + // this handles responding + void route(req, res); +}); + +router.use("/charts", chartsRouter); +router.use("/songs/:songID", songIDRouter); +router.use("/folders", foldersRouter); +router.use("/tables", tablesRouter); +router.use("/targets", targetsRouter); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/songs/_songID/middleware.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/songs/_songID/middleware.ts new file mode 100644 index 000000000..304c51276 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/songs/_songID/middleware.ts @@ -0,0 +1,31 @@ +import type { RequestHandler } from "express"; + +import db from "#services/mongo/db"; +import { AssignToReqTachiData, GetTachiData } from "#utils/req-tachi-data"; +import { ParseStrPositiveInt } from "#utils/string-checks"; + +export const ValidateAndGetSong: RequestHandler = async (req, res, next) => { + const songID = ParseStrPositiveInt(req.params.songID); + + if (songID === null) { + return res.status(400).json({ + success: false, + description: `Invalid songID - could not be converted into integer?`, + }); + } + + const game = GetTachiData(req, "game"); + + const song = await db.anySongs[game].findOne({ id: songID }); + + if (!song) { + return res.status(404).json({ + success: false, + description: `No song exists with the songID ${songID}.`, + }); + } + + AssignToReqTachiData(req, { songDoc: song }); + + next(); +}; diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/songs/_songID/router.test.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/songs/_songID/router.test.ts new file mode 100644 index 000000000..8b1f49abe --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/songs/_songID/router.test.ts @@ -0,0 +1,41 @@ +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { LoadTachiIIDXData } from "#test-utils/test-data"; +import t from "tap"; + +t.test("GET /api/v1/games/:game/:playtype/songs/:songID", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(LoadTachiIIDXData); + + t.test("Should return the song at this ID and all of its charts.", async (t) => { + const res = await mockApi.get("/api/v1/games/iidx/SP/songs/1"); + + t.equal(res.body.body.charts.length, 4); + + t.equal(res.body.body.song.id, 1); + + t.end(); + }); + + t.test("Should return 404 if this songID does not exist.", async (t) => { + const res = await mockApi.get("/api/v1/games/iidx/SP/songs/0"); + + t.equal(res.statusCode, 404); + + t.end(); + }); + + t.test("Should return 400 if songID is not coercible into an integer.", async (t) => { + const res = await mockApi.get("/api/v1/games/iidx/SP/songs/1.5"); + + t.equal(res.statusCode, 400); + + const res2 = await mockApi.get("/api/v1/games/iidx/SP/songs/FOO"); + + t.equal(res2.statusCode, 400); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/songs/_songID/router.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/songs/_songID/router.ts new file mode 100644 index 000000000..3470a592c --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/songs/_songID/router.ts @@ -0,0 +1,35 @@ +import db from "#services/mongo/db"; +import { GetGPT, GetTachiData } from "#utils/req-tachi-data"; +import { Router } from "express"; + +import { ValidateAndGetSong } from "./middleware"; + +const router: Router = Router({ mergeParams: true }); + +router.use(ValidateAndGetSong); + +/** + * Returns the song at this ID and its child chart documents. + * + * @name GET /api/v1/games/:game/:playtype/songs/:songID + */ +router.get("/", async (req, res) => { + const song = GetTachiData(req, "songDoc"); + const { game, playtype } = GetGPT(req); + + const charts = await db.anyCharts[game].find({ + songID: song.id, + playtype, + }); + + return res.status(200).json({ + success: true, + description: `Returned ${charts.length} charts for song ${song.title}.`, + body: { + song, + charts, + }, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/tables/middleware.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/tables/middleware.ts new file mode 100644 index 000000000..a3574f1d9 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/tables/middleware.ts @@ -0,0 +1,22 @@ +import type { RequestHandler } from "express"; + +import db from "#services/mongo/db"; +import { AssignToReqTachiData, GetTachiData } from "#utils/req-tachi-data"; + +export const GetTableFromParam: RequestHandler = async (req, res, next) => { + const game = GetTachiData(req, "game"); + const playtype = GetTachiData(req, "playtype"); + + const table = await db.tables.findOne({ tableID: req.params.tableID, game, playtype }); + + if (!table) { + return res.status(404).json({ + success: false, + description: `This table does not exist.`, + }); + } + + AssignToReqTachiData(req, { tableDoc: table }); + + next(); +}; diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/tables/router.test.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/tables/router.test.ts new file mode 100644 index 000000000..18313352f --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/tables/router.test.ts @@ -0,0 +1,51 @@ +import type { FolderDocument } from "tachi-common"; + +import db from "#services/mongo/db"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { TestingIIDXFolderSP10 } from "#test-utils/test-data"; +import deepmerge from "deepmerge"; +import t from "tap"; + +t.test("GET /api/v1/games/:game/:playtype/tables", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return all folders for this game.", async (t) => { + const res = await mockApi.get("/api/v1/games/iidx/SP/tables"); + + t.equal(res.body.body.length, 1); + t.equal(res.body.body[0].tableID, "mock_table"); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/games/:game/:playtype/tables/:tableID", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return the table at this ID and its folders.", async (t) => { + await db.folders.insert( + deepmerge(TestingIIDXFolderSP10, { folderID: "testing_folder" }) as FolderDocument, + ); + + const res = await mockApi.get("/api/v1/games/iidx/SP/tables/mock_table"); + + t.equal(res.body.body.folders.length, 1); + t.equal(res.body.body.folders[0].folderID, "testing_folder"); + t.equal(res.body.body.table.tableID, "mock_table"); + + t.end(); + }); + + t.test("Should return 404 if the table does not exist.", async (t) => { + const res = await mockApi.get("/api/v1/games/iidx/SP/tables/non_existent_table"); + + t.equal(res.statusCode, 404); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/tables/router.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/tables/router.ts new file mode 100644 index 000000000..2e8217fd0 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/tables/router.ts @@ -0,0 +1,72 @@ +import type { FilterQuery } from "mongodb"; + +import { log } from "#lib/log/log.js"; +import db from "#services/mongo/db"; +import { GetFoldersFromTable } from "#utils/folder"; +import { GetGPT, GetTachiData } from "#utils/req-tachi-data"; +import { Router } from "express"; +import { FormatGameGroup, type TableDocument } from "tachi-common"; + +import { GetTableFromParam } from "./middleware"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Return all the tables for this game. + * + * @param showInactive - If present, also show "inactive" tables. + * + * @name GET /api/v1/games/:game/:playtype/tables + */ +router.get("/", async (req, res) => { + const { game, playtype } = GetGPT(req); + + const query: FilterQuery = { game, playtype }; + + if (req.query.showInactive === undefined) { + query.inactive = false; + } + + const tables = await db.tables.find(query); + + if (tables.length === 0) { + log.error( + `The game ${FormatGameGroup( + game, + playtype, + )} has no tables. This renders table support for the game broken!`, + ); + return res.status(500).json({ + success: false, + description: "This game has no tables.", + }); + } + + return res.status(200).json({ + success: true, + description: `Returned ${tables.length} tables.`, + body: tables, + }); +}); + +/** + * Return the folder documents that make up this table. + * + * @name GET /api/v1/games/:game/:playtype/tables/:tableID + */ +router.get("/:tableID", GetTableFromParam, async (req, res) => { + const table = GetTachiData(req, "tableDoc"); + + const folders = await GetFoldersFromTable(table); + + return res.status(200).json({ + success: true, + description: `Returned ${folders.length} for table ${table.title}.`, + body: { + folders, + table, + }, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/targets/goals/router.test.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/targets/goals/router.test.ts new file mode 100644 index 000000000..1600b50b1 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/targets/goals/router.test.ts @@ -0,0 +1,94 @@ +import type { GoalDocument, GoalSubscriptionDocument } from "tachi-common"; + +import db from "#services/mongo/db"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { + FakeOtherUser, + IIDXSPQuestGoals, + IIDXSPQuestGoalSubs, + TestingIIDXSPQuest, +} from "#test-utils/test-data"; +import dm from "deepmerge"; +import t from "tap"; + +// this is my lazy sample data for these tests. +const LoadLazySampleData = async () => { + await db.users.insert(FakeOtherUser); + await db.goals.insert(IIDXSPQuestGoals); + await db["goal-subs"].insert([ + ...IIDXSPQuestGoalSubs, + dm(IIDXSPQuestGoalSubs[0]!, { + userID: 2, + }), + ] as Array); +}; + +t.test("GET /api/v1/games/:game/:playtype/targets/goals/popular", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(LoadLazySampleData); + + t.test("Should return the most popular subscribed goals for this game.", async (t) => { + const res = await mockApi.get("/api/v1/games/iidx/SP/targets/goals/popular"); + + t.equal(res.statusCode, 200, "Should return 200."); + + // note: we have to sort the output here such that it's deterministic. + t.strictSame( + (res.body.body as Array).sort((a, b) => a.goalID.localeCompare(b.goalID)), + ( + [ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + dm(IIDXSPQuestGoals[0] as any, { __subscriptions: 2 }), + // eslint-disable-next-line @typescript-eslint/no-explicit-any + dm(IIDXSPQuestGoals[1] as any, { __subscriptions: 1 }), + // eslint-disable-next-line @typescript-eslint/no-explicit-any + dm(IIDXSPQuestGoals[2] as any, { __subscriptions: 1 }), + // eslint-disable-next-line @typescript-eslint/no-explicit-any + dm(IIDXSPQuestGoals[3] as any, { __subscriptions: 1 }), + ] as unknown as Array + ).sort((a, b) => a.goalID.localeCompare(b.goalID)), + "Should return the most subscribed goals.", + ); + + t.end(); + }); + + t.test("Should return an empty array if nobody has done anything.", async (t) => { + const res = await mockApi.get("/api/v1/games/chunithm/Single/targets/goals/popular"); + + t.equal(res.statusCode, 200, "Should return 200."); + t.strictSame(res.body.body, []); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/games/:game/:playtype/targets/goals/:goalID", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(LoadLazySampleData); + + t.test("Should return information about the specified goal.", async (t) => { + await db.quests.insert(TestingIIDXSPQuest); + + const res = await mockApi.get("/api/v1/games/iidx/SP/targets/goals/eg_goal_1"); + + t.hasStrict(res.body.body, { + goal: { + goalID: "eg_goal_1", + }, + goalSubs: [ + { userID: 1, goalID: "eg_goal_1" }, + { userID: 2, goalID: "eg_goal_1" }, + ], + users: [{ id: 1 }, { id: 2 }], + parentQuests: [{ questID: TestingIIDXSPQuest.questID }], + }); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/targets/goals/router.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/targets/goals/router.ts new file mode 100644 index 000000000..f46d0200b --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/targets/goals/router.ts @@ -0,0 +1,180 @@ +import type { GoalDocument } from "tachi-common"; + +import { log } from "#lib/log/log.js"; +import { CreateGoalTitle, ValidateGoalChartsAndCriteria } from "#lib/targets/goal-utils"; +import { GetQuestsThatContainGoal } from "#lib/targets/goals"; +import prValidate from "#server/middleware/prudence-validate"; +import db from "#services/mongo/db"; +import { GetMostSubscribedGoals } from "#utils/db"; +import { AssignToReqTachiData, GetGPT, GetTachiData } from "#utils/req-tachi-data"; +import { GetUsersWithIDs } from "#utils/user"; +import { type RequestHandler, Router } from "express"; +import { p } from "prudence"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Get the most popular goals for this GPT. + * + * @name GET /api/v1/games/:game/:playtype/targets/goals/popular + */ +router.get("/popular", async (req, res) => { + const { game, playtype } = GetGPT(req); + + const goals = await GetMostSubscribedGoals({ game, playtype }); + + return res.status(200).json({ + success: true, + description: `Returned ${goals.length} goals.`, + body: goals, + }); +}); + +/** + * Given a partial goal, return a name for it. This formats the goal into something like + * "AAA 100 charts in the Level 12 folder". + * + * This is used by the quest editor, as the controls for formatting charts are done + * on the backend. + * + * This is a post request because it expects nested data, and get requests suck + * for that. + * + * @name POST /api/v1/games/:game/:playtype/targets/goals/format + */ +router.post( + "/format", + prValidate( + { + criteria: { + // we do proper validation on this later. + key: "string", + value: p.gte(0), + + mode: p.isIn("single", "absolute", "proportion"), + countNum: (self, parent) => { + if (parent.mode === "single") { + return ( + self === undefined || + "Invalid countNum for mode 'single'. Must not have one!" + ); + } + + // proper validation later. + return p.gte(0)(self); + }, + }, + charts: { + type: p.isIn("single", "multi", "folder"), + data: (self, parent) => { + if (parent.type === "single") { + return ( + typeof self === "string" || + "Expected a string in charts.data due to charts.type being 'single'." + ); + } else if (parent.type === "multi") { + return ( + (Array.isArray(self) && + self.every((k) => typeof k === "string") && + self.length <= 10 && + self.length > 1) || + "Expected an array of 2 to 10 strings in charts.data due to charts.type being 'multi'." + ); + /* istanbul ignore next */ + } else if (parent.type === "folder") { + return ( + typeof self === "string" || + "Expected a string in charts.data due to charts.type being 'folder'." + ); + } + + // impossible to reach, so doesn't count for coverage. + /* istanbul ignore next */ + return "Unknown charts.type."; + }, + }, + }, + undefined, + undefined, + "debug", + ), + async (req, res) => { + const { game, playtype } = GetGPT(req); + + const { charts, criteria } = req.safeBody as { + charts: GoalDocument["charts"]; + criteria: GoalDocument["criteria"]; + }; + + try { + await ValidateGoalChartsAndCriteria(charts, criteria, game, playtype); + } catch (e) { + const err = e as Error; + + return res.status(400).json({ + success: false, + description: `Invalid goal: ${err.message}.`, + }); + } + + const title = await CreateGoalTitle(charts, criteria, game, playtype); + + return res.status(200).json({ + success: true, + description: `Formatted goal.`, + body: title, + }); + }, +); + +const ResolveGoalID: RequestHandler = async (req, res, next) => { + const { game, playtype } = GetGPT(req); + const goalID = req.params.goalID; + + const goal = await db.goals.findOne({ + goalID, + game, + playtype, + }); + + if (!goal) { + return res.status(404).json({ + success: false, + description: `A goal with ID ${goalID} doesn't exist.`, + }); + } + + AssignToReqTachiData(req, { goalDoc: goal }); + + next(); +}; + +/** + * Retrieve information about this goal and who is subscribed to it. + * + * @name GET /api/v1/games/:game/:playtype/targets/goals/:goalID + */ +router.get("/:goalID", ResolveGoalID, async (req, res) => { + const goal = GetTachiData(req, "goalDoc"); + + const goalSubs = await db["goal-subs"].find({ + goalID: goal.goalID, + }); + + const users = await GetUsersWithIDs(goalSubs.map((e) => e.userID)); + + const parentQuests = await GetQuestsThatContainGoal(goal.goalID); + + return res.status(200).json({ + success: true, + description: `Retrieved information about ${goal.name}.`, + body: { + goal, + goalSubs, + users, + parentQuests, + }, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/targets/questlines/router.test.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/targets/questlines/router.test.ts new file mode 100644 index 000000000..ee1ec2d14 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/targets/questlines/router.test.ts @@ -0,0 +1,96 @@ +import type { QuestDocument, QuestlineDocument } from "tachi-common"; + +import db from "#services/mongo/db"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { TestingIIDXSPQuest } from "#test-utils/test-data"; +import dm from "deepmerge"; +import t from "tap"; + +const TestingIIDXSPQuestline: QuestlineDocument = { + name: "Testing Questline", + desc: "foo", + game: "iidx", + quests: [TestingIIDXSPQuest.questID, "other_quest"], + playtype: "SP", + questlineID: "quest_set", +}; + +t.test("GET /api/v1/games/:game/:playtype/targets/questlines", (t) => { + t.beforeEach(ResetDBState); + + function mkSet(merge: any) { + return dm(TestingIIDXSPQuestline, merge) as QuestlineDocument; + } + + t.test("Should return all questlines for this game.", async (t) => { + await db.questlines.insert([ + mkSet({ name: "Testing Set", questlineID: "name" }), + mkSet({ name: "Testing Other Set", questlineID: "similar_name" }), + mkSet({ name: "Different Name", questlineID: "radically_different_name" }), + mkSet({ + game: "chunithm", + playtype: "Single", + questlineID: "matching name but different gpt", + }), + mkSet({ playtype: "DP", questlineID: "matching name but different playtype" }), + ]); + + const res = await mockApi.get("/api/v1/games/iidx/SP/targets/questlines"); + + t.hasStrict( + (res.body.body.questlines as Array).sort((a, b) => + a.name.localeCompare(b.name), + ), + [ + { questlineID: "radically_different_name" }, + { questlineID: "similar_name" }, + { questlineID: "name" }, + ], + ); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/games/:game/:playtype/targets/questlines/:questlineID", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(async () => { + await db.questlines.insert(TestingIIDXSPQuestline); + await db.quests.insert([ + TestingIIDXSPQuest, + dm(TestingIIDXSPQuest, { questID: "other_quest" }) as QuestDocument, + ]); + }); + + t.test("Should return the questline and its quests.", async (t) => { + const res = await mockApi.get("/api/v1/games/iidx/SP/targets/questlines/quest_set"); + + t.equal(res.statusCode, 200, "Should return 200."); + + t.hasStrict(res.body.body.questline, { + questlineID: TestingIIDXSPQuestline.questlineID, + }); + + t.hasStrict( + (res.body.body.quests as Array).sort((a, b) => + a.questID.localeCompare(b.questID), + ), + [{ questID: TestingIIDXSPQuest.questID }, { questID: "other_quest" }], + ); + + t.end(); + }); + + t.test("Should return 404 if the questline doesn't exist.", async (t) => { + const res = await mockApi.get("/api/v1/games/iidx/SP/targets/questlines/foobar"); + + t.equal(res.statusCode, 404); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/targets/questlines/router.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/targets/questlines/router.ts new file mode 100644 index 000000000..cff4d51b9 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/targets/questlines/router.ts @@ -0,0 +1,75 @@ +import { FindStandaloneQuests, GetGoalsInQuests } from "#lib/targets/quests"; +import db from "#services/mongo/db"; +import { GetChildQuests } from "#utils/db"; +import { IsString } from "#utils/misc"; +import { AssignToReqTachiData, GetGPT, GetTachiData } from "#utils/req-tachi-data"; +import { type RequestHandler, Router } from "express"; + +const router: Router = Router({ mergeParams: true }); + +const ResolveQuestlineID: RequestHandler = async (req, res, next) => { + const { game, playtype } = GetGPT(req); + const questlineID = req.params.questlineID; + + const questline = await db.questlines.findOne({ + questlineID, + game, + playtype, + }); + + if (!questline) { + return res.status(404).json({ + success: false, + description: `A questline with ID ${questlineID} doesn't exist.`, + }); + } + + AssignToReqTachiData(req, { questlineDoc: questline }); + + next(); +}; + +/** + * Retrieve all questlines for this GPT. Also, return any standalone quests. + * + * @name GET /api/v1/games/:game/:playtype/targets/questlines + */ +router.get("/", async (req, res) => { + const { game, playtype } = GetGPT(req); + + const questlines = await db.questlines.find({ game, playtype }); + + const standalone = await FindStandaloneQuests(game, playtype); + const standaloneGoals = await GetGoalsInQuests(standalone); + + return res.status(200).json({ + success: true, + description: `Returned ${questlines.length} questlines.`, + body: { questlines, standalone, standaloneGoals }, + }); +}); + +/** + * Retrieve a specific questline. + * + * @name GET /api/v1/games/:game/:playtype/targets/questlines/:questlineID + */ +router.get("/:questlineID", ResolveQuestlineID, async (req, res) => { + const questline = GetTachiData(req, "questlineDoc"); + + const quests = await GetChildQuests(questline); + + const goals = await GetGoalsInQuests(quests); + + return res.status(200).json({ + success: true, + description: `Retrieved questline '${questline.name}'.`, + body: { + quests, + questline, + goals, + }, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/targets/quests/router.test.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/targets/quests/router.test.ts new file mode 100644 index 000000000..89a228eb2 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/targets/quests/router.test.ts @@ -0,0 +1,124 @@ +import type { QuestDocument, QuestlineDocument, QuestSubscriptionDocument } from "tachi-common"; + +import db from "#services/mongo/db"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { + FakeOtherUser, + IIDXSPQuestGoals, + IIDXSPQuestGoalSubs, + TestingIIDXSPQuest, + TestingIIDXSPQuestSub, +} from "#test-utils/test-data"; +import dm from "deepmerge"; +import t from "tap"; + +t.test("GET /api/v1/games/:game/:playtype/targets/quests", (t) => { + t.beforeEach(ResetDBState); + + function mkQuest(merge: any) { + return dm(TestingIIDXSPQuest, merge) as QuestDocument; + } + + t.test("Should search quests.", async (t) => { + await db.quests.insert([ + mkQuest({ name: "Testing Set", questID: "name" }), + mkQuest({ name: "Testing Other Set", questID: "similar_name" }), + mkQuest({ name: "Different Name", questID: "radically_different_name" }), + mkQuest({ + game: "chunithm", + playtype: "Single", + questID: "matching name but different gpt", + }), + mkQuest({ playtype: "DP", questID: "matching name but different playtype" }), + ]); + + const res = await mockApi.get("/api/v1/games/iidx/SP/targets/quests?search=Testing"); + + t.equal(res.statusCode, 200); + + t.hasStrict( + (res.body.body.quests as Array).sort((a, b) => + a.name.localeCompare(b.name), + ), + [{ questID: "similar_name" }, { questID: "name" }], + ); + + t.end(); + }); + + t.end(); +}); + +// this is my lazy sample data for these tests. +const LoadLazySampleData = async () => { + await db.users.insert(FakeOtherUser); + await db.goals.insert(IIDXSPQuestGoals); + await db.quests.insert([ + TestingIIDXSPQuest, + dm(TestingIIDXSPQuest, { questID: "other_quest" }) as QuestDocument, + ]); + await db["quest-subs"].insert([ + TestingIIDXSPQuestSub, + dm(TestingIIDXSPQuestSub, { questID: "other_quest" }), + dm(TestingIIDXSPQuestSub, { + userID: 2, + }), + ] as Array); +}; + +t.test("GET /api/v1/games/:game/:playtype/targets/quests/:questID", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(async () => { + await Promise.all([ + db["goal-subs"].insert(IIDXSPQuestGoalSubs), + db.questlines.insert({ + questlineID: "set_id", + quests: [TestingIIDXSPQuest.questID], + } as QuestlineDocument), + ]); + }); + + t.beforeEach(LoadLazySampleData); + + t.test("Should return the quest and its goals.", async (t) => { + const res = await mockApi.get( + `/api/v1/games/iidx/SP/targets/quests/${TestingIIDXSPQuest.questID}`, + ); + + t.hasStrict(res.body.body, { + quest: { questID: TestingIIDXSPQuest.questID }, + questSubs: [{ userID: 1, questID: TestingIIDXSPQuest.questID }], + users: [{ id: 1 }, { id: 2 }], + goals: [ + { goalID: "eg_goal_1" }, + { goalID: "eg_goal_2" }, + { goalID: "eg_goal_3" }, + { goalID: "eg_goal_4" }, + ], + parentQuestlines: [{ questlineID: "set_id" }], + }); + + t.end(); + }); + + t.test("Should return 404 if the requested quest doesn't exist.", async (t) => { + const res = await mockApi.get("/api/v1/games/iidx/SP/targets/quests/fake_quest"); + + t.equal(res.statusCode, 404); + + t.end(); + }); + + t.test("Should return 404 if the quest exists but for a different GPT.", async (t) => { + const res = await mockApi.get( + `/api/v1/games/iidx/DP/targets/quests/${TestingIIDXSPQuest.questID}`, + ); + + t.equal(res.statusCode, 404); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/targets/quests/router.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/targets/quests/router.ts new file mode 100644 index 000000000..3421a2f75 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/targets/quests/router.ts @@ -0,0 +1,99 @@ +import { SearchCollection } from "#lib/search/search"; +import { GetGoalsInQuest, GetGoalsInQuests } from "#lib/targets/quests"; +import db from "#services/mongo/db"; +import { IsString } from "#utils/misc"; +import { AssignToReqTachiData, GetGPT, GetTachiData } from "#utils/req-tachi-data"; +import { GetUsersWithIDs } from "#utils/user"; +import { type RequestHandler, Router } from "express"; + +const router: Router = Router({ mergeParams: true }); + +const ResolveQuestID: RequestHandler = async (req, res, next) => { + const { game, playtype } = GetGPT(req); + const questID = req.params.questID; + + const quest = await db.quests.findOne({ + questID, + game, + playtype, + }); + + if (!quest) { + return res.status(404).json({ + success: false, + description: `A quest with ID ${questID} doesn't exist.`, + }); + } + + AssignToReqTachiData(req, { questDoc: quest }); + + next(); +}; + +/** + * Search quests for this GPT. + * + * @param search - The query to search for. + * + * @name GET /api/v1/games/:game/:playtype/targets/quests + */ +router.get("/", async (req, res) => { + const { game, playtype } = GetGPT(req); + + if (!IsString(req.query.search)) { + return res.status(400).json({ + success: false, + description: `Invalid value for search.`, + }); + } + + const quests = await SearchCollection( + db.quests, + req.query.search, + "quests", + { game, playtype }, + 50, + ); + const goals = await GetGoalsInQuests(quests); + + return res.status(200).json({ + success: true, + description: `Returned ${quests.length} quests.`, + body: { quests, goals }, + }); +}); + +/** + * Retrieve information about this quest and who is subscribed to it. + * + * @name GET /api/v1/games/:game/:playtype/targets/quests/:questID + */ +router.get("/:questID", ResolveQuestID, async (req, res) => { + const quest = GetTachiData(req, "questDoc"); + + const questSubs = await db["quest-subs"].find({ + questID: quest.questID, + }); + + const users = await GetUsersWithIDs(questSubs.map((e) => e.userID)); + + const goals = await GetGoalsInQuest(quest); + + const parentQuestlines = await db.questlines.find({ + quests: quest.questID, + }); + + return res.status(200).json({ + success: true, + description: `Retrieved information about ${quest.name}.`, + body: { + quest, + questSubs, + users, + goals, + parentQuestlines, + }, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/targets/router.test.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/targets/router.test.ts new file mode 100644 index 000000000..1c5c4533c --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/targets/router.test.ts @@ -0,0 +1,102 @@ +import type { GoalSubscriptionDocument } from "tachi-common"; + +import db from "#services/mongo/db"; +import { mkFakeGoal, mkFakeGoalSub } from "#test-utils/misc"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { HC511UserGoal } from "#test-utils/test-data"; +import t from "tap"; + +t.test("GET /api/v1/games/:game/:playtype/targets/recently-achieved", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return some recently achieved goals.", async (t) => { + await db.goals.insert([ + mkFakeGoal({ goalID: "achieved" }), + mkFakeGoal({ goalID: "achieved_more_recently" }), + mkFakeGoal({ goalID: "achieved_instantly" }), + ]); + + await db["goal-subs"].insert([ + // not achieved + HC511UserGoal, + mkFakeGoalSub({ goalID: "achieved", achieved: true, timeAchieved: 1000 }), + mkFakeGoalSub({ goalID: "achieved_more_recently", achieved: true, timeAchieved: 2000 }), + mkFakeGoalSub({ + goalID: "achieved_instantly", + achieved: true, + timeAchieved: 1000, + wasInstantlyAchieved: true, + }), + ]); + + const res = await mockApi.get("/api/v1/games/iidx/SP/targets/recently-achieved"); + + t.equal(res.statusCode, 200); + + // Shouldn't have the unachieved goal, shouldn't have the instantly achieved goal. + // should also have them in the right order. + t.strictSame( + res.body.body.goalSubs.map((e: GoalSubscriptionDocument) => e.goalID), + ["achieved_more_recently", "achieved"], + ); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/games/:game/:playtype/targets/recently-raised", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return some recently interacted goals.", async (t) => { + await db.goals.insert([ + mkFakeGoal({ goalID: "interacted" }), + mkFakeGoal({ goalID: "interacted_more_recently" }), + mkFakeGoal({ goalID: "achieved" }), + mkFakeGoal({ goalID: "achieved_instantly" }), + ]); + + await db["goal-subs"].insert([ + // not achieved + HC511UserGoal, + mkFakeGoalSub({ goalID: "interacted", achieved: false, lastInteraction: 1000 }), + + // happened more recently + mkFakeGoalSub({ + goalID: "interacted_more_recently", + achieved: false, + lastInteraction: 2000, + }), + + // shouldnt be included -- just recently-raised. + mkFakeGoalSub({ + goalID: "achieved", + achieved: true, + lastInteraction: 1000, + }), + mkFakeGoalSub({ + goalID: "achieved_instantly", + achieved: true, + lastInteraction: 1000, + wasInstantlyAchieved: true, + }), + ]); + + const res = await mockApi.get("/api/v1/games/iidx/SP/targets/recently-raised"); + + t.equal(res.statusCode, 200); + + // Shouldn't have the uninteracted goal, shouldn't have the instantly achieved goal. + // should also have them in the right order. + t.strictSame( + res.body.body.goalSubs.map((e: GoalSubscriptionDocument) => e.goalID), + ["interacted_more_recently", "interacted"], + ); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/targets/router.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/targets/router.ts new file mode 100644 index 000000000..3fd4f95cf --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/_playtype/targets/router.ts @@ -0,0 +1,74 @@ +import { + GetRecentlyAchievedGoals, + GetRecentlyAchievedQuests, + GetRecentlyInteractedGoals, + GetRecentlyInteractedQuests, +} from "#utils/db"; +import { GetGPT } from "#utils/req-tachi-data"; +import { Router } from "express"; +import { FormatGameGroup } from "tachi-common"; + +import goalsRouter from "./goals/router"; +import questlineRouter from "./questlines/router"; +import questsRouter from "./quests/router"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Retrieve all of this game's recently achieved goals and quests. + * + * @name GET /api/v1/games/:game/:playtype/targets/recently-achieved + */ +router.get("/recently-achieved", async (req, res) => { + const { game, playtype } = GetGPT(req); + + const [{ goals, goalSubs }, { quests, questSubs }] = await Promise.all([ + GetRecentlyAchievedGoals({ game, playtype }), + GetRecentlyAchievedQuests({ game, playtype }), + ]); + + return res.status(200).json({ + success: true, + description: `Retrieved some recently achieved targets for ${FormatGameGroup(game, playtype)}`, + body: { + goals, + goalSubs, + quests, + questSubs, + }, + }); +}); + +/** + * Retrieve all of this game's recently interacted-with goals and quests. + * + * @name GET /api/v1/games/:game/:playtype/targets/recently-raised + */ +router.get("/recently-raised", async (req, res) => { + const { game, playtype } = GetGPT(req); + + const [{ goals, goalSubs }, { quests, questSubs }] = await Promise.all([ + GetRecentlyInteractedGoals({ game, playtype }), + GetRecentlyInteractedQuests({ game, playtype }), + ]); + + return res.status(200).json({ + success: true, + description: `Retrieved some recently interacted-with targets for ${FormatGameGroup( + game, + playtype, + )}`, + body: { + goals, + goalSubs, + quests, + questSubs, + }, + }); +}); + +router.use("/goals", goalsRouter); +router.use("/quests", questsRouter); +router.use("/questlines", questlineRouter); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/middleware.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/middleware.ts new file mode 100644 index 000000000..bbb3745b6 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/middleware.ts @@ -0,0 +1,28 @@ +import type { RequestHandler } from "express"; + +import { TachiConfig } from "#lib/setup/config"; +import { IsValidGame } from "#utils/misc"; +import { AssignToReqTachiData } from "#utils/req-tachi-data"; + +export const ValidateGameFromParam: RequestHandler = (req, res, next) => { + const game = req.params.game; + + if (game === undefined) { + throw new Error( + `Expected parameter of game when ValidateGameFromParam was called on ${req.originalUrl}.`, + ); + } + + if (!IsValidGame(game)) { + return res.status(400).json({ + success: false, + description: `Invalid/unsupported game ${ + req.params.game + } - Expected any of ${TachiConfig.GAMES.join(", ")}`, + }); + } + + AssignToReqTachiData(req, { game }); + + next(); +}; diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/router.test.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/router.test.ts new file mode 100644 index 000000000..e7fce157f --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/router.test.ts @@ -0,0 +1,23 @@ +import mockApi from "#test-utils/mock-api"; +import { GetGameGroupConfig } from "tachi-common"; +import t from "tap"; + +t.test("GET /api/v1/games/:game", (t) => { + t.test("Should parse the game from the header", async (t) => { + const res = await mockApi.get("/api/v1/games/iidx"); + + t.hasStrict(GetGameGroupConfig("iidx"), res.body.body); + + t.end(); + }); + + t.test("Should reject an unsupported game.", async (t) => { + const res = await mockApi.get("/api/v1/games/invalid_game"); + + t.equal(res.statusCode, 400); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/games/_game/router.ts b/typescript/server/src/server/router/api/v1postgres/games/_game/router.ts new file mode 100644 index 000000000..aa9f10ca8 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/_game/router.ts @@ -0,0 +1,29 @@ +import { GetTachiData } from "#utils/req-tachi-data"; +import { Router } from "express"; +import { GetGameGroupConfig } from "tachi-common"; + +import playtypeRouter from "./_playtype/router"; +import { ValidateGameFromParam } from "./middleware"; + +const router: Router = Router({ mergeParams: true }); + +router.use(ValidateGameFromParam); + +/** + * Returns the configuration for this game. + * + * @name GET /api/v1/games/:game + */ +router.get("/", (req, res) => { + const game = GetTachiData(req, "game"); + + return res.status(200).json({ + success: true, + description: `Returned information for ${game}`, + body: GetGameGroupConfig(game), + }); +}); + +router.use("/:playtype", playtypeRouter); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/games/router.test.ts b/typescript/server/src/server/router/api/v1postgres/games/router.test.ts new file mode 100644 index 000000000..88a2e6cf9 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/router.test.ts @@ -0,0 +1,27 @@ +import { TachiConfig } from "#lib/setup/config"; +import mockApi from "#test-utils/mock-api"; +import { GetGameGroupConfig } from "tachi-common"; +import t from "tap"; + +t.test("GET /api/v1/games", async (t) => { + // lets just run some basic tests that this contains all of our supported games + // and also returns configs properly. + const res = await mockApi.get("/api/v1/games"); + + t.strictSame(res.body.body.supportedGames, TachiConfig.GAMES); + + t.hasStrict( + { + ...res.body.body.configs.iidx, + // songData doesn't serialise nicely as it has functions on it. + songData: null, + }, + { + ...GetGameGroupConfig("iidx"), + songData: null, + }, + ); + t.equal(Object.keys(res.body.body.configs).length, TachiConfig.GAMES.length); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/games/router.ts b/typescript/server/src/server/router/api/v1postgres/games/router.ts new file mode 100644 index 000000000..b1b234901 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/games/router.ts @@ -0,0 +1,36 @@ +import { TachiConfig } from "#lib/setup/config"; +import { Router } from "express"; +import { GetGameGroupConfig } from "tachi-common"; + +import gameSpecificRoutes from "./@gameSpecificRoutes/router"; +import gameRouter from "./_game/router"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Declares the supported games for this version of tachi. + * Not sure if this endpoint has any purpose, to be honest. + * + * @name GET /api/v1/games + */ +router.get("/", (req, res) => { + // this line is a bit too 'smart' for its own good, but whatever. + const configs = Object.fromEntries(TachiConfig.GAMES.map((e) => [e, GetGameGroupConfig(e)])); + + return res.status(200).json({ + success: true, + description: `Returned support information for ${TachiConfig.GAMES.length} game(s).`, + body: { + supportedGames: TachiConfig.GAMES, + configs, + }, + }); +}); + +router.use("/:game", gameRouter); + +// These routes are mounted at /api/v1/games and add things that are game specific, +// such as /bms/7K/tables/sieglindeEC. Simple enough. +router.use("/", gameSpecificRoutes); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/import/router.test.ts b/typescript/server/src/server/router/api/v1postgres/import/router.test.ts new file mode 100644 index 000000000..39602518c --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/import/router.test.ts @@ -0,0 +1,393 @@ +import db from "#services/mongo/db"; +import { RequireAuthPerms } from "#test-utils/api-common"; +import { CreateFakeAuthCookie } from "#test-utils/fake-auth"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { + GetKTDataBuffer, + LoadTachiIIDXData, + TestingIIDXEamusementCSV26, + TestingIIDXEamusementCSV27, +} from "#test-utils/test-data"; +import t from "tap"; + +t.test("POST /api/v1/import/file", async (t) => { + const cookie = await CreateFakeAuthCookie(mockApi); + + t.beforeEach(ResetDBState); + + RequireAuthPerms("/api/v1/import/file", "submit_score", "POST"); + + t.test("file/eamusement-iidx-csv", (t) => { + t.beforeEach(LoadTachiIIDXData); + + t.test("Mini HV import", async (t) => { + const res = await mockApi + .post("/api/v1/import/file") + .set("Cookie", cookie) + .attach( + "scoreData", + GetKTDataBuffer("./eamusement-iidx-csv/small-hv-file.csv"), + "my_csv.csv", + ) + .field("importType", "file/eamusement-iidx-csv") + .field("playtype", "SP"); + + t.equal(res.body.success, true, "Should be successful."); + + t.equal(res.body.body.errors.length, 0, "Mini HV Import Should have 0 failed scores."); + + t.equal(res.body.body.scoreIDs.length, 2, "Should have 2 successful scores."); + + const scoreCount = await db.scores.find({ + scoreID: { $in: res.body.body.scoreIDs }, + }); + + t.equal( + scoreCount.length, + res.body.body.scoreIDs.length, + "All returned scoreIDs should be inserted to the DB.", + ); + + t.end(); + }); + + t.test("Valid Rootage CSV import", async (t) => { + const res = await mockApi + .post("/api/v1/import/file") + .set("Cookie", cookie) + .attach("scoreData", TestingIIDXEamusementCSV26, "my_csv.csv") + .field("importType", "file/eamusement-iidx-csv") + .field("playtype", "SP"); + + t.equal(res.body.success, true, "Should be successful."); + + t.equal(res.body.body.errors.length, 0, "Should have 0 failed scores."); + + const scoreCount = await db.scores.find({ + scoreID: { $in: res.body.body.scoreIDs }, + }); + + t.equal( + scoreCount.length, + res.body.body.scoreIDs.length, + "All returned scoreIDs should be inserted to the DB.", + ); + + t.end(); + }); + + t.test("Valid Heroic Verse CSV import", async (t) => { + const res = await mockApi + .post("/api/v1/import/file") + .set("Cookie", cookie) + .attach("scoreData", TestingIIDXEamusementCSV27, "my_csv.csv") + .field("importType", "file/eamusement-iidx-csv") + .field("playtype", "SP"); + + t.equal(res.body.success, true, "Should be successful."); + + t.strictSame(res.body.body.errors, [], "Should have 0 failed scores."); + + const scoreCount = await db.scores.find({ + scoreID: { $in: res.body.body.scoreIDs }, + }); + + t.equal( + scoreCount.length, + res.body.body.scoreIDs.length, + "All returned scoreIDs should be inserted to the DB.", + ); + + t.end(); + }); + + t.end(); + }); + + // thats right i literally just copied it + t.test("file/pli-iidx-csv", (t) => { + t.beforeEach(LoadTachiIIDXData); + + t.test("Mini HV import", async (t) => { + const res = await mockApi + .post("/api/v1/import/file") + .set("Cookie", cookie) + .attach( + "scoreData", + GetKTDataBuffer("./eamusement-iidx-csv/small-hv-file.csv"), + "my_csv.csv", + ) + .field("importType", "file/pli-iidx-csv") + .field("playtype", "SP"); + + t.equal(res.body.success, true, "Should be successful."); + + t.equal(res.body.body.errors.length, 0, "Mini HV Import Should have 0 failed scores."); + + t.equal(res.body.body.scoreIDs.length, 2, "Should have 2 successful scores."); + + const scoreCount = await db.scores.find({ + scoreID: { $in: res.body.body.scoreIDs }, + }); + + t.equal( + scoreCount.length, + res.body.body.scoreIDs.length, + "All returned scoreIDs should be inserted to the DB.", + ); + + t.end(); + }); + + t.test("Valid Rootage CSV import", async (t) => { + const res = await mockApi + .post("/api/v1/import/file") + .set("Cookie", cookie) + .attach("scoreData", TestingIIDXEamusementCSV26, "my_csv.csv") + .field("importType", "file/pli-iidx-csv") + .field("playtype", "SP"); + + t.equal(res.body.success, true, "Should be successful."); + + t.equal(res.body.body.errors.length, 0, "Should have 0 failed scores."); + + const scoreCount = await db.scores.find({ + scoreID: { $in: res.body.body.scoreIDs }, + }); + + t.equal( + scoreCount.length, + res.body.body.scoreIDs.length, + "All returned scoreIDs should be inserted to the DB.", + ); + + t.end(); + }); + + t.test("Valid Heroic Verse CSV import", async (t) => { + const res = await mockApi + .post("/api/v1/import/file") + .set("Cookie", cookie) + .attach("scoreData", TestingIIDXEamusementCSV27, "my_csv.csv") + .field("importType", "file/pli-iidx-csv") + .field("playtype", "SP"); + + t.equal(res.body.success, true, "Should be successful."); + + t.equal(res.body.body.errors.length, 0, "Should have 0 failed scores."); + + const scoreCount = await db.scores.find({ + scoreID: { $in: res.body.body.scoreIDs }, + }); + + t.equal( + scoreCount.length, + res.body.body.scoreIDs.length, + "All returned scoreIDs should be inserted to the DB.", + ); + + t.end(); + }); + + t.end(); + }); + + t.test("file/batch-manual", (t) => { + t.test("Empty import", async (t) => { + const res = await mockApi + .post("/api/v1/import/file") + .set("Cookie", cookie) + .attach( + "scoreData", + GetKTDataBuffer("./batch-manual/empty-file.json"), + "empty-file.json", + ) + .field("importType", "file/batch-manual"); + + t.equal(res.body.success, true, "Should be successful."); + + t.equal(res.body.body.errors.length, 0, "Import Should have 0 failed scores."); + + t.equal(res.body.body.scoreIDs.length, 0, "Should have 0 successful scores."); + + const scoreCount = await db.scores.find({ + scoreID: { $in: res.body.body.scoreIDs }, + }); + + t.equal( + scoreCount.length, + res.body.body.scoreIDs.length, + "All returned scoreIDs should be inserted to the DB.", + ); + + t.end(); + }); + + t.test("Invalid JSON", async (t) => { + const res = await mockApi + .post("/api/v1/import/file") + .set("Cookie", cookie) + .attach("scoreData", Buffer.from("{invalid JSON")) + .field("importType", "file/batch-manual"); + + t.equal(res.body.success, false, "Should not be successful."); + + t.equal(res.statusCode, 400); + + t.end(); + }); + + t.test("Single import", async (t) => { + const res = await mockApi + .post("/api/v1/import/file") + .set("Cookie", cookie) + .attach( + "scoreData", + GetKTDataBuffer("./batch-manual/small-file.json"), + "small-file.json", + ) + .field("importType", "file/batch-manual"); + + t.equal(res.body.success, true, "Should be successful."); + + t.equal(res.body.body.errors.length, 0, "Import Should have 0 failed scores."); + + t.equal(res.body.body.scoreIDs.length, 1, "Should have 1 successful score."); + + const scoreCount = await db.scores.find({ + scoreID: { $in: res.body.body.scoreIDs }, + }); + + t.equal( + scoreCount.length, + res.body.body.scoreIDs.length, + "All returned scoreIDs should be inserted to the DB.", + ); + + t.end(); + }); + + t.test("Single sdvxInGameID import", async (t) => { + const res = await mockApi + .post("/api/v1/import/file") + .set("Cookie", cookie) + .attach( + "scoreData", + GetKTDataBuffer("./batch-manual/sdvx-in-game-id.json"), + "small-file.json", + ) + .field("importType", "file/batch-manual"); + + t.equal(res.body.success, true, "Should be successful."); + + t.equal(res.body.body.errors.length, 0, "Import Should have 0 failed scores."); + + t.equal(res.body.body.scoreIDs.length, 1, "Should have 1 successful score."); + + const scoreCount = await db.scores.find({ + scoreID: { $in: res.body.body.scoreIDs }, + }); + + t.equal( + scoreCount.length, + res.body.body.scoreIDs.length, + "All returned scoreIDs should be inserted to the DB.", + ); + + t.end(); + }); + + t.end(); + }); + + t.skip("file/solid-state-squad", (t) => { + t.beforeEach(LoadTachiIIDXData); + + t.test("Large Import", async (t) => { + const res = await mockApi + .post("/api/v1/import/file") + .set("Cookie", cookie) + .attach("scoreData", GetKTDataBuffer("./s3/large-example.xml"), "large.xml") + .field("importType", "file/solid-state-squad"); + + t.equal(res.body.success, true, "Should be successful"); + t.equal(res.body.body.scoreIDs.length, null, "Should parse N scores."); + + t.end(); + }); + + t.end(); + }); + + t.end(); +}); + +t.test("POST /api/v1/import/orphans", async (t) => { + const cookie = await CreateFakeAuthCookie(mockApi); + + t.beforeEach(ResetDBState); + + t.test("Should force a reprocessing of orphan scores.", async (t) => { + await db["orphan-scores"].insert([ + { + userID: 1, + timeInserted: 1000, + orphanID: "asdf", + importType: "ir/direct-manual", + errMsg: "foo", + context: { + game: "iidx", + playtype: "SP", + service: "foo", + version: null, + }, + data: { + score: 500, + lamp: "HARD CLEAR", + matchType: "songTitle", + identifier: "5.1.1.", + difficulty: "ANOTHER", + }, + game: "iidx", + }, + { + userID: 1, + timeInserted: 1000, + orphanID: "asdf2", + importType: "ir/direct-manual", + errMsg: "foo", + context: { + game: "iidx", + playtype: "SP", + service: "foo", + version: null, + }, + data: { + score: 500, + lamp: "HARD CLEAR", + matchType: "songTitle", + identifier: "TITLE NOBODY WILL USE", + difficulty: "ANOTHER", + }, + game: "iidx", + }, + ]); + + const res = await mockApi.post("/api/v1/import/orphans").set("Cookie", cookie); + + t.equal(res.statusCode, 200, "Should return 200."); + + t.equal(res.body.body.success, 1, "Should successfully reprocess one orphan."); + t.equal(res.body.body.processed, 2, "Should reprocess two orphans."); + t.equal(res.body.body.failed, 1, "Should fail in de-orphaning one orphan."); + + const dbCount = await db["orphan-scores"].count({}); + + t.equal(dbCount, 1, "Should only leave one orphan-score in the database."); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/import/router.ts b/typescript/server/src/server/router/api/v1postgres/import/router.ts new file mode 100644 index 000000000..2cc2974bb --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/import/router.ts @@ -0,0 +1,186 @@ +import type { ScoreImportJobData } from "#lib/score-import/worker/types"; +import type { APIImportTypes, FileUploadImportTypes } from "tachi-common"; + +import { SIXTEEN_MEGABTYES } from "#lib/constants/filesize"; +import { SYMBOL_TACHI_API_AUTH } from "#lib/constants/tachi"; +import { log } from "#lib/log/log.js"; +import { ExpressWrappedScoreImportMain } from "#lib/score-import/framework/express-wrapper"; +import { DeorphanScores } from "#lib/score-import/framework/orphans/orphans"; +import { MakeScoreImport } from "#lib/score-import/framework/score-import"; +import { ServerConfig, TachiConfig } from "#lib/setup/config"; +import { RequirePermissions } from "#server/middleware/auth"; +import { CreateMulterSingleUploadMiddleware } from "#server/middleware/multer-upload"; +import prValidate from "#server/middleware/prudence-validate"; +import { ScoreImportRateLimiter } from "#server/middleware/rate-limiter"; +import { Random20Hex } from "#utils/misc"; +import { FormatUserDoc, GetUserWithIDGuaranteed } from "#utils/user"; +import { Router } from "express"; +import { p } from "prudence"; + +const router: Router = Router({ mergeParams: true }); + +const ParseMultipartScoredata = CreateMulterSingleUploadMiddleware("scoreData", SIXTEEN_MEGABTYES); + +const fileImportTypes = TachiConfig.IMPORT_TYPES.filter((e) => e.startsWith("file/")); +const apiImportTypes = TachiConfig.IMPORT_TYPES.filter((e) => e.startsWith("api/")); + +/** + * Import scores from a file. Expects the post request to be multipart, and to provide a scoreData file. + * + * @param importType - The import type for this file. + * @param file - The actual file. Should be passed as multipart. + * + * @name POST /api/v1/import/file + */ +router.post( + "/file", + RequirePermissions("submit_score"), + ScoreImportRateLimiter, + ParseMultipartScoredata, + prValidate( + { + importType: p.isIn(fileImportTypes), + }, + {}, + { allowExcessKeys: true }, + ), + async (req, res) => { + if (!req.file) { + return res.status(400).json({ + success: false, + description: `No file provided.`, + }); + } + + const importType = req.safeBody.importType as FileUploadImportTypes; + + const userIntent = req.header("X-User-Intent")?.toLowerCase() === "true"; + + if (ServerConfig.USE_EXTERNAL_SCORE_IMPORT_WORKER) { + const importID = Random20Hex(); + + const job: ScoreImportJobData = { + importID, + userID: req[SYMBOL_TACHI_API_AUTH].userID!, + userIntent, + importType, + parserArguments: [req.file, req.safeBody], + }; + + // Fire the score import, but make no guarantees about its state. + void MakeScoreImport(job); + + return res.status(202).json({ + success: true, + description: + "Import loaded into queue. You can poll the provided URL for information on when its complete.", + body: { + url: `${ServerConfig.OUR_URL}/api/v1/imports/${importID}/poll-status`, + importID, + }, + }); + } + + // Fire the score import and wait for it to finish! + const importResponse = await ExpressWrappedScoreImportMain( + req[SYMBOL_TACHI_API_AUTH].userID!, + userIntent, + importType, + [req.file, req.safeBody], + ); + + return res.status(importResponse.statusCode).json(importResponse.body); + }, +); + +/** + * Import scores from another API. This typically will perform a full sync. + * @name POST /api/v1/import/from-api + */ +router.post( + "/from-api", + RequirePermissions("submit_score"), + prValidate( + { + importType: p.isIn(apiImportTypes), + }, + {}, + { allowExcessKeys: true }, + ), + async (req, res) => { + const importType = req.safeBody.importType as APIImportTypes; + + const importID = Random20Hex(); + + const userID = req[SYMBOL_TACHI_API_AUTH].userID!; + + const userIntent = req.header("X-User-Intent")?.toLowerCase() === "true"; + + if (ServerConfig.USE_EXTERNAL_SCORE_IMPORT_WORKER) { + const job: ScoreImportJobData = { + importID, + userID, + userIntent, + importType, + parserArguments: [userID], + }; + + // Fire the score import, but make no guarantees about its state. + void MakeScoreImport(job); + + return res.status(202).json({ + success: true, + description: + "Import loaded into queue. You can poll the provided URL for information on when its complete.", + body: { + url: `${ServerConfig.OUR_URL}/api/v1/imports/${importID}/poll-status`, + importID, + }, + }); + } + + // Fire the score import and wait for it to finish! + const importResponse = await ExpressWrappedScoreImportMain( + userID, + userIntent, + importType, + [userID], + ); + + return res.status(importResponse.statusCode).json(importResponse.body); + }, +); + +/** + * Force Tachi to reprocess your orphaned scores. This is automatically done + * daily, but this endpoint allows users to speed that up. + * + * @name POST /api/v1/import/orphans + */ +router.post("/orphans", RequirePermissions("submit_score"), async (req, res) => { + const userDoc = await GetUserWithIDGuaranteed(req[SYMBOL_TACHI_API_AUTH].userID!); + + log.info(`User ${FormatUserDoc(userDoc)} forced an orphan sync.`); + + const { processed, removed, failed, success } = await DeorphanScores( + { userID: userDoc.id }, + log, + ); + + log.info(`Finished attempting deorphaning.`); + + log.info(`Success: ${success} | Failed ${failed} | Removed ${removed}.`); + + return res.status(200).json({ + success: true, + description: `Reprocessed ${processed} orphan scores.`, + body: { + processed, + failed, + success, + removed, + }, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/imports/middleware.ts b/typescript/server/src/server/router/api/v1postgres/imports/middleware.ts new file mode 100644 index 000000000..e4a1b2670 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/imports/middleware.ts @@ -0,0 +1,49 @@ +import type { RequestHandler } from "express"; + +import { SYMBOL_TACHI_API_AUTH } from "#lib/constants/tachi"; +import { log } from "#lib/log/log.js"; +import db from "#services/mongo/db"; +import { AssignToReqTachiData, GetTachiData } from "#utils/req-tachi-data"; +import { IsRequesterAdmin } from "#utils/user"; + +export const GetImportFromParam: RequestHandler = async (req, res, next) => { + const importDoc = await db.imports.findOne({ importID: req.params.importID }); + + if (!importDoc) { + return res.status(404).json({ + success: false, + description: `This import does not exist.`, + }); + } + + AssignToReqTachiData(req, { importDoc }); + + next(); +}; + +export const RequireOwnershipOfImportOrAdmin: RequestHandler = async (req, res, next) => { + const importDoc = GetTachiData(req, "importDoc"); + const userID = req[SYMBOL_TACHI_API_AUTH].userID; + + if (userID === null) { + return res.status(401).json({ + success: false, + description: `You are not authorised as anyone, and this endpoint requires us to know who you are.`, + }); + } + + if (importDoc.userID !== userID) { + if (await IsRequesterAdmin(req[SYMBOL_TACHI_API_AUTH])) { + log.info(`Admin ${userID} interacted with someone elses import.`); + next(); + return; + } + + return res.status(403).json({ + success: false, + description: `You are not authorised to perform this action.`, + }); + } + + next(); +}; diff --git a/typescript/server/src/server/router/api/v1postgres/imports/router.test.ts b/typescript/server/src/server/router/api/v1postgres/imports/router.test.ts new file mode 100644 index 000000000..f953744e4 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/imports/router.test.ts @@ -0,0 +1,166 @@ +import db from "#services/mongo/db"; +import { CreateFakeAuthCookie } from "#test-utils/fake-auth"; +import { mkFakeImport } from "#test-utils/misc"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { FakeImport } from "#test-utils/test-data"; +import { UserAuthLevels } from "tachi-common"; +import t from "tap"; + +t.test("GET /api/v1/imports/:importID", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(() => db.imports.insert(FakeImport)); + + t.test("Should return the import at this ID.", async (t) => { + const res = await mockApi.get(`/api/v1/imports/${FakeImport.importID}`); + + t.equal(res.statusCode, 200, "Should return 200."); + + t.hasStrict( + res.body.body, + { + user: { + id: 1, + }, + scores: [ + { + scoreID: FakeImport.scoreIDs[0], + }, + ], + charts: [ + { + chartID: res.body.body.scores[0].chartID, + }, + ], + songs: [ + { + id: res.body.body.scores[0].songID, + }, + ], + import: { + importID: FakeImport.importID, + }, + }, + "Should return the import and some info about it.", + ); + + t.end(); + }); + + t.test("Should return 404 if the import doesn't exist.", async (t) => { + const res = await mockApi.get("/api/v1/imports/bad-import"); + + t.equal(res.statusCode, 404, "Should return 404."); + + t.end(); + }); + + t.end(); +}); + +t.test("POST /api/v1/imports/:importID/revert", async (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(() => db.imports.insert(FakeImport)); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should revert the import at this ID.", async (t) => { + const res = await mockApi + .post(`/api/v1/imports/${FakeImport.importID}/revert`) + .set("Cookie", cookie); + + t.equal(res.statusCode, 200, "Should return 200."); + + t.strictSame(res.body.body, {}, "The response body should be empty."); + + t.resolveMatch( + db.scores.findOne({ scoreID: FakeImport.scoreIDs[0] }), + + // @ts-expect-error https://github.com/DefinitelyTyped/DefinitelyTyped/pull/60020 + null, + "The scores that were part of this import should be deleted.", + ); + + t.end(); + }); + + t.test("Should return 404 if the import doesn't exist.", async (t) => { + const res = await mockApi.post(`/api/v1/imports/doesnt-exist/revert`).set("Cookie", cookie); + + t.equal(res.statusCode, 404, "Should return 404."); + + t.end(); + }); + + t.test("Should return 401 if the user isn't authed.", async (t) => { + const res = await mockApi.post(`/api/v1/imports/${FakeImport.importID}/revert`); + + t.equal(res.statusCode, 401, "Should return 401."); + + t.end(); + }); + + t.test("Should return 403 if the user is authed as someone else.", async (t) => { + await db.users.update( + { + id: 1, + }, + { + $set: { authLevel: UserAuthLevels.USER }, + }, + ); + + const someoneElsesImport = mkFakeImport({ userID: 2, importID: "someone_elses" }); + + await db.imports.insert(someoneElsesImport); + + const res = await mockApi + .post(`/api/v1/imports/${someoneElsesImport.importID}/revert`) + .set("Cookie", cookie); + + t.equal(res.statusCode, 403, "Should return 403."); + + t.end(); + }); + + t.test( + "Should allow reverting another users import if the requester is an admin.", + async (t) => { + await db.users.update( + { + id: 1, + }, + { + $set: { authLevel: UserAuthLevels.ADMIN }, + }, + ); + + const someoneElsesImport = mkFakeImport({ userID: 2, importID: "someone_elses" }); + + await db.imports.insert(someoneElsesImport); + + const res = await mockApi + .post(`/api/v1/imports/${someoneElsesImport.importID}/revert`) + .set("Cookie", cookie); + + t.equal(res.statusCode, 200, "Should return 200."); + + t.strictSame(res.body.body, {}, "The response body should be empty."); + + t.resolveMatch( + db.scores.findOne({ scoreID: FakeImport.scoreIDs[0] }), + + // @ts-expect-error https://github.com/DefinitelyTyped/DefinitelyTyped/pull/60020 + null, + "The scores that were part of this import should be deleted.", + ); + + t.end(); + }, + ); + + t.end(); +}); + +t.todo("GET /api/v1/imports"); +t.todo("GET /api/v1/imports/failed"); diff --git a/typescript/server/src/server/router/api/v1postgres/imports/router.ts b/typescript/server/src/server/router/api/v1postgres/imports/router.ts new file mode 100644 index 000000000..fdc08a5ee --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/imports/router.ts @@ -0,0 +1,368 @@ +import type { ScoreImportWorkerReturns } from "#lib/score-import/worker/types"; +import type { FilterQuery } from "mongodb"; +import type { ImportTrackerDocument, ImportTypes } from "tachi-common"; + +import { JOB_RETRY_COUNT } from "#lib/constants/tachi"; +import { RevertImport } from "#lib/imports/imports"; +import { log } from "#lib/log/log.js"; +import ScoreImportQueue, { ScoreImportQueueEvents } from "#lib/score-import/worker/queue"; +import { ServerConfig, TachiConfig } from "#lib/setup/config"; +import { RequirePermissions } from "#server/middleware/auth"; +import prValidate from "#server/middleware/prudence-validate"; +import db from "#services/mongo/db"; +import { GetRelevantSongsAndCharts } from "#utils/db"; +import { DeleteUndefinedProps } from "#utils/misc"; +import { GetTachiData } from "#utils/req-tachi-data"; +import { GetUsersWithIDs, GetUserWithID } from "#utils/user"; +import { Router } from "express"; +import { p } from "prudence"; + +import { GetImportFromParam, RequireOwnershipOfImportOrAdmin } from "./middleware"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Query imports. Returns the 500 most recently-finished imports. + * + * @param importType - Optionally, limit the returns to only this import type. + * @param userIntent - Optionally, limit returns to only those with or without userIntent. + * + * @name GET /api/v1/imports + */ +router.get( + "/", + prValidate({ + importType: p.optional(p.isIn(TachiConfig.IMPORT_TYPES)), + userIntent: p.optional(p.isIn("true", "false")), + }), + async (req, res) => { + const importType = req.query.importType as ImportTypes | undefined; + + // all query input ends up as strings, so we need convert it into an optional + // boolean + const userIntent = + req.query.userIntent === undefined ? undefined : req.query.userIntent === "true"; + + const query = { + userIntent, + importType, + }; + + DeleteUndefinedProps(query); + + const imports = await db.imports.find(query, { + sort: { timeFinished: -1 }, + limit: 500, + }); + + // mayaswell attach the users for better UI. + const users = await GetUsersWithIDs(imports.map((e) => e.userID)); + + return res.status(200).json({ + success: true, + description: `Found ${imports.length} imports.`, + body: { + imports, + users, + }, + }); + }, +); + +/** + * Query *failed* imports. Returns the 500 most recently-finished imports. + * + * This is done by checking import-trackers for imports that ended with a thrown + * error. An import is considered 'failed' if ScoreImportFatalError is thrown at any + * point during the process, or if any unknown error is thrown. + * + * @param importType - Optionally, limit the returns to only this import type. + * @param userIntent - Optionally, limit returns to only those with or without userIntent. + * + * @name GET /api/v1/imports/failed + */ +router.get( + "/failed", + prValidate({ + importType: p.optional(p.isIn(TachiConfig.IMPORT_TYPES)), + userIntent: p.optional(p.isIn("true", "false")), + }), + async (req, res) => { + const importType = req.query.importType as ImportTypes | undefined; + + // all query input ends up as strings, so we need convert it into an optional + // boolean + const userIntent = + req.query.userIntent === undefined ? undefined : req.query.userIntent === "true"; + + const query: FilterQuery = { + userIntent, + importType, + type: "FAILED", + }; + + DeleteUndefinedProps(query); + + const trackers = await db["import-trackers"].find(query, { + sort: { timeStarted: -1 }, + limit: 500, + }); + + // mayaswell attach the users for better UI. + const users = await GetUsersWithIDs(trackers.map((e) => e.userID)); + + return res.status(200).json({ + success: true, + description: `Found ${trackers.length} failed imports.`, + body: { + failedImports: trackers, + users, + }, + }); + }, +); + +/** + * Retrieve an import with this ID. + * + * @name GET /api/v1/imports/:importID + */ +router.get("/:importID", GetImportFromParam, async (req, res) => { + const importDoc = GetTachiData(req, "importDoc"); + + const scores = await db.scores.find({ + scoreID: { $in: importDoc.scoreIDs }, + }); + + const { songs, charts } = await GetRelevantSongsAndCharts(scores, importDoc.game); + + const sessions = await db.sessions.find({ + sessionID: { $in: importDoc.createdSessions.map((e) => e.sessionID) }, + }); + + const user = await GetUserWithID(importDoc.userID); + + if (!user) { + log.error(`User ${importDoc.userID} doesn't exist, yet has a session?`); + return res.status(500).json({ + success: false, + description: `An internal server error has occured.`, + }); + } + + return res.status(200).json({ + success: true, + description: `Returned info about this session.`, + body: { + scores, + songs, + charts, + sessions, + import: importDoc, + user, + }, + }); +}); + +/** + * Delete this import and revert it from having ever happened. This un-imports all + * of the scores that were imported. + * + * Must be a request from the owner of this import. + * + * Counterintuitively, this endpoint requires the "delete_score" permission. This is + * because reverting an import is actually just deleting all of its scores. + * + * @name POST /api/v1/imports/:importID/revert + */ +router.post( + "/:importID/revert", + GetImportFromParam, + RequireOwnershipOfImportOrAdmin, + RequirePermissions("delete_score"), + async (req, res) => { + const importDoc = GetTachiData(req, "importDoc"); + + const k = await RevertImport(importDoc); + + if (k !== null) { + return res.status(409).json({ + success: false, + description: `You already have an import or a revert ongoing.`, + }); + } + + return res.status(200).json({ + success: true, + description: `Reverted import.`, + body: {}, + }); + }, +); + +// Finding jobs is slightly harder than just doing a key lookup, because of retrying. +async function FindImportJob(importID: string) { + const possibleImportIDs = []; + + for (let i = 1; i <= JOB_RETRY_COUNT; i++) { + possibleImportIDs.push(`${importID}:TRY${i}`); + } + + try { + // Note that instead of the cleaner await-inside-for here, we parallelise this + // for performance. + // Just for scalings sake. + const maybeJob = ( + await Promise.all(possibleImportIDs.map((i) => ScoreImportQueue.getJob(i))) + ).find((k) => k); + + return maybeJob; + } catch (err) { + return undefined; + } +} + +/** + * Retrieve the status of an ongoing import. + * If the import has been finalised and was successful, return 200. + * + * If the import is ongoing, return its progress. + * + * If the import was never ongoing, return 404. + * + * If the import was finalised and was unsuccessful (i.e. threw a fatal error) + * return its error information in expressified form. + * + * @name GET /api/v1/import/:importID/poll-status + */ +router.get("/:importID/poll-status", async (req, res) => { + if (!ServerConfig.USE_EXTERNAL_SCORE_IMPORT_WORKER) { + return res.status(501).json({ + success: false, + description: `${TachiConfig.NAME} does not use an external score import worker. Polling imports is not possible. This import may be ongoing, or it may have never occured.`, + }); + } + + const importDoc = await db.imports.findOne({ importID: req.params.importID }); + + if (importDoc) { + return res.status(200).json({ + success: true, + description: `Import was completed!`, + body: { + importStatus: "completed", + import: importDoc, + }, + }); + } + + const job = await FindImportJob(req.params.importID); + + if (!job) { + const tracker = await db["import-trackers"].findOne({ + importID: req.params.importID, + }); + + if (!tracker) { + return res.status(404).json({ + success: false, + description: `There is no ongoing import here.`, + }); + } + + // the user has requested the status of the import before the job has even + // been sent to redis. This is rare, but prevents a race condition of saying + // that an import is not ongoing when it is. + + switch (tracker.type) { + case "ONGOING": + return res.status(200).json({ + success: true, + description: `Import is ongoing.`, + body: { + importStatus: "ongoing", + progress: 0, + }, + }); + case "FAILED": + return res.status(tracker.error.statusCode ?? 500).json({ + success: false, + description: tracker.error.message, + }); + default: + throw new Error( + // @ts-expect-error shouldn't happen + `Unknown tracker type ${tracker.type}, expected ONGOING or FAILED.`, + ); + } + } + + let isFailed; + + try { + isFailed = await job.isFailed(); + } catch (err) { + log.info(`Failed to read job: ${err}`); + isFailed = true; + } + + let isCompleted; + + try { + isCompleted = await job.isCompleted(); + } catch (err) { + log.info(`Failed to read job: ${err}`); + isCompleted = false; + } + + // job.isFailed() actually means a critical error has occured. + // As in, an unhandled exception was thrown. + if (isFailed) { + log.error({ job }, "Internal Server Error with job?"); + + return res.status(500).json({ + success: false, + description: `An internal service error has occured with this import. This has been reported!`, + }); + } else if (isCompleted) { + const content = (await job.waitUntilFinished( + ScoreImportQueueEvents, + )) as ScoreImportWorkerReturns; + + // Since job.isFailed() is for whether a job had a fatal exception + // or not. We still want to check whether a job failed from say, + // nonsense user input. + // As such, if content.success == true, then the import was + // successful. + // Else, it was a "score import fatal error", which means the user + // screwed something up and we had to bail on the import. + if (content.success) { + return res.status(200).json({ + success: true, + description: `Import was completed!`, + body: { + importStatus: "completed", + import: content.importDocument, + }, + }); + } + + return res.status(content.statusCode).json({ + success: false, + description: content.description, + }); + } + + const progress = job.progress; + + return res.status(200).json({ + success: true, + description: `Import is ongoing.`, + body: { + importStatus: "ongoing", + progress: progress === 0 ? { description: "Starting up import." } : progress, + }, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/oauth/router.test.ts b/typescript/server/src/server/router/api/v1postgres/oauth/router.test.ts new file mode 100644 index 000000000..a066e0e55 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/oauth/router.test.ts @@ -0,0 +1,99 @@ +import db from "#services/mongo/db"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import t from "tap"; + +t.test("POST /api/v1/oauth/token", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should grant and create an api token.", async (t) => { + const res = await mockApi.post(`/api/v1/oauth/token`).send({ + client_id: "OAUTH2_CLIENT_ID", + client_secret: "OAUTH2_CLIENT_SECRET", + grant_type: "authorization_code", + redirect_uri: "https://example.com/callback", + code: "AUTH_CODE", + }); + + t.equal(res.statusCode, 200); + + const tokenDoc = await db["api-tokens"].findOne({ + token: res.body.body.token, + }); + + t.not(tokenDoc, null); + t.equal(tokenDoc?.userID, 1); + t.equal(tokenDoc?.fromAPIClient, "OAUTH2_CLIENT_ID"); + t.strictSame( + tokenDoc?.permissions, + { + customise_profile: true, + }, + "Should assign the permissions this client has configured.", + ); + + const exists = await db["oauth2-auth-codes"].findOne({ code: "AUTH_CODE" }); + + t.equal(exists, null, "Should remove the code from the database after being used."); + + t.end(); + }); + + t.test("Requires a valid code.", async (t) => { + const res = await mockApi.post(`/api/v1/oauth/token`).send({ + client_id: "OAUTH2_CLIENT_ID", + client_secret: "OAUTH2_CLIENT_SECRET", + grant_type: "authorization_code", + redirect_uri: "https://example.com/callback", + code: "invalidcode", + }); + + t.equal(res.statusCode, 404); + + t.end(); + }); + + t.test("Requires a valid clientID.", async (t) => { + const res = await mockApi.post(`/api/v1/oauth/token`).send({ + client_id: "INVALID_CLIENT_ID", + client_secret: "OAUTH2_CLIENT_SECRET", + grant_type: "authorization_code", + redirect_uri: "https://example.com/callback", + code: "AUTH_CODE", + }); + + t.equal(res.statusCode, 404); + + t.end(); + }); + + t.test("Requires a valid client secret.", async (t) => { + const res = await mockApi.post(`/api/v1/oauth/token`).send({ + client_id: "OAUTH2_CLIENT_ID", + client_secret: "INVALID_SECRET", + grant_type: "authorization_code", + redirect_uri: "https://example.com/callback", + code: "AUTH_CODE", + }); + + t.equal(res.statusCode, 403); + + t.end(); + }); + + t.test("Requires an identical redirect_uri.", async (t) => { + const res = await mockApi.post(`/api/v1/oauth/token`).send({ + client_id: "OAUTH2_CLIENT_ID", + client_secret: "OAUTH2_CLIENT_SECRET", + grant_type: "authorization_code", + redirect_uri: "https://invalid.example.com/callback", + code: "AUTH_CODE", + }); + + t.equal(res.statusCode, 400); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/oauth/router.ts b/typescript/server/src/server/router/api/v1postgres/oauth/router.ts new file mode 100644 index 000000000..e5a595d46 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/oauth/router.ts @@ -0,0 +1,128 @@ +import prValidate from "#server/middleware/prudence-validate"; +import db from "#services/mongo/db"; +import { Random20Hex } from "#utils/misc"; +import { Router } from "express"; +import { p } from "prudence"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Converts an auth code into a valid API key that is returned. + * + * @note The params here are deliberately snake cased as that's what + * the digitalocean examples for oauth2 do. I have no idea whether that's + * part of the spec or not, but it probably is. + * + * @param client_id - The id for the client requesting a token. + * @param client_secret - The secret for the client. + * @param grant_type - Only exactly "authorization_code" is supported at the moment. + * @param redirect_uri - Must be the exact redirectUri registered with this client. + * @param code - The code to convert into an API token. + * + * @name POST /api/v1/oauth/token + */ +router.post( + "/token", + prValidate({ + client_id: "string", + client_secret: "string", + grant_type: p.is("authorization_code"), + redirect_uri: "string", + code: "string", + }), + async (req, res) => { + const body = req.safeBody as { + client_id: string; + client_secret: string; + code: string; + grant_type: "authorization_code"; + redirect_uri: string; + }; + + const client = await db["api-clients"].findOne({ + clientID: body.client_id, + }); + + if (!client) { + return res.status(404).json({ + success: false, + description: `This client does not exist.`, + }); + } + + if (client.clientSecret !== body.client_secret) { + return res.status(403).json({ + success: false, + description: `Invalid secret.`, + }); + } + + // I honest to god have no idea what the point of this check is + // but it's part of the oauth spec. + if (client.redirectUri !== body.redirect_uri) { + return res.status(400).json({ + success: false, + description: `This redirect_uri does not match with your registered client redirect_uri ${client.redirectUri}.`, + }); + } + + const codeDoc = await db["oauth2-auth-codes"].findOne({ code: body.code }); + + if (!codeDoc) { + return res.status(404).json({ + success: false, + description: `This code does not exist.`, + }); + } + + // don't let people auth with the same code multiple times. + await db["oauth2-auth-codes"].remove({ code: body.code }); + + const apiDoc = { + userID: codeDoc.userID, + token: Random20Hex(), + identifier: `${client.name} Token`, + + // converts ["a","b"] to {a: true, b: true}. + permissions: Object.fromEntries(client.requestedPermissions.map((e) => [e, true])), + fromAPIClient: client.clientID, + }; + + // Now we can actually register the api key (lol) + await db["api-tokens"].insert(apiDoc); + + return res.status(200).json({ + success: true, + description: `Successfully authenticated.`, + body: apiDoc, + }); + }, +); + +/** + * Creates an authorization code for this user (inferred from session). + * + * @name POST /api/v1/oauth/create-code + */ +router.post("/create-code", async (req, res) => { + if (!req.session.tachi?.user) { + return res.status(401).json({ + success: false, + description: `You are not authenticated.`, + }); + } + + const code = Random20Hex(); + + const doc = { code, userID: req.session.tachi.user.id, createdOn: Date.now() }; + + await db["oauth2-auth-codes"].insert(doc); + + return res.status(200).json({ + success: true, + description: `Successfully created code.`, + body: doc, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/router.test.ts b/typescript/server/src/server/router/api/v1postgres/router.test.ts new file mode 100644 index 000000000..f75b352a5 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/router.test.ts @@ -0,0 +1,39 @@ +import { ClearTestingRateLimitCache } from "#server/middleware/rate-limiter"; +import mockApi from "#test-utils/mock-api"; +import t from "tap"; + +// just a rudimentary test for rate-limiting. We fire 150 requests at GET /api/v1 +// (which does a server status check) +// and then check any of them return 429. +t.test("Rate Limiting Test", async (t) => { + ClearTestingRateLimitCache(); + + const promises = []; + + // default rate limit is 500, so lets go a bit over + for (let i = 0; i < 520; i++) { + promises.push(mockApi.get("/api/v1/status")); + } + + const res = await Promise.all(promises); + + const rateLimited = res.filter((e) => e.statusCode === 429); + + t.ok(rateLimited.length > 0, "Some requests should be rate limited."); + + t.end(); +}); + +t.test("404 Handler", async (t) => { + ClearTestingRateLimitCache(); + + const res = await mockApi.get("/api/v1/invalid_route_that_will_never_exist"); + + t.equal(res.statusCode, 404); + t.strictSame(res.body, { + success: false, + description: "Endpoint Not Found.", + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/router.ts b/typescript/server/src/server/router/api/v1postgres/router.ts new file mode 100644 index 000000000..c65eba03f --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/router.ts @@ -0,0 +1,56 @@ +import { NormalRateLimitMiddleware } from "#server/middleware/rate-limiter"; +import { Router } from "express"; + +import activityRouter from "./activity/router"; +import adminRouter from "./admin/router"; +import authRouter from "./auth/router"; +import clientsRouter from "./clients/router"; +import configRouter from "./config/router"; +import gamesRouter from "./games/router"; +import importRouter from "./import/router"; +import importsRouter from "./imports/router"; +import oauthRouter from "./oauth/router"; +import scoresRouter from "./scores/router"; +import searchRouter from "./search/router"; +import seedsRouter from "./seeds/router"; +import sessionsRouter from "./sessions/router"; +import statusRouter from "./status/router"; +import usersRouter from "./users/router"; + +const router: Router = Router({ mergeParams: true }); + +// Auth is up here so it can have special rate limiting rules, +// since it needs slightly harsher ones! +router.use("/auth", authRouter); + +// Everything else can use the normal rate limiter! +router.use(NormalRateLimitMiddleware); + +router.use("/admin", adminRouter); +router.use("/activity", activityRouter); +router.use("/status", statusRouter); +router.use("/import", importRouter); +router.use("/imports", importsRouter); +router.use("/users", usersRouter); +router.use("/games", gamesRouter); +router.use("/search", searchRouter); +router.use("/scores", scoresRouter); +router.use("/sessions", sessionsRouter); +router.use("/oauth", oauthRouter); +router.use("/clients", clientsRouter); +router.use("/config", configRouter); +router.use("/seeds", seedsRouter); + +/** + * Return a JSON 404 response if an endpoint is hit that does not exist. + * + * @name ALL /api/v1/* + */ +router.all("*", (req, res) => + res.status(404).json({ + success: false, + description: "Endpoint Not Found.", + }), +); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/scores/_scoreID/middleware.ts b/typescript/server/src/server/router/api/v1postgres/scores/_scoreID/middleware.ts new file mode 100644 index 000000000..6a2e8e72f --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/scores/_scoreID/middleware.ts @@ -0,0 +1,49 @@ +import type { RequestHandler } from "express"; + +import { SYMBOL_TACHI_API_AUTH } from "#lib/constants/tachi"; +import { log } from "#lib/log/log.js"; +import db from "#services/mongo/db"; +import { AssignToReqTachiData, GetTachiData } from "#utils/req-tachi-data"; +import { IsRequesterAdmin } from "#utils/user"; + +export const GetScoreFromParam: RequestHandler = async (req, res, next) => { + const score = await db.scores.findOne({ scoreID: req.params.scoreID }); + + if (!score) { + return res.status(404).json({ + success: false, + description: `This score does not exist.`, + }); + } + + AssignToReqTachiData(req, { scoreDoc: score }); + + next(); +}; + +export const RequireOwnershipOfScoreOrAdmin: RequestHandler = async (req, res, next) => { + const score = GetTachiData(req, "scoreDoc"); + const userID = req[SYMBOL_TACHI_API_AUTH].userID; + + if (userID === null) { + return res.status(401).json({ + success: false, + description: `You are not authorised as anyone, and this endpoint requires us to know who you are.`, + }); + } + + if (score.userID !== userID) { + if (await IsRequesterAdmin(req[SYMBOL_TACHI_API_AUTH])) { + log.info(`Admin ${userID} interacted with someone elses .`); + next(); + return; + } + + return res.status(403).json({ + success: false, + description: `You are not authorised to perform this action.`, + }); + } + + next(); +}; diff --git a/typescript/server/src/server/router/api/v1postgres/scores/_scoreID/router.test.ts b/typescript/server/src/server/router/api/v1postgres/scores/_scoreID/router.test.ts new file mode 100644 index 000000000..121b8a0ad --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/scores/_scoreID/router.test.ts @@ -0,0 +1,292 @@ +import db from "#services/mongo/db"; +import { CreateFakeAuthCookie } from "#test-utils/fake-auth"; +import { mkFakeScoreIIDXSP } from "#test-utils/misc"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { Testing511SPA } from "#test-utils/test-data"; +import { UserAuthLevels } from "tachi-common"; +import t from "tap"; + +t.test("GET /api/v1/scores/:scoreID", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return the score at that ID.", async (t) => { + const res = await mockApi.get("/api/v1/scores/TESTING_SCORE_ID"); + + t.equal(res.body.body.score.scoreID, "TESTING_SCORE_ID"); + + t.end(); + }); + + t.test("Should return the associated data if the param is set.", async (t) => { + const res = await mockApi.get("/api/v1/scores/TESTING_SCORE_ID?getRelated=true"); + + t.equal(res.body.body.score.scoreID, "TESTING_SCORE_ID"); + t.equal(res.body.body.user.id, 1); + t.equal(res.body.body.chart.chartID, Testing511SPA.chartID); + t.equal(res.body.body.song.id, 1); + + t.end(); + }); + + t.test("Should return 404 if the score does not exist.", async (t) => { + const res = await mockApi.get("/api/v1/scores/not_real"); + + t.equal(res.statusCode, 404); + + t.end(); + }); + + t.end(); +}); + +t.test("PATCH /api/v1/scores/:scoreID", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should modify the session if the user has permission to.", async (t) => { + const res = await mockApi + .patch("/api/v1/scores/TESTING_SCORE_ID") + .set("Authorization", "Bearer fake_api_token") + .send({ + comment: "hello_world", + }); + + t.equal(res.body.body.comment, "hello_world"); + + const score = await db.scores.findOne({ scoreID: "TESTING_SCORE_ID" }); + + t.equal(score?.comment, "hello_world"); + + t.end(); + }); + + t.test("Should modify highlighted status.", async (t) => { + const res = await mockApi + .patch("/api/v1/scores/TESTING_SCORE_ID") + .set("Authorization", "Bearer fake_api_token") + .send({ + highlight: true, + }); + + t.equal(res.body.body.highlight, true); + + const score = await db.scores.findOne({ scoreID: "TESTING_SCORE_ID" }); + + t.equal(score?.highlight, true); + + t.end(); + }); + + t.test("Should set comment status to null.", async (t) => { + const res = await mockApi + .patch("/api/v1/scores/TESTING_SCORE_ID") + .set("Authorization", "Bearer fake_api_token") + .send({ + comment: null, + }); + + t.equal(res.body.body.comment, null); + + const score = await db.scores.findOne({ scoreID: "TESTING_SCORE_ID" }); + + t.equal(score?.comment, null); + + t.end(); + }); + + t.test("Should restrict comments to those between 1 and 120 characters.", async (t) => { + const res = await mockApi + .patch("/api/v1/scores/TESTING_SCORE_ID") + .set("Authorization", "Bearer fake_api_token") + .send({ + comment: "", + }); + + t.equal(res.statusCode, 400); + t.match(res.body.description, /\[comment\]/u); + + const res2 = await mockApi + .patch("/api/v1/scores/TESTING_SCORE_ID") + .set("Authorization", "Bearer fake_api_token") + .send({ + comment: "a".repeat(121), + }); + + t.equal(res2.statusCode, 400); + t.match(res2.body.description, /\[comment\]/u); + + t.end(); + }); + + t.test("Should reject empty bodies.", async (t) => { + const res = await mockApi + .patch("/api/v1/scores/TESTING_SCORE_ID") + .set("Authorization", "Bearer fake_api_token") + .send({}); + + t.equal(res.statusCode, 400); + + t.end(); + }); + + t.test("Should require authorisation as this user.", async (t) => { + await db["api-tokens"].insert({ + token: "some_dude", + userID: 2, + identifier: "Fake Token", + permissions: { + customise_score: true, + }, + fromAPIClient: null, + }); + + const res = await mockApi + .patch("/api/v1/scores/TESTING_SCORE_ID") + .set("Authorization", "Bearer some_dude") + .send({ + comment: "foo", + }); + + t.equal(res.statusCode, 403); + + t.match(res.body.description, /You are not authorised/u); + + t.end(); + }); + + t.test("Should require the customise_score permission", async (t) => { + await db["api-tokens"].insert({ + token: "some_token", + userID: 1, + identifier: "another fake token", + permissions: {}, + fromAPIClient: null, + }); + + const res = await mockApi + .patch("/api/v1/scores/TESTING_SCORE_ID") + .set("Authorization", "Bearer some_token") + .send({ + comment: "foo", + }); + + t.equal(res.statusCode, 403); + + t.match(res.body.description, /customise_score/u); + + t.end(); + }); + + t.end(); +}); + +t.test("DELETE /api/v1/scores/:scoreID", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should delete a score if the requester can.", async (t) => { + await db["api-tokens"].insert({ + userID: 1, + identifier: "foo", + permissions: { + delete_score: true, + }, + token: "foo", + fromAPIClient: null, + }); + + const res = await mockApi + .delete("/api/v1/scores/TESTING_SCORE_ID") + .set("Authorization", "Bearer foo"); + + t.equal(res.statusCode, 200); + + const dbScore = await db.scores.findOne({ scoreID: "TESTING_SCORE_ID" }); + + t.equal(dbScore, null, "Should remove the score from the database."); + + t.end(); + }); + + t.test("Should require authorisation as this user.", async (t) => { + await db["api-tokens"].insert({ + token: "some_dude", + userID: 2, + identifier: "Fake Token", + permissions: { + delete_score: true, + }, + fromAPIClient: null, + }); + + const res = await mockApi + .delete("/api/v1/scores/TESTING_SCORE_ID") + .set("Authorization", "Bearer some_dude") + .send({ + comment: "foo", + }); + + t.equal(res.statusCode, 403); + + t.match(res.body.description, /You are not authorised/u); + + t.end(); + }); + + t.test("Should require the delete_score permission", async (t) => { + await db["api-tokens"].insert({ + token: "some_token", + userID: 1, + identifier: "another fake token", + permissions: {}, + fromAPIClient: null, + }); + + const res = await mockApi + .delete("/api/v1/scores/TESTING_SCORE_ID") + .set("Authorization", "Bearer some_token") + .send(); + + t.equal(res.statusCode, 403); + + t.match(res.body.description, /delete_score/u); + + t.end(); + }); + + t.test("Should allow admins to delete other's scores", async (t) => { + const cookie = await CreateFakeAuthCookie(mockApi); + + await db.users.update( + { + id: 1, + }, + { + $set: { authLevel: UserAuthLevels.ADMIN }, + }, + ); + + const someoneElsesScore = mkFakeScoreIIDXSP({ userID: 2, scoreID: "someone_elses" }); + + await db.scores.insert(someoneElsesScore); + + const res = await mockApi + .delete(`/api/v1/scores/${someoneElsesScore.scoreID}`) + .set("Cookie", cookie); + + t.equal(res.statusCode, 200, "Should return 200."); + + t.strictSame(res.body.body, {}, "The response body should be empty."); + + t.resolveMatch( + db.scores.findOne({ scoreID: someoneElsesScore.scoreID }), + + // @ts-expect-error https://github.com/DefinitelyTyped/DefinitelyTyped/pull/60020 + null, + "The score should be deleted.", + ); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/scores/_scoreID/router.ts b/typescript/server/src/server/router/api/v1postgres/scores/_scoreID/router.ts new file mode 100644 index 000000000..77a950c91 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/scores/_scoreID/router.ts @@ -0,0 +1,170 @@ +import { log } from "#lib/log/log.js"; +import { DeleteScore } from "#lib/score-mutation/delete-scores"; +import { RequirePermissions } from "#server/middleware/auth"; +import prValidate from "#server/middleware/prudence-validate"; +import db from "#services/mongo/db"; +import { GetTachiData } from "#utils/req-tachi-data"; +import { GetUserWithID } from "#utils/user"; +import { Router } from "express"; +import { p } from "prudence"; + +import { GetScoreFromParam, RequireOwnershipOfScoreOrAdmin } from "./middleware"; + +const router: Router = Router({ mergeParams: true }); + +router.use(GetScoreFromParam); + +/** + * Retrieve the score document at this ID. + * + * @param getRelated - Gets the related song and chart document for this score, aswell. + * + * @name GET /api/v1/scores/:scoreID + */ +router.get("/", async (req, res) => { + const score = GetTachiData(req, "scoreDoc"); + + if (req.query.getRelated !== undefined) { + const [user, chart, song] = await Promise.all([ + GetUserWithID(score.userID), + db.anyCharts[score.game].findOne({ chartID: score.chartID }), + db.anySongs[score.game].findOne({ id: score.songID }), + ]); + + if (!user || !chart || !song) { + log.error( + `Score ${ + score.scoreID + } refers to non-existent data: [user,chart,song] [${!!user} ${!!chart} ${!!song}]`, + ); + + return res.status(500).json({ + success: false, + description: `An internal server error has occured.`, + }); + } + + return res.status(200).json({ + success: true, + description: `Returned score.`, + body: { + score, + user, + song, + chart, + }, + }); + } + + return res.status(200).json({ + success: true, + description: `Returned score.`, + body: { + score, + }, + }); +}); + +interface ModifiableScoreProps { + comment?: string | null; + highlight?: boolean; +} + +/** + * Modifies a score. + * + * Requires you to be the owner of this score, and have the modify_scores permission. + * + * @name PATCH /api/v1/scores/:scoreID + */ +router.patch( + "/", + RequireOwnershipOfScoreOrAdmin, + RequirePermissions("customise_score"), + prValidate({ + comment: p.optional(p.nullable(p.isBoundedString(1, 120))), + highlight: "*boolean", + }), + async (req, res) => { + const body = req.safeBody as { + comment?: string | null; + highlight?: boolean; + }; + + const score = GetTachiData(req, "scoreDoc"); + + const modifyOption: ModifiableScoreProps = {}; + + if (body.comment !== undefined) { + modifyOption.comment = body.comment; + } + + if (body.highlight !== undefined) { + modifyOption.highlight = body.highlight; + } + + if (Object.keys(modifyOption).length === 0) { + return res.status(400).json({ + success: false, + description: `This request modifies nothing about the score.`, + }); + } + + const newScore = await db.scores.findOneAndUpdate( + { scoreID: score.scoreID }, + { $set: modifyOption }, + ); + + if (modifyOption.highlight === true || modifyOption.highlight === false) { + await db["personal-bests"].findOneAndUpdate( + { + chartID: score.chartID, + userID: score.userID, + }, + { + $set: { + highlight: modifyOption.highlight, + }, + }, + ); + } + + return res.status(200).json({ + success: true, + description: `Updated score.`, + body: newScore, + }); + }, +); + +/** + * Deletes the score. + * + * @param blacklist - Whether to blacklist this scoreID or not. + * A blacklisted score will never be reimported. + * + * @name DELETE /api/v1/scores/:scoreID + */ +router.delete( + "/", + RequireOwnershipOfScoreOrAdmin, + prValidate({ blacklist: "*boolean" }), + RequirePermissions("delete_score"), + async (req, res) => { + const body = req.safeBody as { + blacklist?: boolean; + }; + + const score = GetTachiData(req, "scoreDoc"); + + await DeleteScore(score, body.blacklist); + + return res.status(200).json({ + success: true, + description: `Successfully deleted score.`, + body: {}, + }); + }, +); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/scores/router.ts b/typescript/server/src/server/router/api/v1postgres/scores/router.ts new file mode 100644 index 000000000..374ff8ce9 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/scores/router.ts @@ -0,0 +1,16 @@ +import { Router } from "express"; + +import scoreIDRouter from "./_scoreID/router"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Nothing? Maybe we can think of a good use for this endpoint at some point. + * + * @name GET /api/v1/scores/:scoreID + */ +// router.get("/", async (req, res) => {}); + +router.use("/:scoreID", scoreIDRouter); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/search/router.test.ts b/typescript/server/src/server/router/api/v1postgres/search/router.test.ts new file mode 100644 index 000000000..81e659d01 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/search/router.test.ts @@ -0,0 +1,53 @@ +import type { ChartDocument, SongDocument } from "tachi-common"; + +import db from "#services/mongo/db"; +import { mkFakeGameSettings, mkFakeUser } from "#test-utils/misc"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { LoadTachiIIDXData } from "#test-utils/test-data"; +import t from "tap"; + +t.test("GET /api/v1/search", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(LoadTachiIIDXData); + + t.test("Should search users and songs.", async (t) => { + const res = await mockApi.get("/api/v1/search?search=zkldi"); + + t.equal(res.body.body.users.length, 1); + + t.equal(res.body.body.users[0].username, "test_zkldi"); + t.equal(res.body.body.users[0].__isRival, false); + + t.end(); + }); + + t.test("Should highlight users as rivals if they're rivals of the requester", async (t) => { + await db.users.insert( + mkFakeUser(2, { username: "scoobydoo", usernameLowercase: "scoobydoo" }), + ); + + await db["game-settings"].remove({}); + await db["game-settings"].insert(mkFakeGameSettings(1, "iidx", "SP", { rivals: [2] })); + + const res = await mockApi + .get("/api/v1/search?search=scoobydoo") + .set("Authorization", "Bearer fake_api_token"); + + t.equal(res.body.body.users.length, 1); + + t.equal(res.body.body.users[0].__isRival, true); + + t.end(); + }); + + t.test("Should reject requests without a query.", async (t) => { + const res = await mockApi.get("/api/v1/search"); + + t.equal(res.statusCode, 400); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/search/router.ts b/typescript/server/src/server/router/api/v1postgres/search/router.ts new file mode 100644 index 000000000..c76f41f8d --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/search/router.ts @@ -0,0 +1,123 @@ +import type { FilterQuery } from "mongodb"; + +import { SYMBOL_TACHI_API_AUTH } from "#lib/constants/tachi"; +import { + SearchFolders, + SearchForChartHash, + SearchGamesSongsCharts, + SearchUsersRegExp, +} from "#lib/search/search"; +import { TachiConfig } from "#lib/setup/config"; +import { IsString } from "#utils/misc"; +import { GetAllUserRivals, GetUserPlayedGPTs } from "#utils/user"; +import { Router } from "express"; +import { + type FolderDocument, + GameGroup, + GetGameGroupConfig, + GetGPTString, + type GPTString, + type integer, + type SongDocument, + type UserDocument, +} from "tachi-common"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Performs a generic "search" across Tachi. + * + * @param search - The criteria to search on. + * + * @name GET /api/v1/search + */ +router.get("/", async (req, res) => { + if (!IsString(req.query.search)) { + return res.status(400).json({ + success: false, + description: "No search parameter given.", + }); + } + + const userID = req[SYMBOL_TACHI_API_AUTH].userID; + + let filter: FilterQuery = {}; + + let relevantGPTs: Array = TachiConfig.GAMES.flatMap((g) => + GetGameGroupConfig(g).playtypes.map((pt) => GetGPTString(g, pt)), + ); + + if (userID !== null) { + // if the requesting user exists, and they've set this param, + // only return info related to games they've played. + if (IsString(req.query.hasPlayedGame)) { + const gpts = await GetUserPlayedGPTs(userID); + + // @hack This is a bit lazy. We should really be filtering the user stuff + // on GPTs with an $or query. + filter = { + game: { $in: gpts.map((e) => e.game) }, + playtype: { $in: gpts.map((e) => e.playtype) }, + }; + + relevantGPTs = gpts.map((e) => GetGPTString(e.game, e.playtype)); + } + } + + const [users, charts, folders] = await Promise.all([ + SearchUsersRegExp(req.query.search), + SearchGamesSongsCharts(req.query.search, relevantGPTs), + SearchFolders(req.query.search, filter), + ]); + + // @ts-expect-error Handled below -- the field is added by the below for loop. + const usersWithRivalTag: Array<{ __isRival: boolean } & UserDocument> = users; + + let rivals: Array = []; + + if (userID !== null) { + rivals = await GetAllUserRivals(userID); + } + + for (const user of usersWithRivalTag) { + user.__isRival = rivals.includes(user.id); + } + + return res.status(200).json({ + success: true, + description: `Searched everything.`, + body: { + users, + charts, + folders, + }, + }); +}); + +/** + * Search checksums for charts, instead of matching on song title. + * + * @param search - The hash to search on. + * + * @note This matches MD5 and SHA256 for BMS/PMS, GSv3 for ITG and SHA1 for USC. + */ +router.get("/chart-hash", async (req, res) => { + if (!IsString(req.query.search)) { + return res.status(400).json({ + success: false, + description: "No search parameter given.", + }); + } + + const charts = await SearchForChartHash(req.query.search); + + return res.status(200).json({ + success: true, + description: `Searched for chart hash ${req.query.search}.`, + body: { + charts, + }, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/seeds/router.ts b/typescript/server/src/server/router/api/v1postgres/seeds/router.ts new file mode 100644 index 000000000..11d590f7c --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/seeds/router.ts @@ -0,0 +1,317 @@ +import { log } from "#lib/log/log.js"; +import { PullDatabaseSeeds } from "#lib/seeds/repo"; +import { Env } from "#lib/setup/config"; +import prValidate from "#server/middleware/prudence-validate"; +import { RequireLocalDevelopment } from "#server/middleware/type-require"; +import { GetCommit, ListGitCommitsInPath } from "#utils/git"; +import { asyncExec, IsString } from "#utils/misc"; +import { Router } from "express"; +import fsSync from "fs"; +import fs from "fs/promises"; +import path from "path"; + +// Routes for interacting with the `seeds` folder in this instance of Tachi. + +// Why do we have this, and why is it limited to only local development? +// The answer is that we have a "Seeds UI" that runs in the client. For local development +// it's useful to be able to see the current state of the seeds on-disk, and diff that +// against various local commits. As such, we need an api such that the client can +// interface with our local seeds. + +// In production/staging, we use GitHub as a source of truth for our git repository. +// In local dev, we have this option available too, but we also enable this API. + +const router: Router = Router({ mergeParams: true }); + +router.use(RequireLocalDevelopment); + +// there's a lady who's sure +// all that glitters is gold +const LOCAL_DEV_SEEDS_PATH = path.join( + __dirname, + + // and she's buying a... + "../../../../../../../seeds/collections", +); +const TEST_SEEDS_PATH = path.join(__dirname, "../../../../../test-utils/mock-db"); + +const LOCAL_SEEDS_PATH = Env.NODE_ENV === "test" ? TEST_SEEDS_PATH : LOCAL_DEV_SEEDS_PATH; + +if (Env.NODE_ENV === "dev" || Env.NODE_ENV === "test") { + if (!fsSync.existsSync(LOCAL_SEEDS_PATH)) { + log.error(`Failed to load seeds routes, could not find any seeds/collections checked out at ${LOCAL_SEEDS_PATH}. +These were expected to be present as this is local-development! +All seeds routes will return 500.`); + } +} + +/** + * No-Op route for checking whether this feature is supported by this instance of Tachi. + * + * @name GET /api/v1/seeds + */ +router.get("/", (req, res) => + res.status(200).json({ + success: true, + description: `Local seeds are available on this instance of Tachi.`, + body: {}, + }), +); + +/** + * Check whether there are changes to the seeds in this local development + * instance that have not been committed yet. + * + * @name GET /api/v1/seeds/has-uncommitted-changes + */ +router.get("/has-uncommitted-changes", async (req, res) => { + const { stdout, stderr } = await asyncExec(`git status --porcelain`); + + if (stderr) { + log.error({ stderr }, `Failed to read git status --porcelain.`); + return res.status(500).json({ + success: false, + description: `Failed to check current git status.`, + }); + } + + // if any change contains seeds/collections, it's probably uncommitted + // local changes. + const hasUncommittedChanges = stdout + .split("\n") + + // note that doing this properly is frustrating. This has false positives for + // routes that partially contain this route. I've ameliorated this slightly with + // a leading space, but that is not a proper solution. + .some((row) => / seeds\/collections/u.exec(row)); + + return res.status(200).json({ + success: true, + description: hasUncommittedChanges + ? "This local instance has uncommitted changes." + : "This local instance does not have uncommitted changes.", + body: hasUncommittedChanges, + }); +}); + +/** + * List commits that have affected seeds. + * + * This format is a partial implementation of what GitHub's REST API returns. As such, + * an implementing client has far less work to do with respect to handling local + remote + * servers. + * + * @param file - If provided, only returns commits that have touched this specific file. + * + * @name GET /api/v1/seeds/commits + */ +router.get( + "/commits", + prValidate({ + branch: "string", + file: "*string", + }), + async (req, res) => { + // validated by prudence. + const file = req.query.file as string | undefined; + const branch = req.query.branch as string; + + const seeds = await PullDatabaseSeeds(); + const collections = (await seeds.ListCollections()).map((e) => `${e}.json`); + + if (IsString(file) && !collections.includes(file)) { + return res.status(400).json({ + success: false, + description: `Invalid file of '${file}' requested. Expected any of ${collections.join( + ", ", + )}`, + }); + } + + // if we don't have a file, use the do-nothing path. + const realFile = file ?? "."; + + // only check commits in seeds/collections + const commits = await ListGitCommitsInPath( + branch, + path.join("seeds", "collections", realFile), + ); + + return res.status(200).json({ + success: true, + description: `Found ${commits.length} commits.`, + body: commits, + }); + }, +); + +/** + * List branches available on this local repository. + * + * This returns all branches under `branches`, and the currently selected branch + * as `checkedout`, which might be null if the HEAD is currently detached. + * + * @name GET /api/v1/seeds/branches + */ +router.get("/branches", async (req, res) => { + const { stdout: branches } = await asyncExec(`PAGER=cat git branch --no-color -v`); + + const allBranches = []; + let currentBranch: { name: string; sha: string } | null = null; + + for (const branchStr of branches.split("\n")) { + const match = /^ *(\*?) +(.*?) +([a-f0-9]*)/u.exec(branchStr) as + | [string, string, string, string] + | null; + + if (match === null) { + continue; + } + + const [_, isCurrent, branchName, sha] = match; + + if (branchName.startsWith("(HEAD detatched at")) { + continue; + } + + if (branchName === "") { + continue; + } + + const branch = { name: branchName, sha }; + + if (isCurrent === "*") { + currentBranch = branch; + } + + allBranches.push(branch); + } + + return res.status(200).json({ + success: true, + description: `Found ${allBranches.length} branches.`, + body: { + branches: allBranches, + current: currentBranch, + }, + }); +}); + +/** + * Retrieve the current state of the collection as of this revision. + * + * This returns a record of "songs-iidx.json" -> PARSED_SONGS_IIDX_JSON_CONTENT + * for all collections as of that current revision. As such, you should treat all + * returned records as if they might not be present (as they might not be). + * + * @param revision - The revision fetched. This is resolved using standard git rules, + * and can therefore be a branch name, a commit name, or anything else git will resolve + * like HEAD@{2020-01-01}. + * + * If no revision is provided, the current uncommitted state on disk is returned instead. + * + * @name GET /api/v1/seeds/collections + */ +router.get( + "/collections", + prValidate({ + revision: "*string", + }), + async (req, res) => { + // asserted by prudence + const rev = req.query.revision as string | undefined; + + const data: Record = {}; + + // use local disk + if (rev === undefined) { + const files = await fs.readdir(LOCAL_SEEDS_PATH); + + await Promise.all( + files.map(async (file) => { + const content = await fs.readFile(path.join(LOCAL_SEEDS_PATH, file), "utf-8"); + + data[file] = JSON.parse(content); + }), + ); + } else { + // we have a revision. + + if (rev.includes(":")) { + return res.status(400).json({ + success: false, + description: `Git Revisions cannot contain ':' characters.`, + }); + } + + // @warn we don't actually bother doing any real shell + // escaping here, since these routes are only enabled in local development. + const { stdout: fileStdout } = await asyncExec( + `PAGER=cat git show '${rev}:seeds/collections' | tail -n +3`, + ); + + // @warn this breaks for files that have newlines in + // I don't care. + // also, this ends with a trailing newline which means we get a trailing + // empty filename, gotta strip that out. + const files = fileStdout.split("\n").filter((e) => e !== ""); + + await Promise.all( + files.map(async (file) => { + // git show fails with 128 *if* this file doesn't exist at the time + // of this commit. however, the files we're iterating over are the + // files in the collection as of this commit, so, this should never + // crash in that way, right? + const { stdout: content } = await asyncExec( + `PAGER=cat git show '${rev}:seeds/collections/${file}'`, + ); + + data[file] = JSON.parse(content); + }), + ); + } + + return res.status(200).json({ + success: true, + description: `Retrieved data ${rev ? `as of ${rev}` : "off of the current disk"}.`, + body: data, + }); + }, +); + +/** + * Retrieve information about the provided commit. + * + * @param sha - The commit to fetch information about. Technically, this can be the name + * of any git object, but you probably shouldn't. + * + * @name GET /api/v1/seeds/commit + */ +router.get( + "/commit", + prValidate({ + sha: "string", + }), + async (req, res) => { + // asserted by prudence + const sha = req.query.sha as string; + + try { + const commit = await GetCommit(sha); + + return res.status(200).json({ + success: true, + description: `Found commit '${sha}'.`, + body: commit, + }); + } catch (err) { + log.info({ err }, `Failed to fetch commit.`); + return res.status(404).json({ + success: false, + description: `Failed to fetch commit. It may not exist.`, + }); + } + }, +); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/sessions/_sessionID/middleware.ts b/typescript/server/src/server/router/api/v1postgres/sessions/_sessionID/middleware.ts new file mode 100644 index 000000000..581cab34b --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/sessions/_sessionID/middleware.ts @@ -0,0 +1,37 @@ +import type { RequestHandler } from "express"; + +import { SYMBOL_TACHI_API_AUTH } from "#lib/constants/tachi"; +import { log } from "#lib/log/log.js"; +import db from "#services/mongo/db"; +import { AssignToReqTachiData, GetTachiData } from "#utils/req-tachi-data"; + +export const GetSessionFromParam: RequestHandler = async (req, res, next) => { + const session = await db.sessions.findOne({ + sessionID: req.params.sessionID, + }); + + if (!session) { + return res.status(404).json({ + success: false, + description: `This session does not exist.`, + }); + } + + AssignToReqTachiData(req, { sessionDoc: session }); + + next(); +}; + +export const RequireOwnershipOfSession: RequestHandler = (req, res, next) => { + const userID = req[SYMBOL_TACHI_API_AUTH].userID; + const session = GetTachiData(req, "sessionDoc"); + + if (userID !== session.userID) { + return res.status(403).json({ + success: false, + description: `You are not authorised to modify this session.`, + }); + } + + next(); +}; diff --git a/typescript/server/src/server/router/api/v1postgres/sessions/_sessionID/router.test.ts b/typescript/server/src/server/router/api/v1postgres/sessions/_sessionID/router.test.ts new file mode 100644 index 000000000..ddc7471ae --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/sessions/_sessionID/router.test.ts @@ -0,0 +1,204 @@ +import db from "#services/mongo/db"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { Testing511SPA } from "#test-utils/test-data"; +import t from "tap"; + +const TESTING_SESSION_ID = "Qe7b00261b1d3ba8e5c9ee4e76e77ea9f07d9493b"; + +t.test("GET /api/v1/sessions/:sessionID", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return the session at this ID", async (t) => { + const res = await mockApi.get(`/api/v1/sessions/${TESTING_SESSION_ID}`); + + t.equal(res.body.body.session.sessionID, TESTING_SESSION_ID); + + t.equal(res.body.body.charts.length, 1); + t.equal(res.body.body.charts[0].chartID, Testing511SPA.chartID); + + t.equal(res.body.body.songs.length, 1); + t.equal(res.body.body.songs[0].id, 1); + + t.equal(res.body.body.scores.length, 1); + t.equal(res.body.body.scores[0].scoreID, "TESTING_SCORE_ID"); + + t.equal(res.body.body.user.id, 1); + + t.end(); + }); + + t.test("Should return 404 if the session does not exist.", async (t) => { + const res = await mockApi.get("/api/v1/sessions/fake_session"); + + t.equal(res.statusCode, 404); + + t.end(); + }); + + t.end(); +}); + +t.test("PATCH /api/v1/sessions/:sessionID", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should modify the session if the user has permission to.", async (t) => { + const res = await mockApi + .patch(`/api/v1/sessions/${TESTING_SESSION_ID}`) + .set("Authorization", "Bearer fake_api_token") + .send({ + name: "hello_world", + }); + + t.equal(res.body.body.name, "hello_world"); + + const session = await db.sessions.findOne({ sessionID: TESTING_SESSION_ID }); + + t.equal(session?.name, "hello_world", "Should update the session in the database."); + + t.end(); + }); + + t.test("Should modify highlighted status.", async (t) => { + const res = await mockApi + .patch(`/api/v1/sessions/${TESTING_SESSION_ID}`) + .set("Authorization", "Bearer fake_api_token") + .send({ + highlight: true, + }); + + t.equal(res.body.body.highlight, true); + + const session = await db.sessions.findOne({ sessionID: TESTING_SESSION_ID }); + + t.equal(session?.highlight, true); + + t.end(); + }); + + t.test("Should set description.", async (t) => { + const res = await mockApi + .patch(`/api/v1/sessions/${TESTING_SESSION_ID}`) + .set("Authorization", "Bearer fake_api_token") + .send({ + desc: "foobar", + }); + + t.equal(res.body.body.desc, "foobar"); + + const session = await db.sessions.findOne({ sessionID: TESTING_SESSION_ID }); + + t.equal(session?.desc, "foobar"); + + t.end(); + }); + + t.test("Should restrict names to those between 3 and 80 chars.", async (t) => { + const res = await mockApi + .patch(`/api/v1/sessions/${TESTING_SESSION_ID}`) + .set("Authorization", "Bearer fake_api_token") + .send({ + name: "a", + }); + + t.equal(res.statusCode, 400); + t.match(res.body.description, /\[name\]/u); + + const res2 = await mockApi + .patch(`/api/v1/sessions/${TESTING_SESSION_ID}`) + .set("Authorization", "Bearer fake_api_token") + .send({ + name: "a".repeat(81), + }); + + t.equal(res2.statusCode, 400); + t.match(res2.body.description, /\[name\]/u); + + t.end(); + }); + + t.test("Should restrict descs to those between 3 and 120 chars.", async (t) => { + const res = await mockApi + .patch(`/api/v1/sessions/${TESTING_SESSION_ID}`) + .set("Authorization", "Bearer fake_api_token") + .send({ + desc: "a", + }); + + t.equal(res.statusCode, 400); + t.match(res.body.description, /\[desc\]/u); + + const res2 = await mockApi + .patch(`/api/v1/sessions/${TESTING_SESSION_ID}`) + .set("Authorization", "Bearer fake_api_token") + .send({ + desc: "a".repeat(121), + }); + + t.equal(res2.statusCode, 400); + t.match(res2.body.description, /\[desc\]/u); + + t.end(); + }); + + t.test("Should reject empty bodies.", async (t) => { + const res = await mockApi + .patch(`/api/v1/sessions/${TESTING_SESSION_ID}`) + .set("Authorization", "Bearer fake_api_token") + .send({}); + + t.equal(res.statusCode, 400); + + t.end(); + }); + + t.test("Should require authorisation as this user.", async (t) => { + await db["api-tokens"].insert({ + token: "some_dude", + userID: 2, + identifier: "Fake Token", + permissions: { + customise_session: true, + }, + fromAPIClient: null, + }); + + const res = await mockApi + .patch(`/api/v1/sessions/${TESTING_SESSION_ID}`) + .set("Authorization", "Bearer some_dude") + .send({ + comment: "foo", + }); + + t.equal(res.statusCode, 403); + + t.match(res.body.description, /You are not authorised/u); + + t.end(); + }); + + t.test("Should require the customise_session permission", async (t) => { + await db["api-tokens"].insert({ + token: "some_token", + userID: 1, + identifier: "another fake token", + permissions: {}, + fromAPIClient: null, + }); + + const res = await mockApi + .patch(`/api/v1/sessions/${TESTING_SESSION_ID}`) + .set("Authorization", "Bearer some_token") + .send({ + comment: "foo", + }); + + t.equal(res.statusCode, 403); + + t.match(res.body.description, /customise_session/u); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/sessions/_sessionID/router.ts b/typescript/server/src/server/router/api/v1postgres/sessions/_sessionID/router.ts new file mode 100644 index 000000000..eb2e762cb --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/sessions/_sessionID/router.ts @@ -0,0 +1,365 @@ +import { GetSessionScoreInfo } from "#lib/score-import/framework/sessions/sessions"; +import { RequirePermissions } from "#server/middleware/auth"; +import prValidate from "#server/middleware/prudence-validate"; +import db from "#services/mongo/db"; +import { GetEnumDistForFolderAsOf } from "#utils/folder"; +import { AddToSetInRecord } from "#utils/misc"; +import { GetTachiData } from "#utils/req-tachi-data"; +import { GetUserWithID } from "#utils/user"; +import { Router } from "express"; +import { p } from "prudence"; +import { + type FolderDocument, + GetGamePTConfig, + GetScoreEnumConfs, + GetScoreMetrics, + type integer, + type ScoreDocument, +} from "tachi-common"; +import { optNull } from "tachi-common/lib/schemas"; + +import { GetSessionFromParam, RequireOwnershipOfSession } from "./middleware"; + +const router: Router = Router({ mergeParams: true }); + +router.use(GetSessionFromParam); + +/** + * Retrieves the session, its scores and the related songs and charts. + * + * @name GET /api/v1/sessions/:sessionID + */ +router.get("/", async (req, res) => { + const session = GetTachiData(req, "sessionDoc"); + + const scores = await db.scores.find({ + scoreID: { $in: session.scoreIDs }, + }); + + const [songs, charts, user, scoreInfo] = await Promise.all([ + db.anySongs[session.game].find({ + id: { $in: scores.map((e) => e.songID) }, + }), + db.anyCharts[session.game].find({ + chartID: { $in: scores.map((e) => e.chartID) }, + }), + GetUserWithID(session.userID), + GetSessionScoreInfo(session), + ]); + + return res.status(200).json({ + success: true, + description: `Successfully returned session ${session.name}.`, + body: { + session, + songs, + charts, + scores, + user, + scoreInfo, + }, + }); +}); + +/** + * Retrieves additional statistics about folder raises as a result of this session. + * + * More obviously, this endpoint returns stuff like "This session resulted in 4 more + * hard clears on the Level 12 folder." + * + * This allows us to render pretty things in the UI, showing the user what their + * best stats were. + * + * @warn This is probably the most complicated route in all of Tachi. Sorry about that. + * + * @name GET /api/v1/sessions/:sessionID/folder-raises + */ +router.get("/folder-raises", async (req, res) => { + const session = GetTachiData(req, "sessionDoc"); + + const gptConfig = GetGamePTConfig(session.game, session.playtype); + + const scoreInfo = await GetSessionScoreInfo(session); + + const enumRaises = []; + + for (const metric of GetScoreMetrics(gptConfig, "ENUM")) { + enumRaises.push( + ...scoreInfo + .filter((e) => !e.isNewScore && (e.deltas[metric] ?? -1) > 0) + .map((e) => e.scoreID), + ); + } + + // create lookup tables for a scoreID to its delta. We use this later to find out + // what the "original" score's grade or lamp was prior to this raise. + const enumDeltas: Record> = {}; + + for (const sci of scoreInfo) { + if (sci.isNewScore) { + continue; + } + + enumDeltas[sci.scoreID] = sci.deltas; + } + + const enumScoreMetrics = GetScoreEnumConfs(gptConfig); + + const relevantScores = await db.scores.find({ + scoreID: { $in: session.scoreIDs }, + }); + + const chartIDs = relevantScores.map((e) => e.chartID); + + // what folderIDs were involved in this session? + const affectedFolderIDs = ( + await db["folder-chart-lookup"].find( + { + chartID: { $in: chartIDs }, + }, + { + projection: { folderID: 1 }, + }, + ) + ).map((e) => e.folderID); + + // find all the active folder documents raised in this session. + const folders = await db.folders.find({ + folderID: { $in: affectedFolderIDs }, + inactive: false, + }); + + const bestEnumMap = new Map(); + + for (const score of relevantScores) { + for (const [metric, conf] of Object.entries(enumScoreMetrics)) { + if ( + // @ts-expect-error lazy index cheating + score.scoreData.enumIndexes[metric]! < + conf.values.indexOf(conf.minimumRelevantValue) + ) { + // isn't relevant + continue; + } + + const mapKey = `${score.chartID}-${metric}`; + + const existing = bestEnumMap.get(mapKey); + + if (!existing) { + bestEnumMap.set(mapKey, score); + } else if ( + // @ts-expect-error lazy index cheating + score.scoreData.enumIndexes[metric] > existing.scoreData.enumIndexes[metric] + ) { + bestEnumMap.set(mapKey, score); + } + } + } + + const raiseInfo: Array<{ + folder: FolderDocument; + previousCount: integer; // how many AAAs/HARD CLEARs/whatevers was on this + raisedCharts: Array; // Array; + totalCharts: integer; + // folder before this session? + type: string; + value: string; + }> = []; + + await Promise.all( + folders.map(async (folder) => { + // what was the grade and lamp distribution on this folder before the session? + const { chartIDs, cumulativeEnumDist } = await GetEnumDistForFolderAsOf( + session.userID, + folder.folderID, + session.timeStarted, + ); + + // what is the distribution of raises on this folder? + // NOTE: instead of storing an integer here + // i.e. For the Level 12 folder: + // AAA: 5 <- 5 new AAAs, + // AA: 2 <- 2 new AAs, etc. + // we store a Set of chartIDs instead, so + // AAA: ["chart1","chart2", ...] with size 5. + // This is so we can display *what* charts were raised in the UI. + // This type results in looking like: + // + // { + // grade: { + // AAA: [chartID, chartID2], + // AA: [chartID3] + // }, + // lamp: { + // "HARD CLEAR": [chartID2] + // } + // } + + for (const [metric, conf] of Object.entries(enumScoreMetrics)) { + const metricDist: Record> = {}; + const previousDist = cumulativeEnumDist[metric]!; + + for (const chartID of chartIDs) { + const bestEnumOnThisChart = bestEnumMap.get(`${chartID}-${metric}`); + + if (!bestEnumOnThisChart) { + continue; + } + + const gradeDeltaSc = scoreInfo.find( + (s) => s.scoreID === bestEnumOnThisChart.scoreID, + ); + + // if no grade delta exists then they raised from 0 + // @ts-expect-error silly cheaty enum access + let gradeDelta = bestEnumOnThisChart.scoreData.enumIndexes[metric]!; + + if ( + gradeDeltaSc && + !gradeDeltaSc.isNewScore && + gradeDeltaSc.deltas[metric] !== undefined + ) { + gradeDelta = gradeDeltaSc.deltas[metric]!; + } + + // get all the enums this counts as a raise for. + // that is to say: if you get an AAA, that also counts as a raise + // for an AA, etc. + + // however, this should only extend down to whatever the previous + // best enum on this chart was. + // luckily, we can calculate this by checking what the grade is now + // and taking away the delta. That gets us the original. + // If this is less than the clearGradeIndex, use that instead. + + // note: we add one to this because .slice is inclusive, + // so if we have a EX HARD CLEAR (i=7) with a raise of two, + // minusing two will take us to CLEAR (i=5), and the + // inclusivity will result in us + // slicing ["CLEAR", "HARD CLEAR", "EX HARD CLEAR"] + // (i=5), (i=6) (i=7) + // but this wasn't a new clear! this was only a new HARD CLEAR + // and EX HARD CLEAR, so + // we want ["HARD CLEAR", "EX HARD CLEAR"]. + const originalIndex = + // @ts-expect-error silly cheaty enum access + bestEnumOnThisChart.scoreData.enumIndexes[metric]! - gradeDelta + 1; + + // lowerbound the original grade at the minimum-relevant enum. + const minimumGrade = Math.max( + conf.values.indexOf(conf.minimumRelevantValue), + originalIndex, + ); + + for (const grade of conf.values.slice( + minimumGrade, + // @ts-expect-error silly cheaty enum access (2) + + bestEnumOnThisChart.scoreData.enumIndexes[metric]! + 1, + )) { + AddToSetInRecord(grade, metricDist, chartID); + } + } + + for (const [enumVal, raisedCharts] of Object.entries(metricDist)) { + raiseInfo.push({ + folder, + + previousCount: previousDist[enumVal] ?? 0, + + raisedCharts: Array.from(raisedCharts), + type: metric, + value: enumVal, + totalCharts: chartIDs.length, + }); + } + } + + // now that we know what we've raised, and what was there at the start + // we can push that. + }), + ); + + return res.status(200).json({ + success: true, + description: `Retrieved folder raises.`, + body: raiseInfo, + }); +}); + +interface ModifiableSessionProps { + name?: string; + desc?: string | null; + highlight?: boolean; +} + +/** + * Modifies a session. + * + * Requires the requester to be the owner of the session, alongside having the + * customise_session permission. + * + * @param name - A new name for the session. + * @param desc - A new desc for the session. + * @param highlight - Update the highlighted state of the session with this. + * + * @name PATCH /api/v1/sessions/:sessionID + */ +router.patch( + "/", + RequireOwnershipOfSession, + RequirePermissions("customise_session"), + prValidate( + { + name: p.optional(p.isBoundedString(3, 80)), + desc: optNull(p.isBoundedString(3, 120)), + highlight: "*boolean", + }, + {}, + { allowExcessKeys: true }, + ), + async (req, res) => { + const session = GetTachiData(req, "sessionDoc"); + + const updateExp: ModifiableSessionProps = {}; + + const body = req.safeBody as { + desc?: string | null; + highlight?: boolean; + name?: string; + }; + + if (body.name) { + updateExp.name = body.name; + } + + if (body.desc !== undefined) { + updateExp.desc = body.desc; + } + + if (typeof body.highlight === "boolean") { + updateExp.highlight = body.highlight; + } + + if (Object.keys(updateExp).length === 0) { + return res.status(400).json({ + success: false, + description: `This request modifies nothing about this session.`, + }); + } + + const newSession = await db.sessions.findOneAndUpdate( + { sessionID: session.sessionID }, + { $set: updateExp }, + ); + + return res.status(200).json({ + success: true, + description: `Updated Session.`, + body: newSession, + }); + }, +); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/sessions/router.ts b/typescript/server/src/server/router/api/v1postgres/sessions/router.ts new file mode 100644 index 000000000..674cb8723 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/sessions/router.ts @@ -0,0 +1,16 @@ +import { Router } from "express"; + +import sessionIDRouter from "./_sessionID/router"; + +const router: Router = Router({ mergeParams: true }); + +/** + * nothing, yet. + * + * @name GET /api/v1/sessions + */ +// router.get("/", async (req, res) => {}); + +router.use("/:sessionID", sessionIDRouter); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/status/router.test.ts b/typescript/server/src/server/router/api/v1postgres/status/router.test.ts new file mode 100644 index 000000000..8ba315728 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/status/router.test.ts @@ -0,0 +1,84 @@ +import { VERSION_PRETTY } from "#lib/constants/version"; +import { CreateFakeAuthCookie } from "#test-utils/fake-auth"; +import mockApi from "#test-utils/mock-api"; +import t from "tap"; + +t.test("GET /api/v1/status", async (t) => { + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should return the current time and the server version.", async (t) => { + const res = await mockApi.get("/api/v1/status").set("Cookie", cookie); + + t.equal(res.statusCode, 200); + t.equal(res.body.success, true); + t.ok( + Math.abs(Date.now() - res.body.body.serverTime) < 5_000, + "Should be roughly the current time (5 seconds lenience)", + ); + t.type(res.body.body.startTime, "number", "Should return a number for startTime."); + t.equal(res.body.body.version, VERSION_PRETTY); + t.equal(res.body.body.whoami, 1); + + t.end(); + }); + + t.test("Should echo the provided echo param.", async (t) => { + const res = await mockApi.get("/api/v1/status?echo=foobar").set("Cookie", cookie); + + t.equal(res.statusCode, 200); + t.equal(res.body.success, true); + t.equal(res.body.body.echo, "foobar"); + t.ok( + Math.abs(Date.now() - res.body.body.serverTime) < 5_000, + "Should be roughly the current time (5 seconds lenience)", + ); + t.type(res.body.body.startTime, "number", "Should return a number for startTime."); + t.equal(res.body.body.version, VERSION_PRETTY); + t.equal(res.body.body.whoami, 1); + + t.end(); + }); + + t.end(); +}); + +t.test("POST /api/v1/status", async (t) => { + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should return the current time and the server version.", async (t) => { + const res = await mockApi.post("/api/v1/status").set("Cookie", cookie); + + t.equal(res.statusCode, 200); + t.equal(res.body.success, true); + t.ok( + Math.abs(Date.now() - res.body.body.serverTime) < 5_000, + "Should be roughly the current time (5 seconds lenience)", + ); + t.equal(res.body.body.version, VERSION_PRETTY); + t.equal(res.body.body.whoami, 1); + t.type(res.body.body.startTime, "number", "Should return a number for startTime."); + + t.end(); + }); + + t.test("Should echo the provided echo param.", async (t) => { + const res = await mockApi.post("/api/v1/status").set("Cookie", cookie).send({ + echo: "foobar", + }); + + t.equal(res.statusCode, 200); + t.equal(res.body.success, true); + t.equal(res.body.body.echo, "foobar"); + t.ok( + Math.abs(Date.now() - res.body.body.serverTime) < 5_000, + "Should be roughly the current time (5 seconds lenience)", + ); + t.equal(res.body.body.version, VERSION_PRETTY); + t.equal(res.body.body.whoami, 1); + t.type(res.body.body.startTime, "number", "Should return a number for startTime."); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/status/router.ts b/typescript/server/src/server/router/api/v1postgres/status/router.ts new file mode 100644 index 000000000..3190b37e2 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/status/router.ts @@ -0,0 +1,70 @@ +import { SYMBOL_TACHI_API_AUTH } from "#lib/constants/tachi"; +import { VERSION_PRETTY } from "#lib/constants/version"; +import { Router } from "express"; + +const router: Router = Router({ mergeParams: true }); + +const startTime = Date.now(); + +/** + * Returns the current status of the Tachi Server. + * + * @name GET /api/v1/status + */ +router.get("/", (req, res) => { + let echo; + + if (typeof req.query.echo === "string") { + echo = req.query.echo; + } + + return res.status(200).json({ + success: true, + description: "Status check successful.", + body: { + serverTime: Date.now(), + startTime, + version: VERSION_PRETTY, + whoami: req[SYMBOL_TACHI_API_AUTH].userID, + + // converts {foo: true, bar: false, baz: true} into [foo, baz] + permissions: Object.entries(req[SYMBOL_TACHI_API_AUTH].permissions) + .filter((e) => e[1]) + .map((e) => e[0]), + echo, + }, + }); +}); + +/** + * Returns the current status of the Tachi Server, but as a POST + * request, for that kind of testing. + * + * @name POST /api/v1/status + */ +router.post("/", (req, res) => { + let echo; + + if (typeof req.safeBody.echo === "string") { + echo = req.safeBody.echo; + } + + return res.status(200).json({ + success: true, + description: "Status check successful.", + body: { + serverTime: Date.now(), + startTime, + version: VERSION_PRETTY, + whoami: req[SYMBOL_TACHI_API_AUTH].userID, + + // converts {foo: true, bar: false, baz: true} into [foo, baz] + permissions: Object.entries(req[SYMBOL_TACHI_API_AUTH].permissions) + .filter((e) => e[1]) + .map((e) => e[0]), + echo, + }, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/api-tokens/router.test.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/api-tokens/router.test.ts new file mode 100644 index 000000000..0c82f1eb5 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/api-tokens/router.test.ts @@ -0,0 +1,289 @@ +import type { UserDocument } from "tachi-common"; + +import db from "#services/mongo/db"; +import { CreateFakeAuthCookie } from "#test-utils/fake-auth"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import t from "tap"; + +t.test("GET /api/v1/users/:userID/api-tokens", async (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(async () => { + await db["api-tokens"].remove({}); + await db["api-tokens"].insert([ + { + userID: 1, + identifier: "foo", + permissions: {}, + token: "tfoo", + fromAPIClient: null, + }, + { + userID: 1, + identifier: "bar", + permissions: {}, + token: "tbar", + fromAPIClient: null, + }, + { + userID: 2, + identifier: "baz", + permissions: {}, + token: "tbaz", + fromAPIClient: null, + }, + ]); + }); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should return this users tokens alone.", async (t) => { + const res = await mockApi.get("/api/v1/users/1/api-tokens").set("Cookie", cookie); + + t.equal(res.statusCode, 200); + + // sort these alphabetically so that strictsame can work properly + t.strictSame( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + res.body.body.sort((a: any, b: any) => a.identifier - b.identifier), + [ + { + userID: 1, + identifier: "foo", + permissions: {}, + token: "tfoo", + fromAPIClient: null, + }, + { + userID: 1, + identifier: "bar", + permissions: {}, + token: "tbar", + fromAPIClient: null, + }, + ], + ); + + t.end(); + }); + + t.test("Should require authentication as that user.", async (t) => { + const res = await mockApi.get("/api/v1/users/1/api-tokens"); + + t.equal(res.statusCode, 401); + + await db.users.insert({ + username: "test", + usernameLowercase: "test", + id: 2, + } as UserDocument); + + const res2 = await mockApi.get("/api/v1/users/2/api-tokens").set("Cookie", cookie); + + t.equal(res2.statusCode, 403); + + t.end(); + }); + + t.end(); +}); + +t.test("DELETE /api/v1/users/:userID/api-tokens/:token", async (t) => { + t.beforeEach(ResetDBState); + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should delete the cookie at that token.", async (t) => { + const res = await mockApi + .delete("/api/v1/users/1/api-tokens/fake_api_token") + .set("Cookie", cookie); + + t.equal(res.statusCode, 200); + + const dbRes = await db["api-tokens"].findOne({ + token: "fake_api_token", + }); + + t.equal(dbRes, null, "Should delete the token in the database"); + + t.end(); + }); + + t.test("Returns 404 if token doesn't exist.", async (t) => { + const res = await mockApi + .delete("/api/v1/users/1/api-tokens/non_exist_token") + .set("Cookie", cookie); + + t.equal(res.statusCode, 404); + + t.end(); + }); + + t.test("Must return 404 if the token belongs to another user.", async (t) => { + await db["api-tokens"].insert({ + identifier: "foo", + permissions: {}, + token: "foo", + userID: 2, + fromAPIClient: null, + }); + + const res = await mockApi.delete("/api/v1/users/1/api-tokens/foo").set("Cookie", cookie); + + // so as not to reveal that this token exists. + t.equal(res.statusCode, 404); + + const dbRes = await db["api-tokens"].findOne({ token: "foo" }); + + t.not(dbRes, null, "Should not have deleted the token."); + + t.end(); + }); + + t.test("Must require authentication as that user.", async (t) => { + const res = await mockApi.delete("/api/v1/users/1/api-tokens/foo"); + + t.equal(res.statusCode, 401); + + t.end(); + }); + + t.end(); +}); + +t.test("POST /api/v1/users/:userID/api-tokens/create", async (t) => { + t.beforeEach(ResetDBState); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should create a new API Key for this user with provided permissions.", async (t) => { + const res = await mockApi + .post("/api/v1/users/1/api-tokens/create") + .set("Cookie", cookie) + .send({ + identifier: "Hello World", + permissions: ["submit_score", "customise_profile"], + }); + + t.equal(res.statusCode, 200, "Should return 200."); + + t.hasStrict( + res.body.body, + { + identifier: "Hello World", + permissions: { submit_score: true, customise_profile: true }, + userID: 1, + fromAPIClient: null, + }, + "Should return a conforming API Token.", + ); + + const dbRes = await db["api-tokens"].findOne({ + identifier: "Hello World", + }); + + t.hasStrict( + dbRes, + { + identifier: "Hello World", + permissions: { submit_score: true, customise_profile: true }, + userID: 1, + fromAPIClient: null, + }, + "Should insert a conforming API Token into the database.", + ); + + t.end(); + }); + + t.test( + "Should create a new API Key for this user according to an existing clientID.", + async (t) => { + const res = await mockApi + .post("/api/v1/users/1/api-tokens/create") + .set("Cookie", cookie) + .send({ + clientID: "OAUTH2_CLIENT_ID", + }); + + t.equal(res.statusCode, 200, "Should return 200."); + + t.hasStrict( + res.body.body, + { + identifier: "Test_Service", + permissions: { customise_profile: true }, + userID: 1, + fromAPIClient: "OAUTH2_CLIENT_ID", + }, + "Should return a conforming API Token, with the permissions from that client.", + ); + + const dbRes = await db["api-tokens"].findOne({ + identifier: "Test_Service", + }); + + t.hasStrict( + dbRes, + { + identifier: "Test_Service", + permissions: { customise_profile: true }, + userID: 1, + fromAPIClient: "OAUTH2_CLIENT_ID", + }, + "Should insert a conforming API Token into the database.", + ); + + t.end(); + }, + ); + + t.test("Should reject requests that use both provided permissions and clientID.", async (t) => { + const res = await mockApi + .post("/api/v1/users/1/api-tokens/create") + .set("Cookie", cookie) + .send({ + identifier: "Hello World", + permissions: ["submit_score", "customise_profile"], + clientID: "OAUTH2_CLIENT_ID", + }); + + t.equal(res.statusCode, 400, "Should return 400."); + t.match( + res.body.description, + /clientID creation and permissions creation at the same time/iu, + ); + + t.end(); + }); + + t.test("Should reject requests with no provided permissions or clientID.", async (t) => { + const res = await mockApi + .post("/api/v1/users/1/api-tokens/create") + .set("Cookie", cookie) + .send({ + identifier: "Hello World", + }); + + t.equal(res.statusCode, 400, "Should return 400."); + t.match(res.body.description, /must specify either clientID or permissions/iu); + + t.end(); + }); + + t.test("Should reject invalid permissions.", async (t) => { + const res = await mockApi + .post("/api/v1/users/1/api-tokens/create") + .set("Cookie", cookie) + .send({ + identifier: "Hello World", + permissions: ["submit_score", "invalid_permission"], + }); + + t.equal(res.statusCode, 400, "Should return 400."); + t.match(res.body.description, /invalid_permission/iu); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/api-tokens/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/api-tokens/router.ts new file mode 100644 index 000000000..6cf7e692b --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/api-tokens/router.ts @@ -0,0 +1,181 @@ +import { log } from "#lib/log/log.js"; +import prValidate from "#server/middleware/prudence-validate"; +import db from "#services/mongo/db"; +import { Random20Hex } from "#utils/misc"; +import { GetTachiData } from "#utils/req-tachi-data"; +import { FormatUserDoc } from "#utils/user"; +import { Router } from "express"; +import { p } from "prudence"; +import { ALL_PERMISSIONS, type APIPermissions, type APITokenDocument } from "tachi-common"; + +import { RequireSelfRequestFromUser } from "../middleware"; + +const router: Router = Router({ mergeParams: true }); + +router.use(RequireSelfRequestFromUser); + +/** + * Retrieve this users API tokens. + * This request MUST be performed with session-level auth. + * + * @name GET /api/v1/users/:userID/api-tokens + */ +router.get("/", async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + + const keys = await db["api-tokens"].find({ + userID: user.id, + }); + + return res.status(200).json({ + success: true, + description: `Returned ${keys.length} keys.`, + body: keys, + }); +}); + +/** + * Create a new API token. + * + * @param clientID - Create a token that has the permissions implied from this client. + * @param identifier - A user provided string to identify this API Key. + * @param permissions - An array of strings dictating what permissions to create with. + * This is incompatible with the first option. + * + * @name POST /api/v1/users/:userID/api-tokens/create + */ +router.post( + "/create", + prValidate({ + permissions: p.optional([p.isIn(Object.keys(ALL_PERMISSIONS))]), + identifier: "*string", + clientID: "*string", + }), + async (req, res) => { + const body = req.safeBody as { + clientID?: string; + identifier?: string; + permissions?: Array; + }; + + if (body.clientID !== undefined && body.permissions) { + return res.status(400).json({ + success: false, + description: `Cannot use ClientID creation and permissions creation at the same time!`, + }); + } + + let permissions: Array; + + const user = GetTachiData(req, "requestedUser"); + + let identifier: string; + let fromAPIClient = null; + + if (body.clientID !== undefined) { + const client = await db["api-clients"].findOne( + { + clientID: body.clientID, + }, + { + projection: { + clientSecret: 0, + }, + }, + ); + + if (!client) { + return res.status(404).json({ + success: false, + description: `This client does not exist.`, + }); + } + + const exists = await db["api-tokens"].findOne({ + userID: user.id, + fromAPIClient: client.clientID, + }); + + if (exists) { + return res.status(200).json({ + success: true, + description: `Returned existing key`, + body: exists, + }); + } + + permissions = client.requestedPermissions; + identifier = client.name; + fromAPIClient = client.clientID; + + log.info( + `Creating API Key for ${FormatUserDoc(user)} from ${client.name} specification.`, + ); + } else if (body.permissions) { + permissions = body.permissions; + identifier = body.identifier ?? "Custom Token"; + + log.info(`Creating API Key for ${FormatUserDoc(user)} with ${permissions.join(", ")}.`); + } else { + return res.status(400).json({ + success: false, + description: `Invalid request, must specify either clientID or permissions.`, + }); + } + + const permissionsObject = Object.fromEntries(permissions.map((e) => [e, true])); + + const apiTokenDocument: APITokenDocument = { + identifier, + permissions: permissionsObject, + token: Random20Hex(), + userID: user.id, + fromAPIClient, + }; + + await db["api-tokens"].insert(apiTokenDocument); + + log.info(`Inserted new API Key for ${FormatUserDoc(user)}.`); + + return res.status(200).json({ + success: true, + description: `Successfully created new API Token.`, + body: apiTokenDocument, + }); + }, +); + +/** + * Delete this token. + * + * @name DELETE /api/v1/users/:userID/api-token/:token + */ +router.delete("/:token", async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + + log.info(`received request from ${FormatUserDoc(user)} to delete token ${req.params.token}.`); + + const token = await db["api-tokens"].findOne({ + token: req.params.token, + userID: user.id, + }); + + if (!token) { + return res.status(404).json({ + success: false, + description: `This key does not exist.`, + }); + } + + await db["api-tokens"].remove({ token: req.params.token }); + + log.info(`Deleted ${req.params.token}, which belonged to ${FormatUserDoc(user)}.`); + + return res.status(200).json({ + success: true, + description: `Removed Token.`, + body: {}, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/banner/router.test.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/banner/router.test.ts new file mode 100644 index 000000000..60b46c217 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/banner/router.test.ts @@ -0,0 +1,88 @@ +import { CDNStoreOrOverwrite } from "#lib/cdn/cdn"; +import { GetProfileBannerURL } from "#lib/cdn/url-format"; +import { log } from "#lib/log/log.js"; +import db from "#services/mongo/db"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { GetKTDataBuffer } from "#test-utils/test-data"; +import t from "tap"; + +t.test("GET /api/v1/users/:userID/banner", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return the default profile banner if user has no custom banner", async (t) => { + await CDNStoreOrOverwrite("/users/default/banner", "test"); + const res = await mockApi.get("/api/v1/users/1/banner").redirects(1); + + t.equal(res.statusCode, 200, "Should return 200."); + + t.equal(res.body.toString(), "test"); + + t.end(); + }); + + t.test("Should return a custom profile banner if one is set", async (t) => { + await CDNStoreOrOverwrite(GetProfileBannerURL(1, "checksum"), "foo"); + await db.users.update({ id: 1 }, { $set: { customBannerLocation: "checksum" } }); + const res = await mockApi.get("/api/v1/users/1/banner").redirects(1); + + t.equal(res.statusCode, 200, "Should return 200."); + + if (res.statusCode !== 200) { + log.info( + { + body: res.body, + }, + "Unexpected non-200 in CDN tests, received this as a body.", + ); + } + + t.equal(res.body.toString(), "foo"); + + t.end(); + }); + + t.end(); +}); + +t.test("PUT /api/v1/users/:userID/banner", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should set a profile banner if user has no custom banner", async (t) => { + const img = GetKTDataBuffer("/images/acorn.png"); + + const res = await mockApi + .put("/api/v1/users/1/banner") + .set("Authorization", "Bearer fake_api_token") + .attach("banner", img, "file.jpg"); + + t.equal(res.statusCode, 200); + + const get = await mockApi.get(res.body.body.get).redirects(1); + + t.strictSame(img, get.body, "Profile banner should be stored."); + + t.end(); + }); + + t.test("Should set a profile banner if user has custom banner", async (t) => { + await db.users.update({ id: 1 }, { $set: { customBannerLocation: "checksum" } }); + + const img = GetKTDataBuffer("/images/acorn.png"); + + const res = await mockApi + .put("/api/v1/users/1/banner") + .set("Authorization", "Bearer fake_api_token") + .attach("banner", img, "file.jpg"); + + t.equal(res.statusCode, 200); + + const get = await mockApi.get(res.body.body.get).redirects(1); + + t.strictSame(img, get.body, "Profile banner should be stored."); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/banner/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/banner/router.ts new file mode 100644 index 000000000..634139227 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/banner/router.ts @@ -0,0 +1,134 @@ +import { CDNDelete, CDNRedirect, CDNStoreOrOverwrite } from "#lib/cdn/cdn"; +import { GetProfileBannerURL } from "#lib/cdn/url-format"; +import { ONE_MEGABYTE } from "#lib/constants/filesize"; +import { log } from "#lib/log/log.js"; +import { RequirePermissions } from "#server/middleware/auth"; +import { CreateMulterSingleUploadMiddleware } from "#server/middleware/multer-upload"; +import db from "#services/mongo/db"; +import { HashSHA256 } from "#utils/crypto"; +import { GetTachiData } from "#utils/req-tachi-data"; +import { FormatUserDoc } from "#utils/user"; +import { Router } from "express"; + +import { RequireAuthedAsUser } from "../middleware"; + +// note: this is just the ../pfp/router.ts code copied and altered. + +const router: Router = Router({ mergeParams: true }); + +/** + * Sets a profile banner. + * + * @param banner - A JPG, PNG or GIF file less than 1mb. + * @note although GIFs are supported, this functionality isn't documented on the site. + * this is kind of an easter egg. + * + * @name PUT /api/v1/users/:userID/banner + */ +router.put( + "/", + RequireAuthedAsUser, + RequirePermissions("customise_profile"), + CreateMulterSingleUploadMiddleware("banner", ONE_MEGABYTE), + async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + + if (!user.customBannerLocation) { + log.debug(`User ${FormatUserDoc(user)} set a custom profile banner.`); + } else { + log.debug(`User ${FormatUserDoc(user)} updated their profile banner.`); + } + + if (!req.file) { + log.error( + `Conflicting state - no req.file has been populated but passed middleware? (${FormatUserDoc( + user, + )})`, + ); + return res.status(500).json({ + success: false, + description: `An internal error has occured.`, + }); + } + + const contentHash = HashSHA256(req.file.buffer); + + if ( + req.file.mimetype === "image/jpeg" || + req.file.mimetype === "image/png" || + req.file.mimetype === "image/gif" + ) { + await CDNStoreOrOverwrite(GetProfileBannerURL(user.id, contentHash), req.file.buffer); + } else { + return res.status(400).json({ + success: false, + description: `Invalid file - only JPG and PNG files are supported.`, + }); + } + + if (req.session.tachi?.user) { + req.session.tachi.user.customBannerLocation = contentHash; + } + + await db.users.update({ id: user.id }, { $set: { customBannerLocation: contentHash } }); + + return res.status(200).json({ + success: true, + description: `Stored profile banner.`, + body: { + get: req.originalUrl, + }, + }); + }, +); + +/** + * Returns this user's profile banner. If the user does not have a custom profile banner, + * return the default profile banner. + * + * @name GET /api/v1/users/:userID/banner + */ +router.get("/", (req, res) => { + const user = GetTachiData(req, "requestedUser"); + + if (!user.customBannerLocation) { + res.setHeader("Content-Type", "image/png"); + CDNRedirect(res, "/users/default/banner"); + return; + } + + // express sniffs whether this is a png or jpg **and** browsers dont care either. + CDNRedirect(res, GetProfileBannerURL(user.id, user.customBannerLocation)); +}); + +/** + * Deletes this user's profile banner, and go back to the default profile banner. + * + * @name DELETE /api/v1/users/:userID/banner + */ +router.delete( + "/", + RequireAuthedAsUser, + RequirePermissions("customise_profile"), + async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + + if (!user.customBannerLocation) { + return res.status(404).json({ + success: false, + description: `You do not have a custom profile banner to delete.`, + }); + } + + await CDNDelete(GetProfileBannerURL(user.id, user.customBannerLocation)); + await db.users.update({ id: user.id }, { $set: { customBannerLocation: null } }); + + return res.status(200).json({ + success: true, + description: `Removed custom profile banner.`, + body: {}, + }); + }, +); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/following/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/following/router.ts new file mode 100644 index 000000000..4c6dc8651 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/following/router.ts @@ -0,0 +1,196 @@ +import type { integer } from "tachi-common"; + +import { log } from "#lib/log/log.js"; +import { ServerConfig } from "#lib/setup/config"; +import prValidate from "#server/middleware/prudence-validate"; +import db from "#services/mongo/db"; +import { GetUser } from "#utils/req-tachi-data"; +import { FormatUserDoc, GetUsersWithIDs, GetUserWithID } from "#utils/user"; +import { Router } from "express"; +import { p } from "prudence"; + +import { RequireSelfRequestFromUser } from "../middleware"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Retrieve who this user is following. + * + * @note Following a user means you get updates from them in your global activity feed. + * + * @name GET /api/v1/users/:userID/following + */ +router.get("/", async (req, res) => { + const user = GetUser(req); + + const settings = await db["user-settings"].findOne({ userID: user.id }); + + if (!settings) { + log.error({ user }, `User ${FormatUserDoc(user)} has no settings?`); + + return res.status(500).json({ + success: false, + description: `This user has no settings.`, + }); + } + + const friends = await GetUsersWithIDs(settings.following); + + return res.status(200).json({ + success: true, + description: `Found ${friends.length} friend${friends.length !== 1 ? "s" : ""}.`, + body: { + friends, + }, + }); +}); + +/** + * Follow a new user. + * + * @param userID - The user to follow. + * + * @name POST /api/v1/users/:userID/following/add + */ +router.post( + "/add", + RequireSelfRequestFromUser, + prValidate({ userID: p.isPositiveInteger }), + async (req, res) => { + const user = GetUser(req); + + const { userID: toFollow } = req.safeBody as { userID: integer }; + + if (user.id === toFollow) { + return res.status(400).json({ + success: false, + description: `Can't follow yourself. Bit self-indulgent!`, + }); + } + + const settings = await db["user-settings"].findOne({ userID: user.id }); + + if (!settings) { + log.error({ user }, `User ${FormatUserDoc(user)} has no settings?`); + + return res.status(500).json({ + success: false, + description: `This user has no settings.`, + }); + } + + if (settings.following.includes(toFollow)) { + return res.status(409).json({ + success: false, + description: `You are already following this user.`, + }); + } + + if (settings.following.length >= ServerConfig.MAX_FOLLOWING_AMOUNT) { + return res.status(400).json({ + success: false, + description: `You are following too many people. The max is ${ServerConfig.MAX_FOLLOWING_AMOUNT}.`, + }); + } + + const userToFollow = await GetUserWithID(toFollow); + + if (!userToFollow) { + return res.status(400).json({ + success: false, + description: `No user with the id '${toFollow}' exists.`, + }); + } + + // Instead of using $push in mongodb, we create a new array and set that. + // due to the above guard, it's not possible for this to ever result + // in a race condition. + const following = [...settings.following, toFollow]; + + await db["user-settings"].update( + { + userID: user.id, + }, + { + $set: { + following, + }, + }, + ); + + return res.status(200).json({ + success: true, + description: `Added ${userToFollow.username}.`, + body: {}, + }); + }, +); + +/** + * Unfollow a user. + * + * @param userID - The user to unfollow. + * + * @name POST /api/v1/users/:userID/following/remove + */ +router.post( + "/remove", + RequireSelfRequestFromUser, + prValidate({ userID: p.isPositiveInteger }), + async (req, res) => { + const user = GetUser(req); + + const { userID: toFollow } = req.safeBody as { userID: integer }; + + const settings = await db["user-settings"].findOne({ userID: user.id }); + + if (!settings) { + log.error({ user }, `User ${FormatUserDoc(user)} has no settings?`); + + return res.status(500).json({ + success: false, + description: `This user has no settings.`, + }); + } + + if (!settings.following.includes(toFollow)) { + return res.status(409).json({ + success: false, + description: `You are not following this user.`, + }); + } + + const userToFollow = await GetUserWithID(toFollow); + + if (!userToFollow) { + return res.status(400).json({ + success: false, + description: `No user with the id '${toFollow}' exists.`, + }); + } + + // Instead of using $pull in mongodb, we create a new array and set that. + // due to the above guard, it's not possible for this to ever result + // in a race condition. + const following = settings.following.filter((e) => e !== toFollow); + + await db["user-settings"].update( + { + userID: user.id, + }, + { + $set: { + following, + }, + }, + ); + + return res.status(200).json({ + success: true, + description: `Unfollowed ${userToFollow.username}.`, + body: {}, + }); + }, +); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/@gameSpecificRoutes/bms/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/@gameSpecificRoutes/bms/router.ts new file mode 100644 index 000000000..334400566 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/@gameSpecificRoutes/bms/router.ts @@ -0,0 +1,168 @@ +import { + CUSTOM_TACHI_BMS_TABLES, + HandleBMSTableBodyRequest, + HandleBMSTableHeaderRequest, + HandleBMSTableHTMLRequest, +} from "#lib/game-specific/custom-bms-tables"; +import { ValidatePlaytypeFromParamFor } from "#server/router/api/v1/games/_game/_playtype/middleware.js"; +import db from "#services/mongo/db"; +import { AssignToReqTachiData, GetTachiData, GetUGPT, GetUser } from "#utils/req-tachi-data"; +import { type RequestHandler, Router } from "express"; + +const router: Router = Router({ mergeParams: true }); + +const FindCustomBMSTable: RequestHandler = (req, res, next) => { + const { playtype, tableUrlName } = req.params; + + // find the table + const customTable = CUSTOM_TACHI_BMS_TABLES.find((t) => t.urlName === tableUrlName); + + if (!customTable) { + return res.status(404).json({ + success: false, + description: `No such table with the ID '${tableUrlName}' exists.`, + }); + } + + if (customTable.playtype && customTable.playtype !== playtype) { + return res.status(404).json({ + success: false, + description: `The table '${tableUrlName}' exists, but is for ${customTable.playtype}, not ${playtype}.`, + }); + } + + if (customTable.forSpecificUser !== true) { + return res.status(404).json({ + success: false, + description: `The table '${tableUrlName}' exists, but isn't user specific. You should be fetching this table from /api/v1/games instead of /api/v1/users/:userID.`, + }); + } + + AssignToReqTachiData(req, { customBMSTable: customTable }); + + next(); +}; + +/** + * Return some HTML for this custom table. + * + * @note Since this is the UGPT route, trying to fetch GPT custom tables + * will result in a 404. This applies for all subsequent :tableUrlName routes. + * + * @name GET /api/v1/users/:userID/games/bms/:playtype/custom-tables/:tableUrlName + */ +router.get( + "/:playtype/custom-tables/:tableUrlName", + ValidatePlaytypeFromParamFor("bms"), + FindCustomBMSTable, + (req, res) => { + const customTable = GetTachiData(req, "customBMSTable"); + + // This handles returning a response for us. + return HandleBMSTableHTMLRequest(customTable, req, res); + }, +); + +/** + * Return the header.json for this custom table. + * + * @name GET /api/v1/users/:userID/games/bms/:playtype/custom-tables/:tableUrlName/header.json + */ +router.get( + "/:playtype/custom-tables/:tableUrlName/header.json", + ValidatePlaytypeFromParamFor("bms"), + FindCustomBMSTable, + (req, res) => { + const customTable = GetTachiData(req, "customBMSTable"); + + // This handles returning a response for us. + return HandleBMSTableHeaderRequest(customTable, req, res); + }, +); + +/** + * Return the body.json for this custom table. + * + * @name GET /api/v1/users/:userID/games/bms/:playtype/custom-tables/:tableUrlName/body.json + */ +router.get( + "/:playtype/custom-tables/:tableUrlName/body.json", + ValidatePlaytypeFromParamFor("bms"), + FindCustomBMSTable, + (req, res) => { + const customTable = GetTachiData(req, "customBMSTable"); + + // This handles returning a response for us. + return HandleBMSTableBodyRequest(customTable, req, res); + }, +); + +const MD5_CHECKSUM_LENGTH = "60b725f10c9c85c70d97880dfe8191b3".length; +const SHA256_CHECKSUM_LENGTH = "87428fc522803d31065e7bce3cf03fe475096631e5e07bbd7a0fde60c4cf25c7" + .length; + +/** + * Get this user's best chart on the given chart MD5 or SHA256. + * + * @name GET /api/v1/users/:userID/games/bms/:playtype/best-score/:checksum + */ +router.get( + "/:playtype/best-score/:checksum", + ValidatePlaytypeFromParamFor("bms"), + async (req, res) => { + const user = GetUser(req); + + if (!req.params.checksum) { + return res.status(400).json({ success: false, description: "No checksum provided." }); + } + + const checksum = req.params.checksum.toLowerCase(); + + let query = {}; + + if (!/^[0-9a-f]+$/u.exec(checksum)) { + return res.status(400).json({ + success: false, + description: "Invalid checksum (Was not a MD5 or SHA256 checksum).", + }); + } + + if (checksum.length === MD5_CHECKSUM_LENGTH) { + query = { + "data.hashMD5": checksum, + }; + } else if (checksum.length === SHA256_CHECKSUM_LENGTH) { + query = { + "data.hashSHA256": checksum, + }; + } else { + return res.status(400).json({ + success: false, + description: "Invalid checksum length (Was not a MD5 or SHA256 checksum).", + }); + } + + const chart = await db.charts.bms.findOne({ + ...query, + }); + + if (!chart) { + return res + .status(404) + .json({ success: false, description: "No chart found with the given checksum." }); + } + + const pb = await db["personal-bests"].findOne({ + game: "bms", + playtype: chart.playtype, + userID: user.id, + chartID: chart.chartID, + }); + + const description = pb ? "Best score found." : "Player has not played this chart."; + + return res.status(200).json({ success: true, description, body: pb }); + }, +); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/@gameSpecificRoutes/iidx/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/@gameSpecificRoutes/iidx/router.ts new file mode 100644 index 000000000..7574c74af --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/@gameSpecificRoutes/iidx/router.ts @@ -0,0 +1,223 @@ +import type { + ChartDocument, + integer, + PBScoreDocument, + Playtypes, + SongDocument, +} from "tachi-common"; +import type { GetEnumValue } from "tachi-common/types/metrics"; + +import { + CUSTOM_TACHI_IIDX_PLAYLISTS, + type TachiIIDXPlaylist, +} from "#lib/game-specific/iidx-playlists"; +import { ResolveSongAndChart } from "#lib/score-import/import-types/common/batch-manual/converter"; +import { EAM_VERSION_NAMES } from "#lib/score-import/import-types/common/eamusement-iidx-csv/parser"; +import { AggressiveRateLimitMiddleware } from "#server/middleware/rate-limiter"; +import { ValidatePlaytypeFromParamFor } from "#server/router/api/v1/games/_game/_playtype/middleware.js"; +import db from "#services/mongo/db"; +import { GetUser } from "#utils/req-tachi-data"; +import { Router } from "express"; + +const router: Router = Router({ mergeParams: true }); + +const EAMUSEMENT_CSV_HEADER = `バージョン,タイトル,ジャンル,アーティスト,プレー回数,BEGINNER 難易度,BEGINNER スコア,BEGINNER PGreat,BEGINNER Great,BEGINNER ミスカウント,BEGINNER クリアタイプ,BEGINNER DJ LEVEL,NORMAL 難易度,NORMAL スコア,NORMAL PGreat,NORMAL Great,NORMAL ミスカウント,NORMAL クリアタイプ,NORMAL DJ LEVEL,HYPER 難易度,HYPER スコア,HYPER PGreat,HYPER Great,HYPER ミスカウント,HYPER クリアタイプ,HYPER DJ LEVEL,ANOTHER 難易度,ANOTHER スコア,ANOTHER PGreat,ANOTHER Great,ANOTHER ミスカウント,ANOTHER クリアタイプ,ANOTHER DJ LEVEL,LEGGENDARIA 難易度,LEGGENDARIA スコア,LEGGENDARIA PGreat,LEGGENDARIA Great,LEGGENDARIA ミスカウント,LEGGENDARIA クリアタイプ,LEGGENDARIA DJ LEVEL,最終プレー日時`; + +function ConvertEamGrade(grade: GetEnumValue<"iidx:DP" | "iidx:SP", "grade">) { + // eamusement has no concept of max or max-. + if (grade === "MAX" || grade === "MAX-") { + return "AAA"; + } + + return grade; +} + +function ConvertEamLamp(lamp: GetEnumValue<"iidx:DP" | "iidx:SP", "lamp">) { + if (lamp === "FULL COMBO") { + return "FULLCOMBO CLEAR"; // weird, but ok + } + + return lamp; +} + +/** + * Retrieve this users PBs in eamusement CSV format. + * + * @name GET /api/v1/users/:userID/games/iidx/:playtype/eamusement-csv + */ +router.get( + "/:playtype/eamusement-csv", + ValidatePlaytypeFromParamFor("iidx"), + AggressiveRateLimitMiddleware, + async (req, res) => { + const game = "iidx"; + + const playtype = req.params.playtype as Playtypes["iidx"]; + const user = GetUser(req); + + const pbData: Array<{ + _id: integer; + pbs: Array>; + song: SongDocument<"iidx">; + }> = await db["personal-bests"].aggregate([ + { + $match: { + userID: user.id, + game, + playtype, + isPrimary: true, + }, + }, + { + $group: { + // group our scores on the song + _id: "$songID", + pbs: { $push: "$$ROOT" }, + }, + }, + { + $lookup: { + from: "songs-iidx", + foreignField: "id", + localField: "_id", + as: "song", + }, + }, + { + $unwind: "$song", + }, + ]); + + const rows = [EAMUSEMENT_CSV_HEADER]; + + // get all relevant charts + const charts = await db.charts.iidx.find({ + songID: { $in: pbData.map((e) => e.song.id) }, + difficulty: { $in: ["NORMAL", "HYPER", "ANOTHER", "LEGGENDARIA"] }, + }); + + // get a lookup table for songID + difficulty -> chart. + const chartMap = new Map(); + + for (const chart of charts) { + chartMap.set(`${chart.songID}-${chart.difficulty}`, chart); + } + + for (const { pbs, song } of pbData) { + let version = "UNKNOWN"; + const tachiVer = song.data.displayVersion; + + if (tachiVer !== null) { + // @ts-expect-error We're abusing enums which already aren't meant + // for this kind of lookup task. Ah well! + + version = EAM_VERSION_NAMES[tachiVer] ?? tachiVer; + } + + const row = [ + version, + song.title, + song.data.genre, + song.artist, + "0", // always 0, who cares? + ]; + + let lastPlayed = 0; + + for (const difficulty of [ + "BEGINNER", + "NORMAL", + "HYPER", + "ANOTHER", + "LEGGENDARIA", + ] as const) { + const chart = chartMap.get(`${song.id}-${difficulty}`); + let pb; + + // this song might not have a beginner/normal/hyper/another/legg + if (chart) { + // try and find the user's PB + pb = pbs.find((e) => e.chartID === chart.chartID); + } + + if (pb) { + row.push( + chart ? chart.level : "0", + pb.scoreData.score.toString(), // ex + pb.scoreData.judgements.pgreat?.toString() ?? "0", // pgreat + pb.scoreData.judgements.great?.toString() ?? "0", // great + pb.scoreData.optional.bp?.toString() ?? "0", // BP + ConvertEamLamp(pb.scoreData.lamp), // lamp + ConvertEamGrade(pb.scoreData.grade), // grade + ); + + if (pb.timeAchieved !== null && lastPlayed < pb.timeAchieved) { + lastPlayed = pb.timeAchieved; + } + } else { + row.push( + chart ? chart.level : "0", + "0", // ex + "0", // pgreat + "0", // great + "---", // BP + "NO PLAY", // lamp + "---", // grade + ); + } + } + + // last played. This will be 1970-01-01 if this user has never played this chart + // with a timestamp. + row.push(new Date(lastPlayed).toISOString()); + + // IIDX uses a "naive" CSV format. that is to say -- there's no escaping. + // God forbid a song title like "19, november" get output here, because it will + // just break the format. That's what the official site does though. + // bug-for-bug compatibility! + // at the very least, we'll replace , with \,. That should be fine. + rows.push(row.map((e) => e.replace(/,/gu, "\\,")).join(",")); + } + + return res.status(200).json({ + success: true, + description: `Created e-amusement CSV.`, + body: rows.join("\n"), + }); + }, +); + +/** + * Retrieve this playlist. + * + * @name GET /api/v1/users/:userID/games/iidx/:playtype/playlists/:playlistID + */ +router.get("/:playtype/playlists/:playlistID", async (req, res) => { + const user = GetUser(req); + + const playlist: TachiIIDXPlaylist | undefined = CUSTOM_TACHI_IIDX_PLAYLISTS.find( + (e) => + (e.playtype === null || e.playtype === req.params.playtype) && + e.urlName === req.params.playlistID, + ); + + if (!playlist) { + return res.status(404).json({ + success: false, + description: `No such playlist '${req.params.playlistID}' exists for '${req.params.playtype}'.`, + }); + } + + if (playlist.forSpecificUser !== true) { + return res.status(404).json({ + success: false, + description: `This playlist is not for a specific user. Use the /games/:game endpoint instead.`, + }); + } + + const body = await playlist.getPlaylists(user.id, req.params.playtype as "DP" | "SP"); + + return res.status(200).json(body); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/@gameSpecificRoutes/jubeat/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/@gameSpecificRoutes/jubeat/router.ts new file mode 100644 index 000000000..6cb4223fe --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/@gameSpecificRoutes/jubeat/router.ts @@ -0,0 +1,35 @@ +import { GetPBsForJubility } from "#game-implementations/games/jubeat"; +import { GetRelevantSongsAndCharts } from "#utils/db"; +import { GetUser } from "#utils/req-tachi-data"; +import { Router } from "express"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Retrieve the PBs that went into this users jubility ranking. + * + * @name GET /api/v1/users/:userID/games/jubeat/Single/jubility + */ +router.get("/Single/jubility", async (req, res) => { + const user = GetUser(req); + + const { bestHotScores, bestScores } = await GetPBsForJubility(user.id); + + const { songs, charts } = await GetRelevantSongsAndCharts( + [...bestHotScores, ...bestScores], + "jubeat", + ); + + return res.status(200).json({ + success: true, + description: `Retrieved scores that went into this users jubility.`, + body: { + songs, + charts, + pickUp: bestHotScores, + other: bestScores, + }, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/@gameSpecificRoutes/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/@gameSpecificRoutes/router.ts new file mode 100644 index 000000000..51e91822a --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/@gameSpecificRoutes/router.ts @@ -0,0 +1,17 @@ +// This file is special. These routes are "gptSpecific". They only apply to certain games +// and playtypes. This is for things like - say - eamusement exports, which only make sense +// for certain games. + +import { Router } from "express"; + +import bmsRouter from "./bms/router"; +import iidxRouter from "./iidx/router"; +import jubeatRouter from "./jubeat/router"; + +const router: Router = Router({ mergeParams: true }); + +router.use("/bms", bmsRouter); +router.use("/iidx", iidxRouter); +router.use("/jubeat", jubeatRouter); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/folders/_folderID/router.test.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/folders/_folderID/router.test.ts new file mode 100644 index 000000000..79bf24df6 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/folders/_folderID/router.test.ts @@ -0,0 +1,204 @@ +import type { ChartDocument, FolderDocument, ScoreDocument, SongDocument } from "tachi-common"; + +import db from "#services/mongo/db"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { + GetKTDataJSON, + Testing511SPA, + TestingIIDXFolderSP10, + TestingIIDXSPScore, + TestingIIDXSPScorePB, +} from "#test-utils/test-data"; +import { CreateFolderChartLookup } from "#utils/folder"; +import deepmerge from "deepmerge"; +import t from "tap"; + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/folders/:folderID", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(async () => { + const folder = deepmerge(TestingIIDXFolderSP10, { + folderID: "testing_folder", + }) as FolderDocument; + + await db.folders.insert(folder); + await CreateFolderChartLookup(folder, true); + await db["personal-bests"].insert(deepmerge(TestingIIDXSPScorePB, {})); + }); + + t.test("Should return a user's PBs on a given folder.", async (t) => { + const res = await mockApi.get("/api/v1/users/1/games/iidx/SP/folders/testing_folder"); + + t.equal(res.body.body.songs.length, 1); + t.equal(res.body.body.charts.length, 1); + t.equal(res.body.body.charts[0].chartID, Testing511SPA.chartID); + t.equal(res.body.body.pbs.length, 1); + t.equal(res.body.body.pbs[0].chartID, Testing511SPA.chartID); + t.equal(res.body.body.folder.folderID, "testing_folder"); + + t.end(); + }); + + t.test("Should return 404 if this folder does not exist.", async (t) => { + const res = await mockApi.get("/api/v1/users/1/games/iidx/SP/folders/fake_folder"); + + t.equal(res.statusCode, 404); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/folders/:folderID/timeline", (t) => { + const folder = deepmerge(TestingIIDXFolderSP10, { + folderID: "testing_folder", + }) as FolderDocument; + + t.beforeEach(ResetDBState); + t.beforeEach(async () => { + await db.folders.insert(folder); + await CreateFolderChartLookup(folder, true); + await db["personal-bests"].insert(deepmerge(TestingIIDXSPScorePB, {})); + }); + + t.test("Should return the users scores on this folder in timeline order", async (t) => { + // set up a more realistic scenario so we can fire more data at it. + await db.songs.iidx.remove({}); + await db.charts.iidx.remove({}); + await db["folder-chart-lookup"].remove({}); + await db.songs.iidx.insert( + GetKTDataJSON("./tachi/tachi-songs-iidx.json") as Array>, + ); + await db.charts.iidx.insert( + GetKTDataJSON("./tachi/tachi-charts-iidx.json") as Array< + ChartDocument<"iidx:DP" | "iidx:SP"> + >, + ); + + await CreateFolderChartLookup(folder, true); + + await db.scores.insert([ + deepmerge(TestingIIDXSPScore, { + scoreID: "OTHER_SCORE_ID", + timeAchieved: 500, + songID: 5, + chartID: "f3e7f84103d68f9f27193f037f35d0bca8c6d607", + }), + deepmerge(TestingIIDXSPScore, { + scoreID: "OTHER_SCORE_ID_2", + timeAchieved: 100, + songID: 5, + chartID: "f3e7f84103d68f9f27193f037f35d0bca8c6d607", + }), + deepmerge(TestingIIDXSPScore, { + scoreID: "OTHER_SCORE_ID_NULL", + timeAchieved: null, + songID: 5, + chartID: "f3e7f84103d68f9f27193f037f35d0bca8c6d607", + }), + deepmerge(TestingIIDXSPScore, { + scoreData: { + lamp: "EASY CLEAR", + enumIndexes: { + lamp: 3, + }, + }, + scoreID: "OTHER_SCORE_ID_3", + timeAchieved: 50, + songID: 5, + chartID: "f3e7f84103d68f9f27193f037f35d0bca8c6d607", + }), + deepmerge(TestingIIDXSPScore, { + scoreID: "OTHER_SCORE_ID_4", + timeAchieved: 200, + songID: 6, + chartID: "3b5fa295d243c131752e2f1ad835998f6dad2e97", + }), + ]); + + const res = await mockApi.get( + "/api/v1/users/1/games/iidx/SP/folders/testing_folder/timeline?criteriaType=lamp&criteriaValue=CLEAR", + ); + + t.equal(res.body.body.scores.length, 3); + + t.equal( + res.body.body.scores[0].scoreID, + "TESTING_SCORE_ID", + "First score should be TESTING_SCORE_ID, as it has a timeAchieved of null.", + ); + t.equal( + res.body.body.scores[1].scoreID, + "OTHER_SCORE_ID_2", + "Second score returned should be OTHER_SCORE_ID_2", + ); + t.equal( + res.body.body.scores[2].scoreID, + "OTHER_SCORE_ID_4", + "Third score should be OTHER_SCORE_ID_4, as it was achieved later.", + ); + t.notOk( + res.body.body.scores.some((k: ScoreDocument) => k.scoreID === "OTHER_SCORE_ID_NULL"), + "OTHER_SCORE_ID_NULL should never appear, as it is a null timestamp for a score that has a real timestamp.", + ); + + t.end(); + }); + + t.test("Should reject invalid criteriaTypes", async (t) => { + const res = await mockApi.get( + "/api/v1/users/1/games/iidx/SP/folders/testing_folder/timeline?criteriaType=invalid", + ); + + t.equal(res.statusCode, 400); + + t.end(); + }); + + t.test("Should reject invalid indexes for lamps", async (t) => { + const res = await mockApi.get( + "/api/v1/users/1/games/iidx/SP/folders/testing_folder/timeline?criteriaType=lamp&criteriaValue=-1", + ); + + t.equal(res.statusCode, 400); + + const res2 = await mockApi.get( + "/api/v1/users/1/games/iidx/SP/folders/testing_folder/timeline?criteriaType=lamp&criteriaValue=0.5", + ); + + t.equal(res2.statusCode, 400); + + const res3 = await mockApi.get( + "/api/v1/users/1/games/iidx/SP/folders/testing_folder/timeline?criteriaType=lamp&criteriaValue=100", + ); + + t.equal(res3.statusCode, 400); + + t.end(); + }); + + t.test("Should reject invalid indexes for grades", async (t) => { + const res = await mockApi.get( + "/api/v1/users/1/games/iidx/SP/folders/testing_folder/timeline?criteriaType=grade&criteriaValue=-1", + ); + + t.equal(res.statusCode, 400); + + const res2 = await mockApi.get( + "/api/v1/users/1/games/iidx/SP/folders/testing_folder/timeline?criteriaType=grade&criteriaValue=0.5", + ); + + t.equal(res2.statusCode, 400); + + const res3 = await mockApi.get( + "/api/v1/users/1/games/iidx/SP/folders/testing_folder/timeline?criteriaType=grade&criteriaValue=100", + ); + + t.equal(res3.statusCode, 400); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/folders/_folderID/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/folders/_folderID/router.ts new file mode 100644 index 000000000..de24abad5 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/folders/_folderID/router.ts @@ -0,0 +1,211 @@ +import type { FilterQuery } from "mongodb"; + +import prValidate from "#server/middleware/prudence-validate"; +import db from "#services/mongo/db"; +import { GetEnumDistForFolder, GetFolderCharts, GetPBsOnFolder } from "#utils/folder"; +import { GetTachiData, GetUGPT } from "#utils/req-tachi-data"; +import { ParseStrPositiveInt } from "#utils/string-checks"; +import { Router } from "express"; +import { + GetGamePTConfig, + GetScoreMetricConf, + type ScoreDocument, + ValidateMetric, +} from "tachi-common"; + +import { GetFolderFromParam } from "../../../../../../../games/_game/_playtype/folders/middleware"; +import { RequireSelfRequestFromUser } from "../../../../../middleware"; + +const router: Router = Router({ mergeParams: true }); + +router.use(GetFolderFromParam); + +/** + * Returns a users pbs on this folder. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/folders/:folderID + */ +router.get("/", async (req, res) => { + const { user } = GetUGPT(req); + + const folder = GetTachiData(req, "folderDoc"); + + const { songs, charts, pbs } = await GetPBsOnFolder(user.id, folder); + + return res.status(200).json({ + success: true, + description: `Returned ${pbs.length} pbs.`, + body: { + songs, + charts, + pbs, + folder, + }, + }); +}); + +/** + * Returns a users stats on this folder. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/folders/:folderID/stats + */ +router.get("/stats", async (req, res) => { + const { user } = GetUGPT(req); + + const folder = GetTachiData(req, "folderDoc"); + + const stats = await GetEnumDistForFolder(user.id, folder); + + return res.status(200).json({ + success: true, + description: `Returned statistics for ${folder.title}.`, + body: { + folder, + stats, + }, + }); +}); + +/** + * Add a folder to the list of recently-viewed folders. This can only + * be performed by a session-level token, to stop rogue API keys from causing + * trouble. Also, it's a post request, to avoid funny SSRF stuff. + * + * @name POST /api/v1/users/:userID/games/:game/:playtype/folders/:folderID/viewed + */ +router.post("/viewed", RequireSelfRequestFromUser, async (req, res) => { + const { user } = GetUGPT(req); + + const folder = GetTachiData(req, "folderDoc"); + + await db["recent-folder-views"].update( + { + userID: user.id, + game: folder.game, + playtype: folder.playtype, + folderID: folder.folderID, + }, + { + $set: { + lastViewed: Date.now(), + }, + }, + { + upsert: true, + }, + ); + + return res.status(200).json({ + success: true, + description: `Recorded a view on ${folder.title}.`, + body: {}, + }); +}); + +// note: this path is disgustingly long. :( +/** + * Returns the users scores in order of when they met this criteria. + * + * @param criteriaType - Any metric for this GPT. + * @param criteriaValue - Any valid value for that metric. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/folders/:folderID/timeline + */ +router.get( + "/timeline", + prValidate({ + criteriaType: "string", + criteriaValue: "string", + }), + async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const folder = GetTachiData(req, "folderDoc"); + const gptConfig = GetGamePTConfig(game, playtype); + + // as asserted by prudence. + const metric = req.query.criteriaType as string; + + const conf = GetScoreMetricConf(gptConfig, metric); + + if (!conf || conf.type !== "ENUM") { + return res.status(400).json({ + success: false, + description: `Invalid metric '${metric}' passed. Expected an ENUM for this game.`, + }); + } + + const criteriaValue = conf.values.indexOf(req.query.criteriaValue as string); + + if (criteriaValue === -1) { + return res.status(400).json({ + success: false, + description: `Invalid criteriaValue of ${req.query.criteriaValue} for ${metric}.`, + }); + } + + const { songs, charts } = await GetFolderCharts(folder, {}, true); + + const err = ValidateMetric(gptConfig, metric, criteriaValue); + + if (typeof err === "string") { + return res.status(400).json({ + success: false, + description: err, + }); + } + + const matchCriteria: FilterQuery = { + userID: user.id, + game, + playtype, + chartID: { $in: charts.map((e) => e.chartID) }, + }; + + matchCriteria[`scoreData.enumIndexes.${metric}`] = { $gte: criteriaValue }; + + // Returns a unique score per-chart that was the first score to achieve + // this criteria on that chart. + const scoresAgg: Array<{ doc: ScoreDocument }> = await db.scores.aggregate([ + { + $match: matchCriteria, + }, + { + $addFields: { + __sortTime: { $ifNull: ["$timeAchieved", Infinity, "$timeAchieved"] }, + }, + }, + { + $sort: { + __sortTime: 1, + }, + }, + { + $group: { + _id: "$chartID", + doc: { $first: "$$ROOT" }, + }, + }, + { + $unset: ["doc.__sortTime"], + }, + ]); + + const scores = scoresAgg + .map((e) => e.doc) + .sort((a, b) => (a.timeAchieved ?? 0) - (b.timeAchieved ?? 0)); + + return res.status(200).json({ + success: true, + description: `Returned ${scores.length} scores for ${charts.length} charts.`, + body: { + songs, + charts, + scores, + folder, + }, + }); + }, +); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/folders/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/folders/router.ts new file mode 100644 index 000000000..19ba009ac --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/folders/router.ts @@ -0,0 +1,87 @@ +import { SearchCollection } from "#lib/search/search"; +import db from "#services/mongo/db"; +import { GetEnumDistForFolders, GetRecentlyViewedFolders } from "#utils/folder"; +import { IsString } from "#utils/misc"; +import { GetUGPT } from "#utils/req-tachi-data"; +import { Router } from "express"; + +import folderIDRouter from "./_folderID/router"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Search folders, and supplant a users grade+lamp distribution on that + * folder as part of the returns. + * + * This is a "beefed-up" version of GPT /folders, but with this users + * stats returned at the same time. + * + * @param search - What to search for. + * @param inactive - Also show inactive folders, such as those on old versions. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/folders + */ +router.get("/", async (req, res) => { + const { game, playtype, user } = GetUGPT(req); + + if (!IsString(req.query.search)) { + return res.status(400).json({ + success: false, + description: `Invalid value for search.`, + }); + } + + // if inactive is passed, we need this to be undefined so that + // mongodb returns both inactive and active folders. + // Otherwise, only return active folders. + const inactive = req.query.inactive === undefined ? false : undefined; + + const folders = await SearchCollection( + db.folders, + req.query.search, + "folders", + { game, playtype, inactive }, + 20, + ); + + const stats = await GetEnumDistForFolders(user.id, folders); + + return res.status(200).json({ + success: true, + description: `Returned ${stats.length} folders.`, + body: { + folders, + stats, + }, + }); +}); + +/** + * Get a users most recently interacted with folders. + * + * A folder is interacted with if it is directly fetched using a session key. + * This - in UI terms - is when the user clicks on that folder. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/folders/recent + */ +router.get("/recent", async (req, res) => { + const { game, playtype, user } = GetUGPT(req); + + const { views, folders } = await GetRecentlyViewedFolders(user.id, game, playtype); + + const stats = await GetEnumDistForFolders(user.id, folders); + + return res.status(200).json({ + success: true, + description: `Returned ${views.length} recently interacted with folders.`, + body: { + views, + folders, + stats, + }, + }); +}); + +router.use("/:folderID", folderIDRouter); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/middleware.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/middleware.ts new file mode 100644 index 000000000..863ff2c69 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/middleware.ts @@ -0,0 +1,59 @@ +import type { RequestHandler } from "express"; + +import db from "#services/mongo/db"; +import { IsValidGame, IsValidPlaytype } from "#utils/misc"; +import { AssignToReqTachiData, GetTachiData } from "#utils/req-tachi-data"; + +export const CheckUserPlayedGamePlaytype: RequestHandler = async (req, res, next) => { + const user = GetTachiData(req, "requestedUser"); + + const game = req.params.game; + const playtype = req.params.playtype; + + if (game === undefined) { + throw new Error( + `Unexpected lack of game parameter when CheckUserPlayedGamePlaytype called on ${req.originalUrl}.`, + ); + } + + if (playtype === undefined) { + throw new Error( + `Unexpected lack of playtype parameter when CheckUserPlayedGamePlaytype called on ${req.originalUrl}.`, + ); + } + + if (!IsValidGame(game)) { + return res.status(400).json({ + success: false, + description: `The game ${req.params.game} is not supported.`, + }); + } + + if (!IsValidPlaytype(game, playtype)) { + return res.status(400).json({ + success: false, + description: `The game ${game} does not have a playtype called ${playtype}.`, + }); + } + + const stats = await db["game-stats"].findOne({ + userID: user.id, + game, + playtype, + }); + + if (!stats) { + return res.status(404).json({ + success: false, + description: `The user ${user.username} has not played ${req.params.game} (${req.params.playtype})`, + }); + } + + AssignToReqTachiData(req, { + requestedUserGameStats: stats, + game, + playtype, + }); + + next(); +}; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/pbs/router.test.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/pbs/router.test.ts new file mode 100644 index 000000000..5d740eb4f --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/pbs/router.test.ts @@ -0,0 +1,297 @@ +import type { ChartDocument, PBScoreDocument } from "tachi-common"; + +import db from "#services/mongo/db"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { + GetKTDataJSON, + LoadTachiIIDXData, + Testing511Song, + Testing511SPA, + TestingIIDXSPScorePB, +} from "#test-utils/test-data"; +import t from "tap"; + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/pbs/best", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return a user's best 100 personal bests.", async (t) => { + const mockPBs: Array = []; + + for (let i = 0; i < 200; i++) { + mockPBs.push({ + userID: 1, + game: "iidx", + playtype: "SP", + isPrimary: true, + + // hack to generate some random chartIDs + chartID: i.toString(), + + songID: Testing511Song.id, + calculatedData: { + ktLampRating: i, + }, + } as PBScoreDocument); + } + + await db["personal-bests"].insert(mockPBs); + + const res = await mockApi.get("/api/v1/users/test_zkldi/games/iidx/SP/pbs/best"); + + t.hasStrict(res.body, { + success: true, + description: "Retrieved 100 personal bests.", + body: { + pbs: mockPBs.slice(100).reverse(), + songs: [Testing511Song], + charts: [], + }, + }); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/pbs", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(LoadTachiIIDXData); + + t.test("Should return 400 if no search param is given", async (t) => { + const res = await mockApi.get("/api/v1/users/test_zkldi/games/iidx/SP/pbs"); + + t.equal(res.statusCode, 400); + t.equal(res.body.success, false); + + t.end(); + }); + + t.test("Should return 400 if invalid search param is given", async (t) => { + const res = await mockApi.get( + "/api/v1/users/test_zkldi/games/iidx/SP/pbs?search=foo&search=bar", + ); + + t.equal(res.statusCode, 400); + t.equal(res.body.success, false); + + const res2 = await mockApi.get( + "/api/v1/users/test_zkldi/games/iidx/SP/pbs?search[$where]=process.exit(1)", + ); + + t.equal(res2.statusCode, 400); + t.equal(res2.body.success, false); + + t.end(); + }); + + t.test("Should search a user's personal bests.", async (t) => { + const mockPBs: Array = []; + + const charts = GetKTDataJSON("./tachi/tachi-charts-iidx.json") as Array; + + for (let i = 0; i < 200; i++) { + const chart = charts[i]; + + if (!chart) { + return t.fail( + `Not enough charts in tachi-charts-iidx.json to mock pb data? Failed at index ${i}.`, + ); + } + + mockPBs.push({ + userID: 1, + game: "iidx", + playtype: "SP", + isPrimary: true, + chartID: chart.chartID, + songID: chart.songID, + calculatedData: { + ktLampRating: i, + }, + } as PBScoreDocument); + } + + await db["personal-bests"].insert(mockPBs); + + const res = await mockApi.get("/api/v1/users/test_zkldi/games/iidx/SP/pbs?search=5.1.1."); + + t.hasStrict(res.body, { + success: true, + description: "Retrieved 4 personal bests.", + body: { + pbs: [ + { + chartID: "71865a2b6d3581decf076ae83c6621302c4bb271", + }, + { + chartID: "952805894d7d78257e87019426fa1d87aec834a5", + }, + { + chartID: "c2311194e3897ddb5745b1760d2c0141f933e683", + }, + { + chartID: "c641238220d73faf82659513ba03bde71b0b45f0", + }, + ], + songs: [ + { + title: "5.1.1.", + }, + ], + charts: [ + { + chartID: "c2311194e3897ddb5745b1760d2c0141f933e683", + }, + { + chartID: "71865a2b6d3581decf076ae83c6621302c4bb271", + }, + { + chartID: "c641238220d73faf82659513ba03bde71b0b45f0", + }, + { + chartID: "952805894d7d78257e87019426fa1d87aec834a5", + }, + ], + }, + }); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/pbs/:chartID", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should retrieve the PB at this chart ID.", async (t) => { + await db["personal-bests"].insert(TestingIIDXSPScorePB); + + const res = await mockApi.get(`/api/v1/users/1/games/iidx/SP/pbs/${Testing511SPA.chartID}`); + + t.equal(res.body.body.pb.chartID, Testing511SPA.chartID); + t.equal(res.body.body.chart.chartID, Testing511SPA.chartID); + + t.end(); + }); + + t.test("Should retrieve composed scores if param is set.", async (t) => { + await db["personal-bests"].insert(TestingIIDXSPScorePB); + + const res = await mockApi.get( + `/api/v1/users/1/games/iidx/SP/pbs/${Testing511SPA.chartID}?getComposition=true`, + ); + + t.equal(res.body.body.pb.chartID, Testing511SPA.chartID); + t.equal(res.body.body.chart.chartID, Testing511SPA.chartID); + t.equal(res.body.body.scores.length, 1); + t.equal(res.body.body.scores[0].scoreID, "TESTING_SCORE_ID"); + + t.end(); + }); + + t.end(); +}); + +t.test("POST /api/v1/users/:userID/games/:game/:playtype/pbs/resolve", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(LoadTachiIIDXData); + + t.test( + "Should resolve a chart and return user's PB using tachiSongID matchType.", + async (t) => { + await db["personal-bests"].insert(TestingIIDXSPScorePB); + + const res = await mockApi.post("/api/v1/users/1/games/iidx/SP/pbs/resolve").send({ + matchType: "tachiSongID", + identifier: "1", + difficulty: "ANOTHER", + }); + + t.equal(res.statusCode, 200); + t.equal(res.body.success, true); + t.equal(res.body.body.pb.chartID, Testing511SPA.chartID); + t.equal(res.body.body.chart.chartID, Testing511SPA.chartID); + t.equal(res.body.body.song.id, 1); + t.equal(res.body.body.song.title, "5.1.1."); + + t.end(); + }, + ); + + t.test("Should resolve a chart and return user's PB using songTitle matchType.", async (t) => { + await db["personal-bests"].insert(TestingIIDXSPScorePB); + + const res = await mockApi.post("/api/v1/users/1/games/iidx/SP/pbs/resolve").send({ + matchType: "songTitle", + identifier: "5.1.1.", + difficulty: "ANOTHER", + }); + + t.equal(res.statusCode, 200); + t.equal(res.body.success, true); + t.equal(res.body.body.pb.chartID, Testing511SPA.chartID); + t.equal(res.body.body.chart.chartID, Testing511SPA.chartID); + t.equal(res.body.body.song.id, 1); + + t.end(); + }); + + t.test("Should return 404 when chart cannot be resolved.", async (t) => { + const res = await mockApi.post("/api/v1/users/1/games/iidx/SP/pbs/resolve").send({ + matchType: "tachiSongID", + identifier: "99999", + difficulty: "ANOTHER", + }); + + t.equal(res.statusCode, 404); + t.equal(res.body.success, false); + t.match(res.body.description, /Could not resolve this chart/u); + + t.end(); + }); + + t.test("Should return 404 when user has no PB on resolved chart.", async (t) => { + // Don't insert any PBs - user hasn't played this chart + + const res = await mockApi.post("/api/v1/users/1/games/iidx/SP/pbs/resolve").send({ + matchType: "tachiSongID", + identifier: "1", + difficulty: "ANOTHER", + }); + + t.equal(res.statusCode, 404); + t.equal(res.body.success, false); + t.match(res.body.description, /has not played this chart/u); + + t.end(); + }); + + t.test("Should return 400 for invalid request body.", async (t) => { + const res = await mockApi.post("/api/v1/users/1/games/iidx/SP/pbs/resolve").send({ + matchType: "invalidMatchType", + identifier: "1", + }); + + t.equal(res.statusCode, 400); + t.equal(res.body.success, false); + + t.end(); + }); + + t.test("Should return 400 when required fields are missing.", async (t) => { + const res = await mockApi.post("/api/v1/users/1/games/iidx/SP/pbs/resolve").send({ + matchType: "tachiSongID", + // missing identifier + }); + + t.equal(res.statusCode, 400); + t.equal(res.body.success, false); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/pbs/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/pbs/router.ts new file mode 100644 index 000000000..c55642dd3 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/pbs/router.ts @@ -0,0 +1,338 @@ +import { log } from "#lib/log/log.js"; +import { GetRivalUsers } from "#lib/rivals/rivals"; +import { ResolveSongAndChart } from "#lib/score-import/import-types/common/batch-manual/converter"; +import { SearchSpecificGameSongsAndCharts } from "#lib/search/search"; +import prValidate from "#server/middleware/prudence-validate"; +import { AggressiveRateLimitMiddleware } from "#server/middleware/rate-limiter"; +import db from "#services/mongo/db"; +import { GetRelevantSongsAndCharts } from "#utils/db"; +import { IsValidScoreAlg } from "#utils/misc"; +import { GetAdjacentAbove, GetAdjacentBelow } from "#utils/queries/pbs"; +import { GetUGPT } from "#utils/req-tachi-data"; +import { FilterChartsAndSongs, GetPBOnChart, GetScoreIDsFromComposed } from "#utils/scores"; +import { GetUsersWithIDs } from "#utils/user"; +import { Router } from "express"; +import { GetGamePTConfig, type MatchTypeResolver } from "tachi-common"; +import { PR_RESOLVER } from "tachi-common/lib/schemas"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Searches a user's personal bests. + * + * @param search - The search criteria. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/pbs + */ +router.get("/", async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + if (typeof req.query.search !== "string") { + return res.status(400).json({ + success: false, + description: `Invalid value of for search parameter.`, + }); + } + + const { songs: allSongs, charts: allCharts } = await SearchSpecificGameSongsAndCharts( + game, + req.query.search, + playtype, + ); + + const pbs = await db["personal-bests"].find( + { + chartID: { $in: allCharts.map((e) => e.chartID) }, + userID: user.id, + }, + { + sort: { + timeAchieved: -1, + }, + limit: 30, + }, + ); + + const { songs, charts } = FilterChartsAndSongs(pbs, allCharts, allSongs); + + return res.status(200).json({ + success: true, + description: `Retrieved ${pbs.length} personal bests.`, + body: { + pbs, + songs, + charts, + }, + }); +}); + +/** + * Returns all of a users personal bests. + * + * @warn This endpoint is probably quite expensive. We'll need to do + * some performance tests. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/pbs/all + */ +router.get("/all", AggressiveRateLimitMiddleware, async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const pbs = await db["personal-bests"].find({ + userID: user.id, + game, + playtype, + isPrimary: true, + }); + + const { songs, charts } = await GetRelevantSongsAndCharts(pbs, game); + + return res.status(200).json({ + success: true, + description: `Returned ${pbs.length} PBs.`, + body: { pbs, songs, charts }, + }); +}); + +/** + * Returns a users best 100 personal-bests for this game. + * + * @param alg - Specifies an override for the default algorithm + * to sort on. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/pbs/best + */ +router.get("/best", prValidate({ alg: "*string" }), async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const gptConfig = GetGamePTConfig(game, playtype); + + if (req.query.alg !== undefined && !IsValidScoreAlg(gptConfig, req.query.alg)) { + return res.status(400).json({ + success: false, + description: `Invalid score algorithm. Expected any of ${Object.keys( + gptConfig.scoreRatingAlgs, + ).join(", ")}`, + }); + } + + const alg = (req.query.alg as string | undefined) ?? gptConfig.defaultScoreRatingAlg; + + const pbs = await db["personal-bests"].find( + { + userID: user.id, + game, + playtype, + isPrimary: true, + }, + { + limit: 100, + sort: { + [`calculatedData.${alg}`]: -1, + }, + }, + ); + + const { songs, charts } = await GetRelevantSongsAndCharts(pbs, game); + + return res.status(200).json({ + success: true, + description: `Retrieved ${pbs.length} personal bests.`, + body: { + pbs, + songs, + charts, + }, + }); +}); + +/** + * Returns a user's PB on the given chart. If the user has not played this chart, 404 is + * returned. + * + * @param getComposition - Also retrieves the score documents that composed this PB. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/pbs/:chartID + */ +router.get("/:chartID", async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const chart = await db.anyCharts[game].findOne({ + chartID: req.params.chartID, + playtype, + }); + + if (!chart) { + return res.status(404).json({ + success: false, + description: `This chart does not exist.`, + }); + } + + const pb = await db["personal-bests"].findOne({ + chartID: req.params.chartID, + userID: user.id, + }); + + if (!pb) { + return res.status(404).json({ + success: false, + description: `This user has not played this chart.`, + }); + } + + if (req.query.getComposition !== undefined) { + const scoreIDs = GetScoreIDsFromComposed(pb); + + const scores = await db.scores.find({ + scoreID: { $in: scoreIDs }, + }); + + return res.status(200).json({ + success: true, + description: `Successfully retrieved PB for user.`, + body: { + scores, + chart, + pb, + }, + }); + } + + return res.status(200).json({ + success: true, + description: `Successfully retrieved PB for user.`, + body: { + pb, + chart, + }, + }); +}); + +/** + * Returns a user's PB on the given chart, and all of their rivals performances aswell. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/pbs/:chartID/rivals + */ +router.get("/:chartID/rivals", async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const rivals = await GetRivalUsers(user.id, game, playtype); + + const pbs = await db["personal-bests"].find({ + userID: { $in: rivals.map((e) => e.id) }, + chartID: req.params.chartID, + }); + + const usersPB = await GetPBOnChart(user.id, req.params.chartID); + + if (usersPB) { + pbs.push(usersPB); + } + + return res.status(200).json({ + success: true, + description: `Retrieved PBs and Rival PBs.`, + body: { + pbs, + rivals, + }, + }); +}); + +/** + * Return this users PB on this chart, and 5 nearby players on the + * leaderboard. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/pbs/:chartID/leaderboard-adjacent + */ +router.get("/:chartID/leaderboard-adjacent", async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const chart = await db.anyCharts[game].findOne({ + chartID: req.params.chartID, + playtype, + }); + + if (!chart) { + return res.status(404).json({ + success: false, + description: `This chart does not exist.`, + }); + } + + const pb = await db["personal-bests"].findOne({ + chartID: req.params.chartID, + userID: user.id, + }); + + if (!pb) { + return res.status(404).json({ + success: false, + description: `This user has not played this chart.`, + }); + } + + const [adjacentAbove, adjacentBelow] = await Promise.all([ + GetAdjacentAbove(pb), + GetAdjacentBelow(pb), + ]); + + const users = await GetUsersWithIDs([...adjacentAbove, ...adjacentBelow].map((e) => e.userID)); + + return res.status(200).json({ + success: true, + description: `Successfully retrieved PB for user.`, + body: { + pb, + chart, + adjacentAbove, + adjacentBelow, + users, + }, + }); +}); + +/** + * Use the tachi "resolve" engine to identify a chart instead of + * using the Tachi IDs. Used to get a PB. + * + * @name POST /api/v1/users/:userID/games/:game/:playtype/pbs/resolve + */ +router.post("/resolve", prValidate(PR_RESOLVER), async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const safeBody = { + ...req.safeBody, + game, + playtype, + } as unknown as MatchTypeResolver; + const got = await ResolveSongAndChart(safeBody, log); + + if (!got) { + return res.status(404).json({ + success: false, + description: `Could not resolve this chart with details: ${safeBody.matchType}:${safeBody.identifier} (Extra specifiers: version=${safeBody.version}, artist=${safeBody.artist})`, + }); + } + + const pb = await GetPBOnChart(user.id, got.chart.chartID); + + if (!pb) { + return res.status(404).json({ + success: false, + description: `This user has not played this chart.`, + }); + } + + return res.status(200).json({ + success: true, + description: "Successfully retrieved PB for user.", + body: { + pb, + chart: got.chart, + song: got.song, + }, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/rivals/router.test.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/rivals/router.test.ts new file mode 100644 index 000000000..55ab44c85 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/rivals/router.test.ts @@ -0,0 +1,190 @@ +import type { UserDocument } from "tachi-common"; + +import db from "#services/mongo/db"; +import { CreateFakeAuthCookie } from "#test-utils/fake-auth"; +import { mkFakeGameSettings, mkFakeUser } from "#test-utils/misc"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { FakeOtherUser } from "#test-utils/test-data"; +import t from "tap"; + +const SetupRivals = async () => { + await db.users.insert([FakeOtherUser, mkFakeUser(3), mkFakeUser(4)]); + await db["game-settings"].insert([ + mkFakeGameSettings(2, "iidx", "SP"), + mkFakeGameSettings(3, "iidx", "SP"), + ]); + + await db["game-settings"].update( + { + userID: 1, + }, + { + $set: { + rivals: [2, 3], + }, + }, + ); +}; + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/rivals", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(SetupRivals); + + t.test("Should return the userdocs of your rivals.", async (t) => { + const res = await mockApi.get("/api/v1/users/1/games/iidx/SP/rivals"); + + t.equal(res.statusCode, 200); + + t.strictSame( + res.body.body.map((e: UserDocument) => e.id), + [2, 3], + "Should have the users rivals and no more.", + ); + + t.end(); + }); + + t.test("Should panic if your rival doesn't exist.", async (t) => { + await db.users.remove({ id: 3 }); + + const res = await mockApi.get("/api/v1/users/1/games/iidx/SP/rivals"); + + t.equal(res.statusCode, 500); + + t.end(); + }); + + t.end(); +}); + +t.test("PUT /api/v1/users/:userID/games/:game/:playtype/rivals", async (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(SetupRivals); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should replace the users rivals.", async (t) => { + const res = await mockApi + .put("/api/v1/users/1/games/iidx/SP/rivals") + .set("Cookie", cookie) + .send({ + rivalIDs: [2], + }); + + t.equal(res.statusCode, 200); + + const dbRes = await db["game-settings"].findOne({ + userID: 1, + game: "iidx", + playtype: "SP", + }); + + t.strictSame(dbRes?.rivals, [2]); + + t.end(); + }); + + t.test("Should return 400 if the user tries to rival themselves.", async (t) => { + const res = await mockApi + .put("/api/v1/users/1/games/iidx/SP/rivals") + .set("Cookie", cookie) + .send({ + rivalIDs: [1], + }); + + t.equal(res.statusCode, 400); + + t.end(); + }); + + t.test("Should return 400 if the user tries to rival > 5 people.", async (t) => { + await db.users.insert([mkFakeUser(5), mkFakeUser(6)]); + + const res = await mockApi + .put("/api/v1/users/1/games/iidx/SP/rivals") + .set("Cookie", cookie) + .send({ + rivalIDs: [2, 3, 4, 5, 6], + }); + + t.equal(res.statusCode, 400); + + t.end(); + }); + + t.test("Should return 400 if the user tries to rival someone who doesn't exist.", async (t) => { + const res = await mockApi + .put("/api/v1/users/1/games/iidx/SP/rivals") + .set("Cookie", cookie) + .send({ + rivalIDs: [5], + }); + + t.equal(res.statusCode, 400); + + t.end(); + }); + + t.test( + "Should return 400 if the user tries to rival someone who exists but hasn't played the GPT.", + async (t) => { + await db.users.insert(mkFakeUser(5)); + + const res = await mockApi + .put("/api/v1/users/1/games/iidx/SP/rivals") + .set("Cookie", cookie) + .send({ + rivalIDs: [5], + }); + + t.equal(res.statusCode, 400); + + t.end(); + }, + ); + + t.test("Should return 401 if user has no auth.", async (t) => { + const res = await mockApi.put("/api/v1/users/1/games/iidx/SP/rivals").send({ + rivalIDs: [2], + }); + + t.equal(res.statusCode, 401); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/rivals/challengers", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(SetupRivals); + + t.test("Should return all of the users that rival this UGPT.", async (t) => { + await db.users.insert(mkFakeUser(5)); + + await db["game-settings"].remove({ userID: 3 }); + await db["game-settings"].remove({ userID: 4 }); + + await db["game-settings"].insert([ + mkFakeGameSettings(2, "chunithm", "Single", { rivals: [1] }), + mkFakeGameSettings(3, "iidx", "SP", { rivals: [1, 3] }), + mkFakeGameSettings(4, "iidx", "SP", { rivals: [1, 3, 5] }), + mkFakeGameSettings(5, "iidx", "SP", { rivals: [1, 4] }), + ]); + + const res = await mockApi.get("/api/v1/users/1/games/iidx/SP/rivals/challengers"); + + t.equal(res.statusCode, 200); + + t.hasStrict( + res.body.body.map((e: UserDocument) => e.id), + [3, 4, 5], + ); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/rivals/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/rivals/router.ts new file mode 100644 index 000000000..c97f16c09 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/rivals/router.ts @@ -0,0 +1,191 @@ +import { CreateActivityRouteHandler } from "#lib/activity/activity"; +import { SetRivalsFailReasons } from "#lib/constants/err-codes"; +import { GetChallengerUsers, GetRivalIDs, GetRivalUsers, SetRivals } from "#lib/rivals/rivals"; +import { RequirePermissions } from "#server/middleware/auth"; +import prValidate from "#server/middleware/prudence-validate"; +import db from "#services/mongo/db"; +import { GetRelevantSongsAndCharts } from "#utils/db"; +import { IsString } from "#utils/misc"; +import { GetUGPT } from "#utils/req-tachi-data"; +import { CheckStrScoreAlg } from "#utils/string-checks"; +import { GetUsersWithIDs } from "#utils/user"; +import { Router } from "express"; +import { p } from "prudence"; +import { FormatGameGroup, GetGamePTConfig, type integer } from "tachi-common"; + +import { RequireAuthedAsUser } from "../../../../middleware"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Returns all of this user's set rivals. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/rivals + */ +router.get("/", async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const rivals = await GetRivalUsers(user.id, game, playtype); + + return res.status(200).json({ + success: true, + description: `Returned ${rivals.length} rivals.`, + body: rivals, + }); +}); + +/** + * Sets the user's rivals for this GPT. + * + * @param rivalIDs - An array of rivalIDs to set as their rivals. + * + * @name PUT /api/v1/users/:userID/games/:game/:playtype/rivals + */ +router.put( + "/", + RequireAuthedAsUser, + RequirePermissions("manage_rivals"), + prValidate({ + rivalIDs: [p.isPositiveNonZeroInteger], + }), + async (req, res) => { + const body = req.safeBody as { + rivalIDs: Array; + }; + + const rivalIDs = body.rivalIDs; + const { user, game, playtype } = GetUGPT(req); + + const result = await SetRivals(user.id, game, playtype, rivalIDs); + + if (result === SetRivalsFailReasons.RIVALED_SELF) { + return res.status(400).json({ + success: false, + description: `You cannot rival yourself.`, + }); + } else if (result === SetRivalsFailReasons.RIVALS_HAVENT_PLAYED_GPT) { + return res.status(400).json({ + success: false, + description: `Not all of the rivals you specified have played ${FormatGameGroup( + game, + playtype, + )}.`, + }); + } else if (result === SetRivalsFailReasons.TOO_MANY) { + return res.status(400).json({ + success: false, + description: `You can't set more than 5 rivals.`, + }); + } + + return res.status(200).json({ + success: true, + description: `Set ${rivalIDs.length} rivals.`, + body: {}, + }); + }, +); + +/** + * Return all of the users that are rivalling this user for this GPT. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/rivals/challengers + */ +router.get("/challengers", async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const challengers = await GetChallengerUsers(user.id, game, playtype); + + return res.status(200).json({ + success: true, + description: `Returned ${challengers.length} challengers.`, + body: challengers, + }); +}); + +/** + * Retrieve a "PB leaderboard" for this user's set of rivals. + * + * This is - effectively - the best 100 scores from this set of users on the given + * rating algorithm. + * + * @param alg - The score rating algorithm to sort on. Defaults to whatever the GPTConfig + * default is. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/rivals/pb-leaderboard + */ +router.get("/pb-leaderboard", async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + const gptConfig = GetGamePTConfig(game, playtype); + + let alg = gptConfig.defaultScoreRatingAlg; + + if (IsString(req.query.alg)) { + const temp = CheckStrScoreAlg(game, playtype, req.query.alg); + + if (temp === null) { + return res.status(400).json({ + success: false, + description: `Invalid value of ${ + req.query.alg + } for alg. Expected one of ${Object.keys(gptConfig.scoreRatingAlgs).join(", ")}`, + }); + } + + alg = temp; + } + + const rivalIDs = await GetRivalIDs(user.id, game, playtype); + const userSet = [...rivalIDs, user.id]; + + const pbs = await db["personal-bests"].find( + { + game, + playtype, + userID: { $in: userSet }, + }, + { + sort: { + [`calculatedData.${alg}`]: -1, + }, + limit: 100, + }, + ); + + const users = await GetUsersWithIDs(pbs.map((e) => e.userID)); + + const { songs, charts } = await GetRelevantSongsAndCharts(pbs, game); + + return res.status(200).send({ + success: true, + description: `Successfully returned ${pbs.length} pbs.`, + body: { + pbs, + songs, + charts, + users, + }, + }); +}); + +/** + * Retrieve activity for this user's set of rivals. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/rivals/activity + */ +router.get("/activity", async (req, res) => { + const { game, playtype, user } = GetUGPT(req); + + const rivalIDs = await GetRivalIDs(user.id, game, playtype); + + const route = CreateActivityRouteHandler({ + userID: { $in: rivalIDs }, + game, + playtype, + }); + + // this handles responding + void route(req, res); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/router.test.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/router.test.ts new file mode 100644 index 000000000..c2ecf9068 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/router.test.ts @@ -0,0 +1,284 @@ +import type { ScoreDocument } from "tachi-common"; + +import { ONE_DAY } from "#lib/constants/time"; +import db from "#services/mongo/db"; +import { CreateFakeAuthCookie } from "#test-utils/fake-auth"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { Testing511SPA, TestingIIDXSPScore, TestingIIDXSPScorePB } from "#test-utils/test-data"; +import deepmerge from "deepmerge"; +import t from "tap"; + +t.test("GET /api/v1/users/:userID/games/:game/:playtype", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return a users statistics for that game.", async (t) => { + const res = await mockApi.get("/api/v1/users/test_zkldi/games/iidx/SP"); + + t.hasStrict(res.body, { + success: true, + description: "Retrieved user statistics for test_zkldi (iidx SP)", + body: { + gameStats: { + userID: 1, + game: "iidx", + playtype: "SP", + classes: {}, + ratings: {}, + }, + firstScore: null, + mostRecentScore: null, + totalScores: 1, + rankingData: { + ktLampRating: { + ranking: 1, + outOf: 1, + }, + BPI: { + ranking: 1, + outOf: 1, + }, + }, + }, + }); + + t.end(); + }); + + t.test("Should return a users first score if one exists.", async (t) => { + await db.scores.insert([ + { + userID: 1, + timeAchieved: 100, + scoreID: "foo", + game: "iidx", + playtype: "SP", + }, + { + userID: 1, + timeAchieved: 200, + scoreID: "bar", + game: "iidx", + playtype: "SP", + }, + { + userID: 1, + timeAchieved: 300, + scoreID: "baz", + game: "iidx", + playtype: "SP", + }, + ] as Array); + + const res = await mockApi.get("/api/v1/users/test_zkldi/games/iidx/SP"); + + t.hasStrict(res.body, { + success: true, + description: "Retrieved user statistics for test_zkldi (iidx SP)", + body: { + gameStats: { + userID: 1, + game: "iidx", + playtype: "SP", + classes: {}, + ratings: {}, + }, + firstScore: { + timeAchieved: 100, + scoreID: "foo", + }, + mostRecentScore: { + timeAchieved: 300, + scoreID: "baz", + }, + totalScores: 4, + rankingData: { + ktLampRating: { + ranking: 1, + outOf: 1, + }, + BPI: { + ranking: 1, + outOf: 1, + }, + }, + }, + }); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/history", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return a users history snapshots for that gpt.", async (t) => { + await db["game-stats-snapshots"].insert([ + { + userID: 1, + game: "iidx", + playtype: "SP", + + // @ts-expect-error Too lazy to sort this one out... + rankings: { + BPI: { + ranking: 2, + outOf: 4, + }, + }, + playcount: 100, + classes: {}, + ratings: {}, + timestamp: Date.now() - ONE_DAY, + }, + ]); + + const res = await mockApi.get("/api/v1/users/test_zkldi/games/iidx/SP/history"); + + // by default, it's set to the current time. we can't + // test that nicely, so lets round it to the nearest 100 seconds. + res.body.body[0].timestamp = Math.floor(res.body.body[0].timestamp / 100_000); + res.body.body[1].timestamp = Math.floor(res.body.body[1].timestamp / 100_000); + + t.strictSame(res.body.body, [ + { + rankings: { + ktLampRating: { + ranking: 1, + outOf: 1, + }, + BPI: { + ranking: 1, + outOf: 1, + }, + }, + playcount: 1, + classes: {}, + ratings: {}, + + // close enough, right? + timestamp: Math.floor(Date.now() / 100_000), + }, + { + rankings: { + BPI: { + ranking: 2, + outOf: 4, + }, + }, + playcount: 100, + classes: {}, + ratings: {}, + timestamp: Math.floor((Date.now() - ONE_DAY) / 100_000), + }, + ]); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/most-played", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return the users most played scores.", async (t) => { + await db.scores.insert([ + // @ts-expect-error nonsense + deepmerge(TestingIIDXSPScore, { scoreID: "something_else" }), + + // @ts-expect-error nonsense + deepmerge(TestingIIDXSPScore, { scoreID: "something_else2" }), + ]); + + await db["personal-bests"].insert(TestingIIDXSPScorePB); + + const res = await mockApi.get("/api/v1/users/1/games/iidx/SP/most-played"); + + t.equal(res.body.body.pbs.length, 1); + t.equal(res.body.body.pbs[0].__playcount, 3); + + t.equal(res.body.body.songs.length, 1); + t.equal(res.body.body.songs[0].id, 1); + + t.equal(res.body.body.charts.length, 1); + t.equal(res.body.body.charts[0].chartID, Testing511SPA.chartID); + + t.end(); + }); + + t.end(); +}); + +t.test("DELETE /api/v1/users/:userID/games/:game/:playtype", async (t) => { + t.beforeEach(ResetDBState); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should delete this users profile and check passwords.", async (t) => { + const res = await mockApi + .delete(`/api/v1/users/1/games/iidx/SP`) + .set("Cookie", cookie) + .send({ + "!password": "password", + }); + + t.equal(res.status, 200, "Should return 200."); + + const dbRes = await db["game-stats"].findOne({ userID: 1, game: "iidx", playtype: "SP" }); + + t.equal(dbRes, null, "Should remove the UGPT profile from the database."); + + t.end(); + }); + + t.test("Should require a correct password.", async (t) => { + const res = await mockApi + .delete(`/api/v1/users/1/games/iidx/SP`) + .set("Cookie", cookie) + .send({ + "!password": "invalid_password", + }); + + t.equal(res.status, 403, "Should return 403."); + + const dbRes = await db["game-stats"].findOne({ userID: 1, game: "iidx", playtype: "SP" }); + + t.not(dbRes, null, "Should NOT remove the UGPT profile from the database."); + + t.end(); + }); + + t.test("Should require a password.", async (t) => { + const res = await mockApi + .delete(`/api/v1/users/1/games/iidx/SP`) + .set("Cookie", cookie) + .send({}); + + t.equal(res.status, 400, "Should return 400."); + + const dbRes = await db["game-stats"].findOne({ userID: 1, game: "iidx", playtype: "SP" }); + + t.not(dbRes, null, "Should NOT remove the UGPT profile from the database."); + + t.end(); + }); + + t.test("Should require self-key auth.", async (t) => { + const res = await mockApi.delete(`/api/v1/users/1/games/iidx/SP`).send({ + "!password": "password", + }); + + t.equal(res.status, 401, "Should return 401."); + + const dbRes = await db["game-stats"].findOne({ userID: 1, game: "iidx", playtype: "SP" }); + + t.not(dbRes, null, "Should NOT remove the UGPT profile from the database."); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/router.ts new file mode 100644 index 000000000..89f23f3f2 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/router.ts @@ -0,0 +1,460 @@ +import { CreateActivityRouteHandler } from "#lib/activity/activity"; +import { ONE_MONTH, ONE_WEEK, ONE_YEAR } from "#lib/constants/time"; +import { log } from "#lib/log/log.js"; +import prValidate from "#server/middleware/prudence-validate"; +import { PasswordCompare, ValidatePassword } from "#server/router/api/v1/auth/auth.js"; +import db from "#services/mongo/db"; +import { IsString } from "#utils/misc"; +import { GetTachiData, GetUGPT } from "#utils/req-tachi-data"; +import DestroyUserGamePlaytypeData from "#utils/reset-state/destroy-ugpt"; +import { CheckStrProfileAlg } from "#utils/string-checks"; +import { + FormatUserDoc, + GetAllRankings, + GetUGPTPlaycount, + GetUserPrivateInfo, + GetUsersRankingAndOutOf, + GetUsersWithIDs, +} from "#utils/user"; +import { Router } from "express"; +import { p } from "prudence"; +import { + FormatGameGroup, + GetGamePTConfig, + type GPTString, + type integer, + type PBScoreDocument, + type ProfileRatingAlgorithms, + type UserGameStatsSnapshotDocument, +} from "tachi-common"; + +import { RequireAuthedAsUser, RequireSelfRequestFromUser } from "../../../middleware"; +import foldersRouter from "./folders/router"; +import { CheckUserPlayedGamePlaytype } from "./middleware"; +import pbsRouter from "./pbs/router"; +import rivalsRouter from "./rivals/router"; +import scoresRouter from "./scores/router"; +import sessionsRouter from "./sessions/router"; +import settingsRouter from "./settings/router"; +import showcaseRouter from "./showcase/router"; +import tablesRouter from "./tables/router"; +import targetsRouter from "./targets/router"; + +const router: Router = Router({ mergeParams: true }); + +router.use(CheckUserPlayedGamePlaytype); + +/** + * Returns information about a user for this game + playtype. + * @name GET /api/v1/users/:userID/games/:game/:playtype + */ +router.get("/", async (req, res) => { + const { game, playtype, user } = GetUGPT(req); + + const stats = GetTachiData(req, "requestedUserGameStats"); + + const [totalScores, firstScore, mostRecentScore, rankingData, playtime] = await Promise.all([ + db.scores.count({ + userID: user.id, + game, + playtype, + }), + db.scores.findOne( + { + userID: user.id, + game, + playtype, + timeAchieved: { $ne: null }, + }, + { + sort: { + timeAchieved: 1, + }, + }, + ), + db.scores.findOne( + { + userID: user.id, + game, + playtype, + timeAchieved: { $ne: null }, + }, + { + sort: { + timeAchieved: -1, + }, + }, + ), + GetAllRankings(stats), + db.sessions.aggregate<[] | [{ playtime: number }]>([ + { + $match: { + userID: user.id, + game, + playtype, + }, + }, + { + $project: { + duration: { $subtract: ["$timeEnded", "$timeStarted"] }, + }, + }, + { + $group: { + _id: null, + playtime: { $sum: "$duration" }, + }, + }, + ]), + ]); + + return res.status(200).json({ + success: true, + description: `Retrieved user statistics for ${user.username} (${game} ${playtype})`, + body: { + gameStats: stats, + firstScore, + mostRecentScore, + totalScores, + rankingData, + playtime: playtime[0]?.playtime ?? 0, + }, + }); +}); + +/** + * Returns a users game-stats for the past 90 days. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/history + */ +router.get( + "/history", + prValidate({ + duration: p.optional(p.isIn("week", "month", "3mo", "year")), + }), + async (req, res) => { + const duration = req.query.duration as "3mo" | "month" | "week" | "year" | undefined; + + let time = Date.now(); + + switch (duration) { + case "year": { + time = time - ONE_YEAR; + break; + } + + // if the user doesn't define anything, default to 3month + case "3mo": + case undefined: { + time = time - ONE_MONTH * 3; + break; + } + + case "month": { + time = time - ONE_MONTH; + break; + } + + case "week": + time = time - ONE_WEEK; + } + + const { game, playtype, user } = GetUGPT(req); + + const stats = GetTachiData(req, "requestedUserGameStats"); + + const snapshots = (await db["game-stats-snapshots"].find( + { + userID: user.id, + game, + playtype, + timestamp: { $gte: time }, + }, + { + sort: { + timestamp: -1, + }, + + // avoid sending so much garbage. + projection: { + userID: 0, + game: 0, + playtype: 0, + }, + }, + )) as Array>; + + const currentSnapshot: Omit = + { + classes: stats.classes, + ratings: stats.ratings, + + // lazy, should probably be this midnight + timestamp: Date.now(), + playcount: await GetUGPTPlaycount(user.id, game, playtype), + rankings: await GetAllRankings(stats), + }; + + return res.status(200).json({ + success: true, + description: `Successfully returned history for the past ${snapshots.length} days.`, + body: [currentSnapshot, ...snapshots], + }); + }, +); + +/** + * Returns the users most played charts by playcount. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/most-played + */ +router.get("/most-played", async (req, res) => { + const { game, playtype, user } = GetUGPT(req); + + const mostPlayed: Array<{ _id: string; playcount: integer; songID: integer }> = + await db.scores.aggregate([ + { + $match: { + userID: user.id, + game, + playtype, + }, + }, + { + $group: { + _id: "$chartID", + + // micro opt + songID: { $first: "$songID" }, + playcount: { $sum: 1 }, + }, + }, + { + $sort: { + playcount: -1, + }, + }, + { + $limit: 100, + }, + ]); + + const chartIDs = mostPlayed.map((e) => e._id); + const songIDs = mostPlayed.map((e) => e.songID); + + const [songs, charts, pbs] = await Promise.all([ + await db.anySongs[game].find({ id: { $in: songIDs } }), + await db.anyCharts[game].find({ chartID: { $in: chartIDs } }), + await db["personal-bests"].find({ chartID: { $in: chartIDs }, userID: user.id }), + ]); + + const playcountMap = new Map(); + + for (const doc of mostPlayed) { + playcountMap.set(doc._id, doc.playcount); + } + + // @ts-expect-error monkeypatching + const playcountPBs = pbs as Array<{ __playcount: integer } & PBScoreDocument>; + + // monkey patch __playcount on + for (const pb of playcountPBs) { + pb.__playcount = playcountMap.get(pb.chartID) ?? 0; + } + + playcountPBs.sort((a, b) => b.__playcount - a.__playcount); + + return res.status(200).json({ + success: true, + description: `Returned ${playcountPBs.length} scores.`, + body: { + songs, + charts, + pbs: playcountPBs, + }, + }); +}); + +/** + * Returns the users around the given user on the leaderboard. + * + * @param alg - Optional, the algorithm to use. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/leaderboard-adjacent + */ +router.get("/leaderboard-adjacent", async (req, res) => { + const { game, playtype, user } = GetUGPT(req); + + const gptConfig = GetGamePTConfig(game, playtype); + + let alg = gptConfig.defaultProfileRatingAlg; + + if (IsString(req.query.alg)) { + const temp = CheckStrProfileAlg(game, playtype, req.query.alg); + + if (temp === null) { + return res.status(400).json({ + success: false, + description: `Invalid value of ${ + req.query.alg + } for alg. Expected one of ${Object.keys(gptConfig.profileRatingAlgs).join(", ")}`, + }); + } + + alg = temp; + } + + const thisUsersStats = await db["game-stats"].findOne({ game, playtype, userID: user.id }); + + if (!thisUsersStats) { + return res.status(400).json({ + success: false, + description: `This user has not played this game.`, + }); + } + + const [above, below] = await Promise.all([ + db["game-stats"].find( + { + game, + playtype, + userID: { $ne: user.id }, + [`ratings.${alg}`]: { $gt: thisUsersStats.ratings[alg] }, + }, + { + limit: 5, + sort: { + [`ratings.${alg}`]: 1, + }, + }, + ), + db["game-stats"].find( + { + game, + playtype, + userID: { $ne: user.id }, + [`ratings.${alg}`]: { $lte: thisUsersStats.ratings[alg] }, + }, + { + limit: 5, + sort: { + [`ratings.${alg}`]: -1, + }, + }, + ), + ]); + + const users = await GetUsersWithIDs([ + ...above.map((e) => e.userID), + ...below.map((e) => e.userID), + ]); + + const thisUsersRanking = await GetUsersRankingAndOutOf(thisUsersStats, alg); + + return res.status(200).json({ + success: true, + description: `Returned ${above.length + below.length} nearby stats.`, + body: { + above: above.reverse(), + below, + users, + thisUsersStats, + thisUsersRanking, + }, + }); +}); + +/** + * Retrieve activity for this user. + * + * @param session - See CreateActivityRouteHandler + * @param startTime - See CreateActivityRouteHandler + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/activity + */ +router.get("/activity", (req, res) => { + const { game, playtype, user } = GetUGPT(req); + + const route = CreateActivityRouteHandler({ + userID: user.id, + game, + playtype, + }); + + // this handles responding + void route(req, res); +}); + +/** + * Completely wipe this profile. + * Requires a self-request from this user, and also checks that the user knows their + * password. This is one of the most bolted down endpoints in the site, for obvious + * reasons. + * + * @param !password - This user's password. + * + * @name DELETE /api/v1/users/:userID/games/:game/:playtype + */ +router.delete( + "/", + RequireSelfRequestFromUser, + RequireAuthedAsUser, + prValidate({ + "!password": ValidatePassword, + }), + async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + const body = req.safeBody as { + "!password": string; + }; + + log.info( + `Recieved request to delete UGPT ${FormatUserDoc(user)} ${FormatGameGroup(game, playtype)}`, + ); + + const privateInfo = await GetUserPrivateInfo(user.id); + + if (!privateInfo) { + log.error( + { user }, + `State desync for user ${FormatUserDoc( + user, + )}. This user has no password/email information?`, + ); + + return res.status(500).json({ + success: false, + description: `An internal server error has occured.`, + }); + } + + const passwordMatch = await PasswordCompare(body["!password"], privateInfo.password); + + if (!passwordMatch) { + return res.status(403).json({ + success: false, + description: `Invalid password.`, + }); + } + + await DestroyUserGamePlaytypeData(user.id, game, playtype); + + return res.status(200).json({ + success: true, + description: `Destroyed profile.`, + body: {}, + }); + }, +); + +router.use("/pbs", pbsRouter); +router.use("/scores", scoresRouter); +router.use("/sessions", sessionsRouter); +router.use("/tables", tablesRouter); +router.use("/showcase", showcaseRouter); +router.use("/settings", settingsRouter); +router.use("/folders", foldersRouter); +router.use("/targets", targetsRouter); +router.use("/rivals", rivalsRouter); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/scores/router.test.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/scores/router.test.ts new file mode 100644 index 000000000..5c1e8dcaf --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/scores/router.test.ts @@ -0,0 +1,239 @@ +import type { ChartDocument, ScoreDocument } from "tachi-common"; + +import db from "#services/mongo/db"; +import { mkFakeScoreIIDXSP, mkFakeScoreSDVX } from "#test-utils/misc"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { + GetKTDataJSON, + LoadTachiIIDXData, + Testing511Song, + Testing511SPA, +} from "#test-utils/test-data"; +import t from "tap"; + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/scores/recent", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return a users 100 most recent scores.", async (t) => { + const mockScores: Array = []; + + for (let i = 0; i < 200; i++) { + mockScores.push({ + userID: 1, + game: "iidx", + playtype: "SP", + timeAchieved: i * 100, + scoreID: `scoreID_${i}`, + chartID: Testing511SPA.chartID, + songID: Testing511Song.id, + } as ScoreDocument); + } + + await db.scores.insert(mockScores); + + const res = await mockApi.get("/api/v1/users/1/games/iidx/SP/scores/recent"); + + t.hasStrict(res.body, { + success: true, + description: "Retrieved 100 scores.", + body: { + scores: mockScores.slice(100).reverse(), + songs: [Testing511Song], + charts: [Testing511SPA], + }, + }); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/scores", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(LoadTachiIIDXData); + + t.test("Should return 400 if no search param is given", async (t) => { + const res = await mockApi.get("/api/v1/users/test_zkldi/games/iidx/SP/scores"); + + t.equal(res.statusCode, 400); + t.equal(res.body.success, false); + + t.end(); + }); + + t.test("Should return 400 if invalid search param is given", async (t) => { + const res = await mockApi.get( + "/api/v1/users/test_zkldi/games/iidx/SP/scores?search=foo&search=bar", + ); + + t.equal(res.statusCode, 400); + t.equal(res.body.success, false); + + // evil eval attempts + const res2 = await mockApi.get( + "/api/v1/users/test_zkldi/games/iidx/SP/scores?search[$where]=process.exit(1)", + ); + + t.equal(res2.statusCode, 400); + t.equal(res2.body.success, false); + + t.end(); + }); + + t.test("Should search a user's scores.", async (t) => { + const mockScores: Array = []; + + const charts = GetKTDataJSON("./tachi/tachi-charts-iidx.json") as Array< + ChartDocument<"iidx:DP" | "iidx:SP"> + >; + + for (let i = 0; i < 200; i++) { + const chart = charts[i]; + + if (!chart) { + return t.fail( + `tachi-charts-iidx.json doesn't have enough mock data for testing. Needed atleast 200 entries, but failed to retrieve one at index ${i}.`, + ); + } + + mockScores.push({ + scoreID: i.toString(), + userID: 1, + game: "iidx", + playtype: "SP", + isPrimary: true, + chartID: chart.chartID, + songID: chart.songID, + calculatedData: { + ktLampRating: i, + }, + } as ScoreDocument); + } + + await db.scores.insert(mockScores); + + const res = await mockApi.get( + "/api/v1/users/test_zkldi/games/iidx/SP/scores?search=5.1.1.", + ); + + t.equal(res.body.body.scores.length, 5); + t.equal(res.body.body.songs.length, 1); + t.equal(res.body.body.charts.length, 4); + + t.hasStrict(res.body, { + success: true, + description: "Retrieved 5 scores.", + body: { + scores: [ + { + songID: 1, + }, + { + songID: 1, + }, + { + songID: 1, + }, + ], + songs: [ + { + title: "5.1.1.", + }, + ], + charts: [ + { + songID: 1, + }, + { + songID: 1, + }, + ], + }, + }); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/scores/all", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return every score from a user.", async (t) => { + await db.scores.remove({}); + await db.scores.insert([ + mkFakeScoreIIDXSP({ scoreID: "score_1" }), + mkFakeScoreIIDXSP({ scoreID: "score_2" }), + mkFakeScoreIIDXSP({ scoreID: "score_3" }), + mkFakeScoreIIDXSP({ scoreID: "other_score", userID: 2 }), + mkFakeScoreSDVX({ scoreID: "other_game_same_user" }), + ]); + + const res = await mockApi.get("/api/v1/users/1/games/iidx/SP/scores/all"); + + t.equal(res.statusCode, 200, "Should return 200"); + + t.strictSame( + res.body.body.scores.map((e: ScoreDocument) => e.scoreID), + ["score_1", "score_2", "score_3"], + ); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/scores/:chartID", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(LoadTachiIIDXData); + + t.test("Should return a users score history on a given chart.", async (t) => { + await db.scores.remove({}); + await db.scores.insert([ + { + chartID: Testing511SPA.chartID, + userID: 1, + scoreID: "foo", + }, + { + chartID: Testing511SPA.chartID, + userID: 1, + scoreID: "bar", + }, + { + chartID: Testing511SPA.chartID, + userID: 2, + scoreID: "baz", + }, + ] as Array); + + const res = await mockApi.get( + `/api/v1/users/1/games/iidx/SP/scores/${Testing511SPA.chartID}`, + ); + + const scoreIDs = res.body.body.map((e: ScoreDocument) => e.scoreID); + + t.equal(scoreIDs.length, 2); + t.ok(scoreIDs.includes("foo")); + t.ok(scoreIDs.includes("bar")); + + t.end(); + }); + + t.test("Should reject a chart that does not exist.", async (t) => { + const res = await mockApi.get( + `/api/v1/users/1/games/iidx/SP/scores/CHART_THAT_DOESNT_EXIST`, + ); + + t.equal(res.statusCode, 404); + t.match(res.body.description, /chart does not exist/iu); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/scores/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/scores/router.ts new file mode 100644 index 000000000..7778462ca --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/scores/router.ts @@ -0,0 +1,151 @@ +import { SearchSpecificGameSongsAndCharts } from "#lib/search/search"; +import { HyperAggressiveRateLimitMiddleware } from "#server/middleware/rate-limiter"; +import db from "#services/mongo/db"; +import { GetRelevantSongsAndCharts } from "#utils/db"; +import { GetUGPT } from "#utils/req-tachi-data"; +import { FilterChartsAndSongs } from "#utils/scores"; +import { Router } from "express"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Searches a user's individual scores. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/scores + */ +router.get("/", async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + if (typeof req.query.search !== "string") { + return res.status(400).json({ + success: false, + description: `Invalid value for search parameter.`, + }); + } + + const { songs: allSongs, charts: allCharts } = await SearchSpecificGameSongsAndCharts( + game, + req.query.search, + playtype, + ); + + const scores = await db.scores.find( + { + chartID: { $in: allCharts.map((e) => e.chartID) }, + userID: user.id, + }, + { + sort: { + timeAchieved: -1, + }, + limit: 30, + }, + ); + + const { songs, charts } = FilterChartsAndSongs(scores, allCharts, allSongs); + + return res.status(200).json({ + success: true, + description: `Retrieved ${scores.length} scores.`, + body: { + scores, + songs, + charts, + }, + }); +}); + +/** + * Retrieve all scores from this user. + * + * @warn This endpoint is expensive, and is rate-limited as such. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/scores/all + */ +router.get("/all", HyperAggressiveRateLimitMiddleware, async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const scores = await db.scores.find({ + userID: user.id, + game, + playtype, + isPrimary: true, + }); + + const { songs, charts } = await GetRelevantSongsAndCharts(scores, game); + + return res.status(200).json({ + success: true, + description: `Returned ${scores.length} PBs.`, + body: { scores, songs, charts }, + }); +}); + +/** + * Returns a users recent 100 scores for this game. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/scores/recent + */ +router.get("/recent", async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const recentScores = await db.scores.find( + { + userID: user.id, + game, + playtype, + }, + { + limit: 100, + sort: { + timeAchieved: -1, + }, + }, + ); + + const { songs, charts } = await GetRelevantSongsAndCharts(recentScores, game); + + return res.status(200).json({ + success: true, + description: `Retrieved ${recentScores.length} scores.`, + body: { + scores: recentScores, + songs, + charts, + }, + }); +}); + +/** + * Retrieve all the scores a user has on the given chartID. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/scores/:chartID + */ +router.get("/:chartID", async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const chart = await db.anyCharts[game].findOne({ + chartID: req.params.chartID, + playtype, + }); + + if (!chart) { + return res.status(404).json({ + success: false, + description: `This chart does not exist.`, + }); + } + + const scores = await db.scores.find({ + userID: user.id, + chartID: chart.chartID, + }); + + return res.status(200).json({ + success: true, + description: `Returned ${scores.length} scores.`, + body: scores, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/sessions/router.test.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/sessions/router.test.ts new file mode 100644 index 000000000..ec0261464 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/sessions/router.test.ts @@ -0,0 +1,244 @@ +import type { SessionDocument } from "tachi-common"; + +import db from "#services/mongo/db"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { LoadTachiIIDXData } from "#test-utils/test-data"; +import t from "tap"; + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/sessions", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(LoadTachiIIDXData); + + t.test("Should return 400 if no search param is given", async (t) => { + const res = await mockApi.get("/api/v1/users/test_zkldi/games/iidx/SP/sessions"); + + t.equal(res.statusCode, 400); + t.equal(res.body.success, false); + + t.end(); + }); + + t.test("Should return 400 if invalid search param is given", async (t) => { + const res = await mockApi.get( + "/api/v1/users/test_zkldi/games/iidx/SP/sessions?search=foo&search=bar", + ); + + t.equal(res.statusCode, 400); + t.equal(res.body.success, false); + + // evil eval attempts + const res2 = await mockApi.get( + "/api/v1/users/test_zkldi/games/iidx/SP/sessions?search[$where]=process.exit(1)", + ); + + t.equal(res2.statusCode, 400); + t.equal(res2.body.success, false); + + t.end(); + }); + + t.test("Should search a user's sessions.", async (t) => { + await db.sessions.insert( + ["Epic Session", "Session Of Epic", "Epic Gaming", "something else", "bad session"].map( + (e) => ({ + userID: 1, + game: "iidx", + playtype: "SP", + name: e, + desc: "something", + + // hack to avoid db nonsense + sessionID: e, + }), + ) as Array, + ); + + const res = await mockApi.get( + "/api/v1/users/test_zkldi/games/iidx/SP/sessions?search=Epic", + ); + + t.hasStrict(res.body, { + success: true, + description: "Retrieved 3 sessions.", + body: [], + }); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/sessions/best", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(LoadTachiIIDXData); + + t.test("Should return a user's best 100 sessions.", async (t) => { + const sessions: Array = []; + + for (let i = 0; i < 200; i++) { + sessions.push({ + sessionID: i.toString(), + game: "iidx", + playtype: "SP", + userID: 1, + scoreIDs: [], + calculatedData: { + ktLampRating: i, + }, + desc: null, + name: i.toString(), + highlight: false, + timeEnded: 0, + timeInserted: 0, + timeStarted: 0, + }); + } + + await db.sessions.remove({}); + await db.sessions.insert(sessions); + + const res = await mockApi.get("/api/v1/users/test_zkldi/games/iidx/SP/sessions/best"); + + t.hasStrict(res.body, { + success: true, + description: "Retrieved 100 sessions.", + }); + + t.strictSame( + res.body.body.map((e: SessionDocument) => e.sessionID), + sessions + .slice(100) + .reverse() + .map((e) => e.sessionID), + ); + + t.end(); + }); + + t.test( + "Should return a user's best 100 sessions according to the provided rating alg.", + async (t) => { + const sessions: Array = []; + + for (let i = 0; i < 200; i++) { + sessions.push({ + sessionID: i.toString(), + game: "iidx", + playtype: "SP", + userID: 1, + scoreIDs: [], + calculatedData: { + ktLampRating: 200 - i, + BPI: i, + }, + desc: null, + name: i.toString(), + highlight: false, + timeEnded: 0, + timeInserted: 0, + timeStarted: 0, + }); + } + + await db.sessions.remove({}); + await db.sessions.insert(sessions); + + const res = await mockApi.get( + "/api/v1/users/test_zkldi/games/iidx/SP/sessions/best?alg=BPI", + ); + + t.hasStrict(res.body, { + success: true, + description: "Retrieved 100 sessions.", + }); + + t.strictSame( + res.body.body.map((e: SessionDocument) => e.sessionID), + sessions + .slice(100) + .reverse() + .map((e) => e.sessionID), + ); + + t.end(); + }, + ); + + t.end(); +}); + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/sessions/highlighted", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return only highlighted sessions.", async (t) => { + await db.sessions.insert({ + highlight: true, + userID: 1, + game: "iidx", + playtype: "SP", + sessionID: "highlighted_id", + scoreIDs: [""], + } as SessionDocument); + + const res = await mockApi.get("/api/v1/users/1/games/iidx/SP/sessions/highlighted"); + + t.equal(res.body.body.length, 1); + t.equal(res.body.body[0].sessionID, "highlighted_id"); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/sessions/recent", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return the users most recent sessions.", async (t) => { + await db.sessions.remove({}); + await db.sessions.insert([ + { + highlight: false, + userID: 1, + game: "iidx", + playtype: "SP", + sessionID: "recent_id1", + timeEnded: 1, + scoreIDs: [""], + }, + { + highlight: false, + userID: 1, + game: "iidx", + playtype: "SP", + sessionID: "recent_id2", + timeEnded: 3, + scoreIDs: [""], + }, + { + highlight: false, + userID: 1, + game: "iidx", + playtype: "SP", + sessionID: "recent_id3", + timeEnded: 2, + scoreIDs: [""], + }, + ] as Array); + + const res = await mockApi.get("/api/v1/users/1/games/iidx/SP/sessions/recent"); + + t.equal(res.body.body.length, 3); + t.strictSame( + // @ts-expect-error temporary type hack + res.body.body.map((e) => e.sessionID), + ["recent_id2", "recent_id3", "recent_id1"], + ); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/sessions/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/sessions/router.ts new file mode 100644 index 000000000..0e5ad7903 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/sessions/router.ts @@ -0,0 +1,248 @@ +import { GetSessionScoreInfo } from "#lib/score-import/framework/sessions/sessions"; +import { SearchSessions } from "#lib/search/search"; +import db from "#services/mongo/db"; +import { GetUGPT } from "#utils/req-tachi-data"; +import { CheckStrSessionAlg } from "#utils/string-checks"; +import { Router } from "express"; +import { + type AnySessionRatingAlg, + GetGamePTConfig, + type SessionDocument, + type SessionScoreInfo, +} from "tachi-common"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Search a users sessions. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/sessions + */ +router.get("/", async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + if (typeof req.query.search !== "string") { + return res.status(400).json({ + success: false, + description: `Invalid value for search parameter.`, + }); + } + + const sessions = await SearchSessions(req.query.search, game, playtype, user.id, 100); + + return res.status(200).json({ + success: true, + description: `Retrieved ${sessions.length} sessions.`, + body: sessions, + }); +}); + +/** + * Returns a user's best 100 sessions according to the default statistic + * for that game. + * + * @param alg - An override to specify a different algorithm for that game. + * @name GET /api/v1/users/:userID/games/:game/:playtype/sessions/best + */ +router.get("/best", async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const gptConfig = GetGamePTConfig(game, playtype); + + let alg = gptConfig.defaultSessionRatingAlg as AnySessionRatingAlg; + + if (typeof req.query.alg === "string") { + const userAlg = CheckStrSessionAlg(game, playtype, req.query.alg); + + if (userAlg === null) { + return res.status(400).json({ + success: false, + description: `Invalid algorithm '${ + req.query.alg + }' provided. Expected any of ${Object.keys(gptConfig.sessionRatingAlgs).join( + ", ", + )}.`, + }); + } + + alg = userAlg; + } + + const sessions = await db.sessions.find( + { + userID: user.id, + game, + playtype, + }, + { + limit: 100, + sort: { + [`calculatedData.${alg}`]: -1, + }, + }, + ); + + const sessionsWithScoreInfo: Array<{ __scoreInfo: Array } & SessionDocument> = + []; + + await Promise.all( + sessions.map((session) => + GetSessionScoreInfo(session).then((r) => { + sessionsWithScoreInfo.push({ + ...session, + __scoreInfo: r, + }); + }), + ), + ); + + sessionsWithScoreInfo.sort( + (a, b) => (b.calculatedData[alg] ?? -Infinity) - (a.calculatedData[alg] ?? -Infinity), + ); + + return res.status(200).json({ + success: true, + description: `Retrieved ${sessions.length} sessions.`, + body: sessionsWithScoreInfo, + }); +}); + +/** + * Returns a users 100 most recent highlighted sessions. Returned in timeEnded order. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/sessions/highlighted + */ +router.get("/highlighted", async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const sessions = await db.sessions.find( + { userID: user.id, game, playtype, highlight: true }, + { sort: { timeEnded: -1 }, limit: 100 }, + ); + + const sessionsWithScoreInfo: Array<{ __scoreInfo: Array } & SessionDocument> = + []; + + await Promise.all( + sessions.map((session) => + GetSessionScoreInfo(session).then((r) => { + sessionsWithScoreInfo.push({ + ...session, + __scoreInfo: r, + }); + }), + ), + ); + + return res.status(200).json({ + success: true, + description: `Returned ${sessions.length} sessions.`, + body: sessionsWithScoreInfo, + }); +}); + +/** + * Returns a users 100 most recent sessions. Returned in timeEnded order. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/sessions/recent + */ +router.get("/recent", async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const sessions = await db.sessions.find( + { userID: user.id, game, playtype }, + { sort: { timeEnded: -1 }, limit: 100 }, + ); + + const sessionsWithScoreInfo: Array<{ __scoreInfo: Array } & SessionDocument> = + []; + + await Promise.all( + sessions.map((session) => + GetSessionScoreInfo(session).then((r) => { + sessionsWithScoreInfo.push({ + ...session, + __scoreInfo: r, + }); + }), + ), + ); + + sessionsWithScoreInfo.sort((a, b) => b.timeEnded - a.timeEnded); + + return res.status(200).json({ + success: true, + description: `Returned ${sessions.length} sessions.`, + body: sessionsWithScoreInfo, + }); +}); + +/** + * Returns a user's most recent session. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/sessions/last + */ +router.get("/last", async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const session = await db.sessions.findOne( + { userID: user.id, game, playtype }, + { sort: { timeEnded: -1 } }, + ); + + if (!session) { + return res.status(404).json({ + success: false, + description: `This user has not got any sessions!`, + }); + } + + const scoreInfo = await GetSessionScoreInfo(session); + + return res.status(200).json({ + success: true, + description: `Returned a session.`, + body: { + session, + scoreInfo, + }, + }); +}); + +/** + * Returns all sessions, but with unecessary properties removed so as to reduce + * bandwidth. This is used for the calendar view in tachi-client, hence the name. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/sessions/calendar + */ +router.get("/calendar", async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const sessions = await db.sessions.find( + { + userID: user.id, + game, + playtype, + }, + { + projection: { + sessionID: 1, + name: 1, + desc: 1, + highlight: 1, + timeStarted: 1, + timeEnded: 1, + game: 1, + playtype: 1, + }, + }, + ); + + return res.status(200).json({ + success: true, + description: `Found ${sessions.length} events.`, + body: sessions, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/settings/router.test.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/settings/router.test.ts new file mode 100644 index 000000000..257bcbc07 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/settings/router.test.ts @@ -0,0 +1,440 @@ +import type { UGPTSettingsDocument } from "tachi-common"; + +/* eslint-disable no-await-in-loop */ +import db from "#services/mongo/db"; +import { mkFakeUser } from "#test-utils/misc"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import t from "tap"; + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/settings", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return a user's settings.", async (t) => { + const res = await mockApi.get("/api/v1/users/1/games/iidx/SP/settings"); + + t.strictSame(res.body.body, { + userID: 1, + game: "iidx", + playtype: "SP", + preferences: { + preferredScoreAlg: null, + preferredSessionAlg: null, + preferredProfileAlg: null, + preferredRanking: null, + preferredDefaultEnum: null, + defaultTable: null, + stats: [], + gameSpecific: { + display2DXTra: false, + bpiTarget: 0, + }, + }, + rivals: [], + }); + + t.end(); + }); + + t.end(); +}); + +t.test("PATCH /api/v1/users/:userID/games/:game/:playtype/settings", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should update a user's settings.", async (t) => { + await db["api-tokens"].insert({ + userID: 1, + identifier: "api_token", + permissions: { + customise_profile: true, + }, + token: "api_token", + fromAPIClient: null, + }); + + const res = await mockApi + .patch("/api/v1/users/1/games/iidx/SP/settings") + .set("Authorization", "Bearer api_token") + .send({ + preferredScoreAlg: "ktLampRating", + }); + + t.strictSame( + res.body.body, + { + userID: 1, + game: "iidx", + playtype: "SP", + preferences: { + preferredScoreAlg: "ktLampRating", + preferredSessionAlg: null, + preferredProfileAlg: null, + preferredDefaultEnum: null, + preferredRanking: null, + defaultTable: null, + stats: [], + gameSpecific: { + display2DXTra: false, + bpiTarget: 0, + }, + }, + rivals: [], + }, + "Should only update the mutated properties.", + ); + + const data = await db["game-settings"].findOne({ + userID: 1, + game: "iidx", + playtype: "SP", + }); + + t.equal(data?.preferences.preferredScoreAlg, "ktLampRating"); + + t.end(); + }); + + t.test("Should update a user's game specific settings.", async (t) => { + await db["api-tokens"].insert({ + userID: 1, + identifier: "api_token", + permissions: { + customise_profile: true, + }, + token: "api_token", + fromAPIClient: null, + }); + + const res = await mockApi + .patch("/api/v1/users/1/games/iidx/SP/settings") + .set("Authorization", "Bearer api_token") + .send({ + preferredScoreAlg: "ktLampRating", + gameSpecific: { + display2DXTra: true, + bpiTarget: 50, + }, + }); + + t.strictSame( + res.body.body, + { + userID: 1, + game: "iidx", + playtype: "SP", + preferences: { + preferredScoreAlg: "ktLampRating", + preferredSessionAlg: null, + preferredProfileAlg: null, + preferredRanking: null, + preferredDefaultEnum: null, + defaultTable: null, + stats: [], + gameSpecific: { + display2DXTra: true, + bpiTarget: 50, + }, + }, + rivals: [], + }, + "Should only update the mutated properties.", + ); + + const data = await db["game-settings"].findOne({ + userID: 1, + game: "iidx", + playtype: "SP", + }); + + t.equal(data?.preferences.preferredScoreAlg, "ktLampRating"); + + t.end(); + }); + + t.test("Should update an IIDX player's bpiTarget settings.", (t) => { + t.beforeEach(async () => { + await db["api-tokens"].insert({ + userID: 1, + identifier: "api_token", + permissions: { + customise_profile: true, + }, + token: "api_token", + fromAPIClient: null, + }); + }); + + for (const target of [0, 10, 15, 17.5, 100]) { + t.test(`Should be able to update the BPI target to ${target}`, async (t) => { + const res = await mockApi + .patch("/api/v1/users/1/games/iidx/SP/settings") + .set("Authorization", "Bearer api_token") + .send({ + gameSpecific: { + bpiTarget: target, + }, + }); + + t.equal(res.statusCode, 200); + + t.strictSame( + res.body.body, + { + userID: 1, + game: "iidx", + playtype: "SP", + preferences: { + preferredScoreAlg: null, + preferredSessionAlg: null, + preferredProfileAlg: null, + preferredRanking: null, + preferredDefaultEnum: null, + defaultTable: null, + stats: [], + gameSpecific: { + display2DXTra: false, + bpiTarget: target, + }, + }, + rivals: [], + }, + "Should only update the mutated properties.", + ); + + const data = (await db["game-settings"].findOne({ + userID: 1, + game: "iidx", + playtype: "SP", + })) as UGPTSettingsDocument<"iidx:SP"> | undefined; + + t.equal(data?.preferences.gameSpecific.bpiTarget, target); + + t.end(); + }); + } + + t.test("Should reject BPI targets < -15", async (t) => { + const res = await mockApi + .patch("/api/v1/users/1/games/iidx/SP/settings") + .set("Authorization", "Bearer api_token") + .send({ + gameSpecific: { + bpiTarget: -20, + }, + }); + + t.equal(res.statusCode, 400); + + t.end(); + }); + + t.test("Should reject >= 100 BPI targets", async (t) => { + const res = await mockApi + .patch("/api/v1/users/1/games/iidx/SP/settings") + .set("Authorization", "Bearer api_token") + .send({ + gameSpecific: { + bpiTarget: 101, + }, + }); + + t.equal(res.statusCode, 400); + + t.end(); + }); + + t.end(); + }); + + t.test("Should reject arbitrary things on game specific settings.", async (t) => { + await db["api-tokens"].insert({ + userID: 1, + identifier: "api_token", + permissions: { + customise_profile: true, + }, + token: "api_token", + fromAPIClient: null, + }); + + const res = await mockApi + .patch("/api/v1/users/1/games/iidx/SP/settings") + .set("Authorization", "Bearer api_token") + .send({ + preferredScoreAlg: "BPI", + gameSpecific: { + display2DXTra: true, + arbitraryValue: {}, + }, + }); + + t.equal(res.statusCode, 400); + + t.end(); + }); + + t.test("Requires the user to be authed as the requested user.", async (t) => { + await db.users.insert(mkFakeUser(2)); + await db["api-tokens"].insert({ + userID: 2, + identifier: "api_token", + permissions: { + customise_profile: true, + }, + token: "api_token", + fromAPIClient: null, + }); + + const res = await mockApi + .patch("/api/v1/users/1/games/iidx/SP/settings") + .set("Authorization", `Bearer api_token`); + + t.equal(res.statusCode, 403); + + t.end(); + }); + + t.test("Requires the permission customise_profile", async (t) => { + await db["api-tokens"].insert({ + userID: 1, + identifier: "api_token", + permissions: { + customise_profile: false, + }, + token: "api_token", + fromAPIClient: null, + }); + + const res = await mockApi + .patch("/api/v1/users/1/games/iidx/SP/settings") + .set("Authorization", `Bearer api_token`); + + t.equal(res.statusCode, 403); + + t.end(); + }); + + t.test("Should reject invalid values.", async (t) => { + await db["api-tokens"].insert({ + userID: 1, + identifier: "foo", + permissions: { + customise_profile: true, + }, + token: "api_token", + fromAPIClient: null, + }); + + for (const key of [ + "preferredScoreAlg", + "preferredSessionAlg", + "preferredProfileAlg", + ] as const) { + const res = await mockApi + .patch("/api/v1/users/1/games/iidx/SP/settings") + .set("Authorization", "Bearer api_token") + .send({ + [key]: "nonsense", + }); + + t.equal(res.statusCode, 400); + + const data = await db["game-settings"].findOne({ + userID: 1, + game: "iidx", + playtype: "SP", + }); + + t.equal(data?.preferences[key], null, "Should be unmodified."); + } + + t.end(); + }); + + t.test("Should update a user's default table.", async (t) => { + await db["api-tokens"].insert({ + userID: 1, + identifier: "api_token", + permissions: { + customise_profile: true, + }, + token: "api_token", + fromAPIClient: null, + }); + + const res = await mockApi + .patch("/api/v1/users/1/games/iidx/SP/settings") + .set("Authorization", "Bearer api_token") + .send({ + defaultTable: "mock_table", + }); + + t.strictSame( + res.body.body, + { + userID: 1, + game: "iidx", + playtype: "SP", + preferences: { + preferredScoreAlg: null, + preferredSessionAlg: null, + preferredProfileAlg: null, + preferredRanking: null, + preferredDefaultEnum: null, + defaultTable: "mock_table", + stats: [], + gameSpecific: { + display2DXTra: false, + bpiTarget: 0, + }, + }, + rivals: [], + }, + "Should only update the mutated properties.", + ); + + const data = await db["game-settings"].findOne({ + userID: 1, + game: "iidx", + playtype: "SP", + }); + + t.equal(data?.preferences.defaultTable, "mock_table"); + + t.end(); + }); + + t.test("Should not allow updating to a table that doesn't exist.", async (t) => { + await db["api-tokens"].insert({ + userID: 1, + identifier: "api_token", + permissions: { + customise_profile: true, + }, + token: "api_token", + fromAPIClient: null, + }); + + const res = await mockApi + .patch("/api/v1/users/1/games/iidx/SP/settings") + .set("Authorization", "Bearer api_token") + .send({ + defaultTable: "fake_table", + }); + + t.equal(res.statusCode, 400); + + const data = await db["game-settings"].findOne({ + userID: 1, + game: "iidx", + playtype: "SP", + }); + + t.equal(data?.preferences.defaultTable, null); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/settings/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/settings/router.ts new file mode 100644 index 000000000..12470c396 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/settings/router.ts @@ -0,0 +1,183 @@ +import { log } from "#lib/log/log.js"; +import { RequirePermissions } from "#server/middleware/auth"; +import db from "#services/mongo/db"; +import { FormatPrError, optNull } from "#utils/prudence"; +import { GetUGPT } from "#utils/req-tachi-data"; +import { FormatUserDoc } from "#utils/user"; +import { Router } from "express"; +import { p } from "prudence"; +import { + GetGamePTConfig, + GetScoreMetrics, + PrudenceZodShim, + type UGPTSettingsDocument, +} from "tachi-common"; + +import { RequireAuthedAsUser } from "../../../../middleware"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Update your settings. + * + * @param - See the prudence validation. + * + * @name PATCH /api/v1/users/:userID/games/:game/:playtype/settings + */ +router.patch( + "/", + RequireAuthedAsUser, + RequirePermissions("customise_profile"), + async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const gptConfig = GetGamePTConfig(game, playtype); + + const gameSpecificSchema = PrudenceZodShim(gptConfig.preferences); + + const err = p(req.safeBody, { + preferredScoreAlg: p.optional( + p.nullable(p.isIn(Object.keys(gptConfig.scoreRatingAlgs))), + ), + preferredSessionAlg: p.optional( + p.nullable(p.isIn(Object.keys(gptConfig.sessionRatingAlgs))), + ), + preferredProfileAlg: p.optional( + p.nullable(p.isIn(Object.keys(gptConfig.profileRatingAlgs))), + ), + defaultTable: "*?string", + preferredRanking: optNull(p.isIn("global", "rival")), + + gameSpecific: optNull(gameSpecificSchema), + preferredDefaultEnum: optNull(p.isIn(...GetScoreMetrics(gptConfig, "ENUM"))), + }); + + if (err) { + return res.status(400).json({ + success: false, + description: FormatPrError(err, "Invalid game-settings."), + }); + } + + const body = req.safeBody as Partial; + + if (typeof body.defaultTable === "string") { + const table = await db.tables.findOne({ + game, + playtype, + tableID: body.defaultTable, + }); + + if (!table) { + return res.status(400).json({ + success: false, + description: `The table (${body.defaultTable}) does not exist (and therefore cannot be set as a default).`, + }); + } + } + + const updateQuery: Record = {}; + + // @warning Slightly icky dynamic prop assignment instead of copypasta. + for (const key of ["Score", "Session", "Profile"] as const) { + const k = `preferred${key}Alg` as const; + + const value = body[k]; + + if (value !== undefined) { + updateQuery[`preferences.${k}`] = value; + } + } + + if (body.preferredDefaultEnum !== undefined) { + updateQuery[`preferences.preferredDefaultEnum`] = body.preferredDefaultEnum; + } + + if (body.defaultTable !== undefined) { + updateQuery[`preferences.defaultTable`] = body.defaultTable; + } + + if (body.preferredRanking !== undefined) { + updateQuery[`preferences.preferredRanking`] = body.preferredRanking; + } + + if (body.gameSpecific) { + for (const [key, value] of Object.entries(body.gameSpecific)) { + updateQuery[`preferences.gameSpecific.${key}`] = value; + } + } + + if (Object.keys(updateQuery).length === 0) { + const settings = await db["game-settings"].findOne({ + userID: user.id, + game, + playtype, + }); + + return res.status(200).json({ + success: true, + description: `Nothing has been modified, successfully.`, + body: settings, + }); + } + + await db["game-settings"].update( + { + userID: user.id, + game, + playtype, + }, + { + $set: updateQuery, + }, + ); + + const settings = await db["game-settings"].findOne({ + userID: user.id, + game, + playtype, + }); + + if (!settings) { + log.error( + `User ${FormatUserDoc( + user, + )} has no game-settings, but has played ${game} ${playtype}?`, + ); + + return res.status(500).json({ + success: false, + description: `An internal error has occured. Do not repeat this request.`, + }); + } + + return res.status(200).json({ + success: true, + description: `Updated settings.`, + body: settings, + }); + }, +); + +/** + * Returns this user's settings. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/settings + */ +router.get("/", async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const settings = await db["game-settings"].findOne({ + userID: user.id, + game, + playtype, + }); + + return res.status(200).json({ + success: true, + description: `Returned ${FormatUserDoc(user)}'s settings.`, + body: settings, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/showcase/router.test.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/showcase/router.test.ts new file mode 100644 index 000000000..5e9968063 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/showcase/router.test.ts @@ -0,0 +1,430 @@ +import db from "#services/mongo/db"; +import { mkFakeUser } from "#test-utils/misc"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { Testing511SPA, TestingIIDXFolderSP10, TestingIIDXSPScorePB } from "#test-utils/test-data"; +import { CreateFolderChartLookup } from "#utils/folder"; +import deepmerge from "deepmerge"; +import { type ChartDocument, IIDX_GRADES, IIDX_LAMPS, type UserDocument } from "tachi-common"; +import t from "tap"; + +const SetFolders = async () => { + await db.folders.insert(TestingIIDXFolderSP10); + await CreateFolderChartLookup(TestingIIDXFolderSP10, true); + + await db["game-settings"].remove({}); + + await db["game-settings"].insert({ + userID: 1, + game: "iidx", + playtype: "SP", + preferences: { + preferredProfileAlg: null, + preferredScoreAlg: null, + preferredSessionAlg: null, + preferredRanking: null, + preferredDefaultEnum: null, + defaultTable: null, + stats: [ + { + folderID: TestingIIDXFolderSP10.folderID, + mode: "folder", + metric: "lamp", + gte: IIDX_LAMPS.HARD_CLEAR, + }, + { + chartID: Testing511SPA.chartID, + mode: "chart", + metric: "score", + }, + ], + gameSpecific: { + display2DXTra: false, + bpiTarget: 0, + }, + }, + rivals: [], + }); + + await db["personal-bests"].insert(deepmerge(TestingIIDXSPScorePB, {})); +}; + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/showcase", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(SetFolders); + + t.test("Should return the evaluated stats for this user.", async (t) => { + const res = await mockApi.get("/api/v1/users/1/games/iidx/SP/showcase"); + + t.hasStrict(res.body.body, [ + { + stat: { + mode: "folder", + }, + result: { + value: 1, + outOf: 1, + }, + }, + { + stat: { + mode: "chart", + }, + result: { + value: 1479, + }, + }, + ]); + + t.end(); + }); + + t.test("Should project another users stats over this one if projectUser is set.", async (t) => { + await db["game-settings"].insert({ + userID: 2, + game: "iidx", + playtype: "SP", + preferences: { + preferredProfileAlg: null, + preferredScoreAlg: null, + preferredSessionAlg: null, + preferredRanking: null, + preferredDefaultEnum: null, + defaultTable: null, + stats: [ + { + mode: "folder", + folderID: TestingIIDXFolderSP10.folderID, + metric: "score", + gte: 1480, + }, + ], + gameSpecific: { + display2DXTra: false, + bpiTarget: 0, + }, + }, + rivals: [], + }); + + // hack + await db.users.insert({ + username: "test_acc", + usernameLowercase: "test_acc", + id: 2, + } as UserDocument); + + const res = await mockApi.get("/api/v1/users/1/games/iidx/SP/showcase?projectUser=2"); + + t.hasStrict(res.body.body, [ + { + stat: { + mode: "folder", + }, + result: { + value: 0, + outOf: 1, + }, + }, + ]); + + t.end(); + }); + + t.test("Should return 404 if the user has not played this game.", async (t) => { + const res = await mockApi.get("/api/v1/users/1/games/bms/7K/showcase"); + + t.equal(res.statusCode, 404); + + t.match(res.body.description, /not played/iu); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/showcase/custom", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(SetFolders); + + t.test("Should return a custom folder evaluated stat on a user.", async (t) => { + const res = await mockApi.get( + `/api/v1/users/1/games/iidx/SP/showcase/custom?mode=folder&metric=grade>e=3&folderID=${TestingIIDXFolderSP10.folderID}`, + ); + + t.hasStrict(res.body.body, { + result: { + value: 1, + outOf: 1, + }, + }); + + t.end(); + }); + + t.test("Should return a custom chart evaluated stat on a user.", async (t) => { + const res = await mockApi.get( + `/api/v1/users/1/games/iidx/SP/showcase/custom?mode=chart&metric=grade&chartID=${Testing511SPA.chartID}`, + ); + + t.hasStrict(res.body.body, { + result: { value: IIDX_GRADES.AAA }, + }); + + t.end(); + }); + + t.test("Should reject for invalid folderID.", async (t) => { + const res = await mockApi.get( + `/api/v1/users/1/games/iidx/SP/showcase/custom?mode=folder&metric=grade>e=4`, + ); + + t.equal(res.statusCode, 400, "Should reject for no folderID"); + + const res2 = await mockApi.get( + `/api/v1/users/1/games/iidx/SP/showcase/custom?mode=folder&metric=grade>e=4&folderID=foo&folderID=bar`, + ); + + t.equal(res2.statusCode, 400, "Should reject for non-string folderID"); + + t.end(); + }); + + t.test("Should reject for invalid chartID.", async (t) => { + const res = await mockApi.get( + `/api/v1/users/1/games/iidx/SP/showcase/custom?mode=chart&metric=grade>e=4`, + ); + + t.equal(res.statusCode, 400, "Should reject for no chartID"); + + const res2 = await mockApi.get( + `/api/v1/users/1/games/iidx/SP/showcase/custom?mode=chart&metric=grade&chartID=foo&chartID=bar`, + ); + + t.equal(res2.statusCode, 400, "Should reject for non-string chartID"); + + t.end(); + }); + + t.test("Should reject for chartID that doesn't exist.", async (t) => { + const res = await mockApi.get( + `/api/v1/users/1/games/iidx/SP/showcase/custom?mode=chart&metric=grade&chartID=chart_does_not_exist`, + ); + + t.equal(res.statusCode, 400); + + await db.charts.iidx.insert({ + chartID: "testing_dp_chart", + playtype: "DP", + } as ChartDocument<"iidx:DP">); + + const res2 = await mockApi.get( + `/api/v1/users/1/games/iidx/SP/showcase/custom?mode=chart&metric=grade&chartID=testing_dp_chart`, + ); + + t.equal(res2.statusCode, 400); + + t.end(); + }); + + t.test("Should reject for folderID that doesn't exist.", async (t) => { + const res = await mockApi.get( + `/api/v1/users/1/games/iidx/SP/showcase/custom?mode=folder&metric=grade>e=4&folderID=invalid`, + ); + + t.equal(res.statusCode, 400); + + const res2 = await mockApi.get( + `/api/v1/users/1/games/iidx/SP/showcase/custom?mode=folder&metric=grade>e=4&folderID=${TestingIIDXFolderSP10.folderID},invalid`, + ); + + t.equal(res2.statusCode, 400); + + t.end(); + }); + + t.test("Should reject for invalid mode", async (t) => { + const res = await mockApi.get( + `/api/v1/users/1/games/iidx/SP/showcase/custom?mode=nonsense&metric=grade>e=4&chartID=foo`, + ); + + t.equal(res.statusCode, 400); + + t.end(); + }); + + t.end(); +}); + +t.test("PUT /api/v1/users/:userID/games/:game/:playtype/showcase", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(SetFolders); + + t.beforeEach( + async () => + // eslint-disable-next-line no-return-await + await db["api-tokens"].insert({ + userID: 1, + identifier: "alt_token", + permissions: { + customise_profile: true, + }, + token: "alt_token", + fromAPIClient: null, + }), + ); + + t.test("Requires the user to be authed as the requested user.", async (t) => { + await db.users.insert(mkFakeUser(2)); + await db["api-tokens"].insert({ + userID: 2, + identifier: "alt_token", + permissions: { + customise_profile: true, + }, + token: "altz_token", + fromAPIClient: null, + }); + + const res = await mockApi + .put("/api/v1/users/1/games/iidx/SP/showcase") + .set("Authorization", `Bearer altz_token`); + + t.equal(res.statusCode, 403); + + t.end(); + }); + + t.test("Requires the permission customise_profile", async (t) => { + await db["api-tokens"].insert({ + userID: 1, + identifier: "alt_token", + permissions: { + customise_profile: false, + }, + token: "unauth_token", + fromAPIClient: null, + }); + + const res = await mockApi + .put("/api/v1/users/1/games/iidx/SP/showcase") + .set("Authorization", `Bearer unauth_token`); + + t.equal(res.statusCode, 403); + + t.end(); + }); + + t.test("Should replace a user's preferences.stats with the contained stats.", async (t) => { + const res = await mockApi + .put("/api/v1/users/1/games/iidx/SP/showcase") + .set("Authorization", `Bearer alt_token`) + .send([ + { + mode: "chart", + chartID: Testing511SPA.chartID, + metric: "lamp", + }, + ]); + + t.equal(res.statusCode, 200); + + const data = await db["game-settings"].findOne({ userID: 1, game: "iidx", playtype: "SP" }); + + t.hasStrict( + data?.preferences.stats, + [ + { + mode: "chart", + chartID: Testing511SPA.chartID, + metric: "lamp", + }, + ], + "Should update preferences.stats in the database.", + ); + + t.hasStrict( + res.body.body.preferences.stats, + [ + { + mode: "chart", + chartID: Testing511SPA.chartID, + metric: "lamp", + }, + ], + "Should return the updated preferences", + ); + + t.end(); + }); + + t.test("Should reject for chartID that doesn't exist.", async (t) => { + const res = await mockApi + .put("/api/v1/users/1/games/iidx/SP/showcase") + .set("Authorization", `Bearer alt_token`) + .send([ + { + mode: "chart", + chartID: "chart_id_does_not_exist", + metric: "lamp", + }, + ]); + + t.equal(res.statusCode, 400); + + await db.charts.iidx.insert({ + chartID: "testing_dp_chart", + playtype: "DP", + } as ChartDocument<"iidx:DP">); + + const res2 = await mockApi + .put("/api/v1/users/1/games/iidx/SP/showcase") + .set("Authorization", `Bearer alt_token`) + .send([ + { + mode: "chart", + chartID: "testing_dp_chart", + metric: "lamp", + }, + ]); + + t.equal(res2.statusCode, 400); + + t.end(); + }); + + t.test("Should reject for folderID that doesn't exist.", async (t) => { + const res = await mockApi + .put("/api/v1/users/1/games/iidx/SP/showcase") + .set("Authorization", `Bearer alt_token`) + .send([ + { + mode: "folder", + metric: "grade", + gte: 4, + folderID: "folder_does_not_exist", + }, + ]); + + t.equal(res.statusCode, 400); + + const res2 = await mockApi + .put("/api/v1/users/1/games/iidx/SP/showcase") + .set("Authorization", `Bearer alt_token`) + .send([ + { + mode: "folder", + metric: "grade", + gte: 4, + folderID: [TestingIIDXFolderSP10.folderID, "folder_does_not_exist"], + }, + ]); + + t.equal(res2.statusCode, 400); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/showcase/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/showcase/router.ts new file mode 100644 index 000000000..4caee3adb --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/showcase/router.ts @@ -0,0 +1,339 @@ +import { EvaluateShowcaseStat } from "#lib/showcase/evaluator"; +import { GetRelatedStatDocuments } from "#lib/showcase/get-related"; +import { EvaluateUsersStatsShowcase } from "#lib/showcase/get-stats"; +import { RequirePermissions } from "#server/middleware/auth"; +import { RequireAuthedAsUser } from "#server/router/api/v1/users/_userID/middleware.js"; +import db from "#services/mongo/db"; +import { IsRecord } from "#utils/misc"; +import { FormatPrError } from "#utils/prudence"; +import { GetUGPT } from "#utils/req-tachi-data"; +import { ResolveUser } from "#utils/user"; +import { Router } from "express"; +import { p } from "prudence"; +import { + FormatGameGroup, + GetGamePTConfig, + GetGPTString, + GetScoreMetrics, + type ShowcaseStatDetails, +} from "tachi-common"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Evaluate this users set stats. + * + * @param projectUser - Project another user's stats instead of their set stats. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/showcase + */ +router.get("/", async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + let projectUser; + + if (typeof req.query.projectUser === "string") { + const user = await ResolveUser(req.query.projectUser); + + if (!user) { + return res.status(404).json({ + success: false, + description: `The projected user ${req.query.projectUser} does not exist.`, + }); + } + + projectUser = user.id; + } + + const results = await EvaluateUsersStatsShowcase(user.id, game, playtype, projectUser); + + return res.status(200).json({ + success: true, + description: `Evaluated ${results.length} stats.`, + body: results, + }); +}); + +/** + * Evalulate a custom stat on this user. + * + * @param mode - "folder" or "chart" + * @param metric - "any score metric for this game (i.e. non-optional). + * Also, "playcount" if mode is chart. + * @param chartID - If mode is "chart" this must contain the chartID the stat is referencing. + * @param folderID - If mode is "folder" this must contain the folderID the stat is referencing. + * @param gte - If mode is "folder" this must contain the value the metric must be greater than. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/showcase/custom + */ +router.get("/custom", async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const gptConfig = GetGamePTConfig(game, playtype); + + let stat: ShowcaseStatDetails; + + const availableMetrics = GetScoreMetrics(gptConfig, ["DECIMAL", "ENUM", "INTEGER"]); + + if (req.query.mode === "folder") { + const err = p( + req.query, + { + mode: p.is("folder"), + metric: p.isIn(availableMetrics), + folderID: "string", + + // lazy regex for matching strings that look like numbers + gte: p.regex(/^[0-9]*(.[0-9])?$/u), + }, + {}, + { allowExcessKeys: true }, + ); + + if (err) { + return res.status(400).json({ + success: false, + description: FormatPrError(err, "Invalid folder stat"), + }); + } + + const folderID = req.query.folderID as string; + + const folder = await db.folders.findOne({ folderID }); + + if (!folder || folder.game !== game || folder.playtype !== playtype) { + return res.status(400).json({ + success: false, + description: `Invalid folderID - all folders must be for ${FormatGameGroup( + game, + playtype, + )}, and exist.`, + }); + } + + stat = { + mode: "folder", + metric: req.query.metric as string, + folderID, + gte: Number(req.query.gte), + }; + } else if (req.query.mode === "chart") { + const err = p( + req.query, + { + mode: p.is("chart"), + metric: p.isIn(...availableMetrics, "playcount"), + chartID: "string", + }, + {}, + { allowExcessKeys: true }, + ); + + if (err) { + return res.status(400).json({ + success: false, + description: FormatPrError(err, "Invalid chart stat"), + }); + } + + const chart = await db.anyCharts[game].findOne({ chartID: req.query.chartID as string }); + + if (!chart || chart.playtype !== playtype) { + return res.status(400).json({ + success: false, + description: `Chart does not exist, or is not for this game and playtype.`, + }); + } + + stat = { + mode: "chart", + metric: req.query.metric as string, + chartID: req.query.chartID as string, + }; + } else { + return res.status(400).json({ + success: false, + description: `Invalid stat mode - expected either 'chart' or 'folder'.`, + }); + } + + const gpt = GetGPTString(game, playtype); + + const result = await EvaluateShowcaseStat(gpt, stat, user.id); + + const related = await GetRelatedStatDocuments(stat, game); + + return res.status(200).json({ + success: true, + description: `Evaluated Stat for ${user.username}`, + body: { stat, result, related }, + }); +}); + +/** + * Replaces a user's stat showcase. + * + * @name PUT /api/v1/users/:userID/games/:game/:playtype/showcase + */ +router.put("/", RequireAuthedAsUser, RequirePermissions("customise_profile"), async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const gptConfig = GetGamePTConfig(game, playtype); + + if (!Array.isArray(req.safeBody)) { + return res.status(400).json({ + success: false, + description: `No stats provided, or was not an array.`, + }); + } + + if (req.safeBody.length > 6) { + return res.status(400).json({ + success: false, + description: `You are only allowed 6 stats at once.`, + }); + } + + const stats = req.safeBody as Array; + + const availableMetrics = GetScoreMetrics(gptConfig, ["DECIMAL", "ENUM", "INTEGER"]); + + for (const unvalidatedStat of stats) { + let err; + + if (!IsRecord(unvalidatedStat)) { + return res.status(400).json({ + success: false, + description: `Invalid stat -- got null or a non-object.`, + }); + } + + if (unvalidatedStat.mode === "chart") { + err = p(unvalidatedStat, { + chartID: "string", + mode: p.is("chart"), + metric: p.isIn(...availableMetrics, "playcount"), + }); + } else if (unvalidatedStat.mode === "folder") { + err = p(unvalidatedStat, { + folderID: (self) => { + if (typeof self === "string") { + return true; + } else if (Array.isArray(self)) { + return self.length <= 6 && self.every((r) => typeof r === "string"); + } + + return false; + }, + mode: p.is("folder"), + metric: p.isIn(availableMetrics), + + gte: (self, parent) => { + if (typeof self !== "number") { + return "Expected a number."; + } + + if (typeof parent.metric !== "string") { + return `Expected parent.metric to be a string.`; + } + + const conf = + gptConfig.providedMetrics[parent.metric] ?? + gptConfig.derivedMetrics[parent.metric]; + + if (!conf) { + return `Invalid metric ${ + parent.metric + }, Expected any of ${availableMetrics.join(", ")}.`; + } + + if (conf.type === "ENUM") { + return p.isBoundedInteger(0, conf.values.length - 1)(self); + } + + if (conf.type === "GRAPH" || conf.type === "NULLABLE_GRAPH") { + return "Cannot set a showcase stat for this metric."; + } + + if (conf.chartDependentMax) { + return `Cannot set a folder showcase goal for this metric as it is chart dependent.`; + } + + return conf.validate(self); + }, + }); + } else { + return res.status(400).json({ + success: false, + description: `Invalid stat - Expected mode to be 'chart' or 'folder').`, + }); + } + + if (err) { + return res.status(400).json({ + success: false, + description: FormatPrError(err, "Invalid stat."), + }); + } + + const stat = unvalidatedStat as unknown as ShowcaseStatDetails; + + if (stat.mode === "chart") { + // eslint-disable-next-line no-await-in-loop + const chart = await db.anyCharts[game].findOne({ chartID: stat.chartID }); + + if (!chart || chart.playtype !== playtype) { + return res.status(400).json({ + success: false, + description: `Invalid chartID - must be a chart for this game and playtype.`, + }); + } + } else if (unvalidatedStat.mode === "folder") { + const folderIDs = Array.isArray(unvalidatedStat.folderID) + ? unvalidatedStat.folderID + : [unvalidatedStat.folderID]; + + // eslint-disable-next-line no-await-in-loop + const folders = await db.folders.find({ folderID: { $in: folderIDs } }); + + if ( + folders.length !== folderIDs.length || + !folders.every((r) => r.game === game && r.playtype === playtype) + ) { + return res.status(400).json({ + success: false, + + // this error message is kinda lazy. + description: `Invalid folderID - must be a folder for this game and playtype.`, + }); + } + } + } + + await db["game-settings"].update( + { + userID: user.id, + game, + playtype, + }, + { + $set: { + "preferences.stats": req.safeBody, + }, + }, + ); + + const newSettings = await db["game-settings"].findOne({ + userID: user.id, + game, + playtype, + }); + + return res.status(200).json({ + success: true, + description: `Updated stat showcase.`, + body: newSettings, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/tables/router.test.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/tables/router.test.ts new file mode 100644 index 000000000..c2b3d0e24 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/tables/router.test.ts @@ -0,0 +1,47 @@ +import type { FolderDocument } from "tachi-common"; + +import db from "#services/mongo/db"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { TestingIIDXFolderSP10, TestingIIDXSPScorePB } from "#test-utils/test-data"; +import { CreateFolderChartLookup } from "#utils/folder"; +import deepmerge from "deepmerge"; +import t from "tap"; + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/tables/:tableID", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return a users statistics for this table", async (t) => { + const folder = deepmerge(TestingIIDXFolderSP10, { + folderID: "testing_folder", + }) as FolderDocument; + + await db.folders.insert(folder); + + await CreateFolderChartLookup(folder, true); + + await db["personal-bests"].insert(TestingIIDXSPScorePB); + + const res = await mockApi.get("/api/v1/users/1/games/iidx/SP/tables/mock_table"); + + t.equal(res.body.body.folders.length, 1); + t.equal(res.body.body.folders[0].folderID, "testing_folder"); + t.equal(res.body.body.table.tableID, "mock_table"); + t.equal(res.body.body.stats.length, 1); + + t.equal(res.body.body.stats[0].stats.lamp["EX HARD CLEAR"], 1); + t.equal(res.body.body.stats[0].stats.grade.AAA, 1); + + t.end(); + }); + + t.test("Should return 404 if the table does not exist.", async (t) => { + const res = await mockApi.get("/api/v1/users/1/games/iidx/SP/tables/bad_table"); + + t.equal(res.statusCode, 404); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/tables/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/tables/router.ts new file mode 100644 index 000000000..c1b605c5d --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/tables/router.ts @@ -0,0 +1,36 @@ +import { GetEnumDistForFolders, GetFoldersFromTable } from "#utils/folder"; +import { GetTachiData, GetUGPT } from "#utils/req-tachi-data"; +import { Router } from "express"; + +import { GetTableFromParam } from "../../../../../../games/_game/_playtype/tables/middleware"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Retrieves a users statistics on this table. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/tables/:tableID + */ +router.get("/:tableID", GetTableFromParam, async (req, res) => { + const { user } = GetUGPT(req); + + const table = GetTachiData(req, "tableDoc"); + + const folders = await GetFoldersFromTable(table); + + // @optimisable - Requests a lot of charts we don't care about + // could be cached too, i guess. + const stats = await GetEnumDistForFolders(user.id, folders); + + return res.status(200).json({ + success: true, + description: `Returned stats for ${folders.length} folders.`, + body: { + folders, + stats, + table, + }, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/targets/goals/router.test.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/targets/goals/router.test.ts new file mode 100644 index 000000000..aebf89ebb --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/targets/goals/router.test.ts @@ -0,0 +1,708 @@ +import db from "#services/mongo/db"; +import { CreateFakeAuthCookie } from "#test-utils/fake-auth"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { TestSnapshot } from "#test-utils/single-process-snapshot"; +import { + HC511Goal, + HC511UserGoal, + IIDXSPQuestGoals, + IIDXSPQuestGoalSubs, + Testing511SPA, + TestingIIDXFolderSP10, + TestingIIDXSPQuest, + TestingIIDXSPQuestSub, + TestingIIDXSPScore, + TestingIIDXSPScorePB, +} from "#test-utils/test-data"; +import { CreateFolderChartLookup } from "#utils/folder"; +import { + type ChartDocument, + type GoalSubscriptionDocument, + IIDX_GRADES, + IIDX_LAMPS, + type PBScoreDocument, +} from "tachi-common"; +/* eslint-disable no-await-in-loop */ +import dm from "deepmerge"; +import t from "tap"; + +// @ts-expect-error Not sure why the types break here, but they do. +const dupedGoal = dm({}, HC511Goal); + +// @ts-expect-error Not sure why the types break here, but they do. +const dupedGoalSub = dm({}, HC511UserGoal); + +// having two charts available is useful here for testing multi-chart goals. +const anotherFakeChart = dm(Testing511SPA, { + chartID: "another_chart", + difficulty: "HYPER", + data: {}, +}) as ChartDocument<"iidx:SP">; + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/targets/goals", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should retrieve this user's goal subscriptions.", async (t) => { + await db.goals.insert(dupedGoal); + await db["goal-subs"].insert(dupedGoalSub); + + const res = await mockApi.get("/api/v1/users/1/games/iidx/SP/targets/goals"); + + t.equal(res.statusCode, 200); + + t.strictSame(res.body.body, { + goals: [HC511Goal], + goalSubs: [HC511UserGoal], + quests: [], + questSubs: [], + }); + + t.end(); + }); + + t.end(); +}); + +t.test("POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal", async (t) => { + t.beforeEach(ResetDBState); + + const customScorePB = dm(TestingIIDXSPScorePB, { + scoreData: TestingIIDXSPScore.scoreData, + }) as PBScoreDocument; + + t.beforeEach(async () => { + await db["personal-bests"].remove({}); + await db["personal-bests"].insert(customScorePB); + }); + + const cookie = await CreateFakeAuthCookie(mockApi); + + const baseInput = { + criteria: { + key: "percent", + value: 80, + mode: "single", + }, + charts: { + type: "single", + data: Testing511SPA.chartID, + }, + }; + + function mkInput(caseName: string, merge: any) { + const input = { + caseName, + content: dm(baseInput, merge) as any, + }; + + // if we've set this prop to undefined, we want to delete it, actually. + if (input.content.charts.data === undefined) { + delete input.content.charts.data; + } + + return input; + } + + t.beforeEach(() => db.charts.iidx.insert(anotherFakeChart)); + + // @ts-expect-error weird type issues + t.beforeEach(() => db.folders.insert(dm(TestingIIDXFolderSP10, {}))); + + t.beforeEach(() => CreateFolderChartLookup(TestingIIDXFolderSP10, true)); + + const multiCharts = { + type: "multi", + data: [Testing511SPA.chartID, "another_chart"], + }; + + const folderCharts = { + type: "folder", + data: TestingIIDXFolderSP10.folderID, + }; + + const absModeCriteria = { + mode: "absolute", + countNum: 2, + }; + + const proportionModeCriteria = { + mode: "proportion", + countNum: 1, + }; + + t.test("Should set valid goals.", async (t) => { + const validInput = [ + mkInput("Percent:Single Case", {}), + mkInput("Score:Single Case", { + criteria: { + key: "score", + value: 1000, + }, + }), + mkInput("LampIndex:Single Case", { + criteria: { + key: "lamp", + value: IIDX_LAMPS.EX_HARD_CLEAR, + }, + }), + mkInput("GradeIndex:Single Case", { + criteria: { + key: "grade", + value: IIDX_GRADES.AAA, + }, + }), + mkInput("Percent:Multi Case", { + charts: multiCharts, + }), + mkInput("Percent:Multi:Abs Case", { + criteria: absModeCriteria, + charts: multiCharts, + }), + + // NOT LEGAL FOR IIDX, due to being nonsense! NEEDS SPECIFIC TESTING. + // mkInput("Score:Multi Case", { + // criteria: { + // key: "score", + // value: 1, + // }, + // charts: multiCharts, + // }), + mkInput("LampIndex:Multi Case", { + criteria: { + key: "lamp", + value: IIDX_LAMPS.HARD_CLEAR, + }, + charts: multiCharts, + }), + mkInput("LampIndex:Multi:Abs Case", { + criteria: { + key: "lamp", + value: IIDX_LAMPS.HARD_CLEAR, + ...absModeCriteria, + }, + charts: multiCharts, + }), + + mkInput("GradeIndex:Multi Case", { + criteria: { + key: "grade", + value: IIDX_GRADES.AAA, + }, + charts: multiCharts, + }), + mkInput("GradeIndex:Multi:Abs Case", { + criteria: { + key: "grade", + value: IIDX_GRADES.AAA, + ...absModeCriteria, + }, + charts: multiCharts, + }), + mkInput("Percent:Folder Case", { + charts: folderCharts, + }), + mkInput("Percent:Folder:Abs Case", { + criteria: absModeCriteria, + charts: folderCharts, + }), + mkInput("Percent:Folder:Proportion Case", { + criteria: proportionModeCriteria, + charts: folderCharts, + }), + + // also illegal in iidx, bms and pms. + // mkInput("Score:Folder Case", { + // criteria: { + // key: "score", + // value: 1000, + // }, + // charts: folderCharts, + // }), + mkInput("LampIndex:Folder Case", { + criteria: { + key: "lamp", + value: IIDX_LAMPS.HARD_CLEAR, + }, + charts: folderCharts, + }), + mkInput("LampIndex:Folder:Abs Case", { + criteria: { + key: "lamp", + value: IIDX_LAMPS.HARD_CLEAR, + ...absModeCriteria, + }, + charts: folderCharts, + }), + mkInput("LampIndex:Folder:Proportion Case", { + criteria: { + key: "lamp", + value: IIDX_LAMPS.HARD_CLEAR, + ...proportionModeCriteria, + }, + charts: folderCharts, + }), + mkInput("GradeIndex:Folder Case", { + criteria: { + key: "grade", + value: IIDX_GRADES.AAA, + }, + charts: folderCharts, + }), + mkInput("GradeIndex:Folder:Abs Case", { + criteria: { + key: "grade", + value: IIDX_GRADES.AAA, + ...absModeCriteria, + }, + charts: folderCharts, + }), + mkInput("GradeIndex:Folder:Proportion Case", { + criteria: { + key: "grade", + value: IIDX_GRADES.AAA, + ...proportionModeCriteria, + }, + charts: folderCharts, + }), + ]; + + for (const input of validInput) { + await t.test(`Valid Goal: ${input.caseName}`, async (t) => { + const res = await mockApi + .post("/api/v1/users/1/games/iidx/SP/targets/goals/add-goal") + .set("Cookie", cookie) + .send(input.content); + + t.equal( + // this looks stupid, but results in better errmsgs. + res.statusCode === 200 ? 200 : res.body.description, + 200, + "Should return 200", + ); + + // don't bother doing db checks if this is good. + if (res.statusCode !== 200) { + return; + } + + const existsInDb = await db.goals.findOne({ + charts: input.content.charts, + criteria: input.content.criteria, + }); + + t.not(existsInDb, null, "A new goal should be added to the database."); + + const subscribed = await db["goal-subs"].findOne({ + userID: 1, + goalID: existsInDb?.goalID ?? "edge_case", + }); + + t.not( + subscribed, + null, + `Requesting user 1 should be subscribed to their new goal.`, + ); + + t.end(); + }); + } + + t.end(); + }); + + t.test("Should reject invalid goals.", async (t) => { + const invalidInput = [ + mkInput("negative percent", { + criteria: { + value: -1, + }, + }), + // as stupid as it is, it technically "is" a goal, as it's a valid + // value for percent. + // mkInput("percent of 0 is a non-goal", { + // criteria: { + // value: 0, + // }, + // }), + mkInput("percent greater than 100", { + criteria: { + value: 100.1, + }, + }), + mkInput("too big grade", { + criteria: { + key: "grade", + value: IIDX_GRADES.MAX + 1, + }, + }), + mkInput("string enum", { + criteria: { + key: "grade", + value: IIDX_GRADES.MAX.toString(), + }, + }), + mkInput("invalid grade", { + criteria: { + key: "grade", + value: 0.5, + }, + }), + mkInput("too big lamp", { + criteria: { + key: "lamp", + value: IIDX_LAMPS.FULL_COMBO + 1, + }, + }), + mkInput("invalid lamp", { + criteria: { + key: "lamp", + value: 0.5, + }, + }), + mkInput("too big score", { + criteria: { + key: "score", + value: 9_000, + }, + }), + mkInput("abs without countNum", { + criteria: { + mode: "absolute", + }, + charts: multiCharts, + }), + mkInput("proportion without countNum", { + criteria: { + mode: "proportion", + }, + charts: multiCharts, + }), + mkInput("single with countNum", { + criteria: { + mode: "single", + countNum: 123, + }, + }), + mkInput("proportion with negative countNum", { + criteria: { + mode: "proportion", + countNum: -0.5, + }, + charts: multiCharts, + }), + mkInput("proportion with greater than 1 countNum", { + criteria: { + mode: "proportion", + countNum: 1.1, + }, + charts: multiCharts, + }), + mkInput("proportion which results in countNum of 0", { + criteria: { + mode: "proportion", + countNum: 0.05, + }, + charts: multiCharts, + }), + mkInput("nonsense mode", { + criteria: { + mode: "nonsense", + }, + }), + mkInput("abs with countNum but charts.type == single", { + criteria: { + mode: "absolute", + countNum: 1, + }, + charts: { + type: "single", + }, + }), + mkInput("nonsense charts.type", { + charts: { + type: "nonsense", + }, + }), + mkInput("charts.data array when type == single", { + charts: { + type: "single", + data: multiCharts.data, + }, + }), + mkInput("charts.data array of identical chartIDs", { + charts: { + type: "multi", + data: [Testing511SPA.chartID, Testing511SPA.chartID], + }, + }), + mkInput("charts.data array of single chartID", { + charts: { + type: "multi", + data: [Testing511SPA.chartID], + }, + }), + mkInput("charts.data array of chartIDs where some don't exist", { + charts: { + type: "multi", + data: [Testing511SPA.chartID, "not_exist"], + }, + }), + mkInput("charts.data folder refers to folder that doesn't exist", { + charts: { + type: "folder", + data: "fake-folder", + }, + }), + mkInput("nonsense charts.data", { + charts: { + data: "nonsense", + }, + }), + mkInput("multi-score for iidx is illegal", { + criteria: { + key: "score", + value: 1000, + }, + charts: multiCharts, + }), + mkInput("folder-score for iidx is illegal", { + criteria: { + key: "score", + value: 1000, + }, + charts: folderCharts, + }), + mkInput("charts single but criteria not.", { + criteria: { + mode: "absolute", + countNum: 2, + }, + }), + mkInput("LampIndex:Multi:Proportion Case", { + criteria: { + key: "lamp", + value: IIDX_LAMPS.HARD_CLEAR, + ...proportionModeCriteria, + }, + charts: multiCharts, + }), + mkInput("GradeIndex:Multi:Proportion Case", { + criteria: { + key: "grade", + value: IIDX_GRADES.AAA, + ...proportionModeCriteria, + }, + charts: multiCharts, + }), + mkInput("Percent:Multi:Proportion Case", { + criteria: proportionModeCriteria, + charts: multiCharts, + }), + ]; + + for (const input of invalidInput) { + await t.test(`Invalid Goal: ${input.caseName}`, async (t) => { + const res = await mockApi + .post("/api/v1/users/1/games/iidx/SP/targets/goals/add-goal") + .set("Cookie", cookie) + .send(input.content); + + t.equal(res.statusCode, 400); + + TestSnapshot(t, res.body.description, `Invalid Goal: ${input.caseName}`); + + t.end(); + }); + } + + t.end(); + }); + + t.test("Should reject if user tries to subscribe to already subscribed goal.", async (t) => { + const res = await mockApi + .post("/api/v1/users/1/games/iidx/SP/targets/goals/add-goal") + .set("Cookie", cookie) + .send(baseInput); + + t.equal(res.statusCode, 200, "Should allow a subscription the first time."); + + const res2 = await mockApi + .post("/api/v1/users/1/games/iidx/SP/targets/goals/add-goal") + .set("Cookie", cookie) + .send(baseInput); + + t.equal(res2.statusCode, 409, "Should fail the second time."); + + t.end(); + }); + + t.test("Should reject if user tries to subscribe to immediately achieved goal.", async (t) => { + const res = await mockApi + .post("/api/v1/users/1/games/iidx/SP/targets/goals/add-goal") + .set("Cookie", cookie) + .send( + dm(baseInput, { + criteria: { + key: "score", + value: 1, + }, + }), + ); + + t.equal( + res.statusCode, + 400, + "Should disallow goal subscriptions that would be instantly achieved.", + ); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/targets/goals/:goalID", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should retrieve this user's goal subscription.", async (t) => { + await db.goals.insert(dupedGoal); + await db["goal-subs"].insert(dupedGoalSub); + + const res = await mockApi.get( + `/api/v1/users/1/games/iidx/SP/targets/goals/${HC511Goal.goalID}`, + ); + + t.equal(res.statusCode, 200); + + t.hasStrict(res.body.body, { + goal: HC511Goal, + goalSub: HC511UserGoal, + quests: [], + user: { + id: 1, + }, + }); + + t.end(); + }); + + t.test("Should return parent quests if goal has any.", async (t) => { + await db.goals.insert(IIDXSPQuestGoals); + await db["goal-subs"].insert(IIDXSPQuestGoalSubs); + await db.quests.insert(TestingIIDXSPQuest); + + if (!IIDXSPQuestGoalSubs[0] || !IIDXSPQuestGoals[0]) { + throw new Error(`Expected atleast one quest goal or sub to work with?`); + } + + const res = await mockApi.get( + `/api/v1/users/1/games/iidx/SP/targets/goals/${IIDXSPQuestGoalSubs[0].goalID}`, + ); + + t.equal(res.statusCode, 200); + + t.hasStrict(res.body.body, { + goal: IIDXSPQuestGoals[0], + goalSub: IIDXSPQuestGoalSubs[0], + quests: [TestingIIDXSPQuest], + user: { + id: 1, + }, + }); + + t.end(); + }); + + t.test("Should return 404 if the user is not subscribed to this goal ID.", async (t) => { + const res = await mockApi.get(`/api/v1/users/1/games/iidx/SP/targets/goals/INVALID_GOAL`); + + t.equal(res.statusCode, 404); + + t.end(); + }); + + t.end(); +}); + +t.test("DELETE /api/v1/users/:userID/games/:game/:playtype/targets/goals/:goalID", async (t) => { + t.beforeEach(ResetDBState); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should delete a goal subscription if subscribed.", async (t) => { + await db.goals.insert(dupedGoal); + await db["goal-subs"].insert(dupedGoalSub); + + const res = await mockApi + .delete(`/api/v1/users/1/games/iidx/SP/targets/goals/${dupedGoalSub.goalID}`) + .set("Cookie", cookie); + + t.equal(res.statusCode, 200); + + const dbRes = await db["goal-subs"].findOne({ + userID: 1, + goalID: dupedGoal.goalID, + }); + + t.equal(dbRes, null, "Should delete the goal sub from the database."); + + t.end(); + }); + + t.test("Should reject a goal deletion if goal has parent quests.", async (t) => { + await db.quests.insert(TestingIIDXSPQuest); + await db["quest-subs"].insert(TestingIIDXSPQuestSub); + await db.goals.insert(IIDXSPQuestGoals); + await db["goal-subs"].insert( + dm(dupedGoalSub, { goalID: "eg_goal_1" }) as GoalSubscriptionDocument, + ); + + const res = await mockApi + .delete(`/api/v1/users/1/games/iidx/SP/targets/goals/eg_goal_1`) + .set("Cookie", cookie); + + t.equal(res.statusCode, 400); + t.equal( + res.body.description, + `This goal is part of a quest you are subscribed to. It can only be removed by unsubscribing from the relevant quests: '${TestingIIDXSPQuest.name}'.`, + ); + + const dbRes = await db["goal-subs"].findOne({ + userID: 1, + goalID: "eg_goal_1", + }); + + t.not(dbRes, null, "Should NOT delete the goal sub from the database."); + + t.end(); + }); + + t.test("Should reject a goal deletion if not subscribed.", async (t) => { + await db.goals.insert(dupedGoal); + await db["goal-subs"].insert(dupedGoalSub); + + const res = await mockApi + .delete(`/api/v1/users/1/games/iidx/SP/targets/goals/INVALID_GOAL`) + .set("Cookie", cookie); + + t.equal(res.statusCode, 404); + + t.end(); + }); + + t.test("Should reject a goal deletion if not authed.", async (t) => { + await db.goals.insert(dupedGoal); + await db["goal-subs"].insert(dupedGoalSub); + + const res = await mockApi.delete( + `/api/v1/users/1/games/iidx/SP/targets/goals/${dupedGoalSub.goalID}`, + ); + + t.equal(res.statusCode, 401); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/targets/goals/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/targets/goals/router.ts new file mode 100644 index 000000000..9ad6ff471 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/targets/goals/router.ts @@ -0,0 +1,302 @@ +import { SubscribeFailReasons } from "#lib/constants/err-codes"; +import { log } from "#lib/log/log.js"; +import { ServerConfig } from "#lib/setup/config"; +import { + ConstructGoal, + GetQuestsThatContainGoal, + SubscribeToGoal, + UnsubscribeFromGoal, +} from "#lib/targets/goals"; +import { GetParentQuests } from "#lib/targets/quests"; +import { RequirePermissions } from "#server/middleware/auth"; +import prValidate from "#server/middleware/prudence-validate"; +import db from "#services/mongo/db"; +import { GetGoalForIDGuaranteed } from "#utils/db"; +import { AssignToReqTachiData, GetTachiData, GetUGPT } from "#utils/req-tachi-data"; +import { type RequestHandler, Router } from "express"; +import { p } from "prudence"; +import { GetGamePTConfig, type GoalDocument, type QuestDocument } from "tachi-common"; + +import { RequireAuthedAsUser } from "../../../../../middleware"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Retrieves this user's set goals for this GPT. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/targets/goals + */ +router.get("/", async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const goalSubs = await db["goal-subs"].find({ + userID: user.id, + game, + playtype, + }); + + const goals = await db.goals.find({ + goalID: { $in: goalSubs.map((e) => e.goalID) }, + }); + + const allQuests = await GetParentQuests(user.id, game, playtype, goalSubs); + + const questSubs = await db["quest-subs"].find({ userID: user.id, game, playtype }); + + const questSubIDs = questSubs.map((e) => e.questID); + + // filter parent quests to only those that this user is subscribed to + const quests = allQuests.filter((quest) => questSubIDs.includes(quest.questID)); + + return res.status(200).json({ + success: true, + description: `Retrieved ${goalSubs.length} goal(s).`, + body: { + goals, + goalSubs, + quests, + questSubs, + }, + }); +}); + +type GoalCreationBody = Pick; + +/** + * Add a goal to your account. If the goal document already exists, it is subscribed to. + * Otherwise, that goal document is created, and then subscribed to. + * + * @param criteria.key - The key for the goal to be on. This is stuff like scoreData.percent. + * @param criteria.value - The value the key must be greater than for it to count as achieved. + * @param criteria.mode - "single", "absolute" or "proportion". If abs or proportion, countNum + * must be supplied. + * @param criteria.countNum - For abs/proportion mode. Atleast N scores must achieve the + * key:value condition. + * + * @param charts.type - "single", "multi" or "folder". + * @param charts.data - an identifier for the set of charts must be + * supplied here. For single, this is a chartID. For multi, this is an array of chartIDs. + * For folder, this is a folderID. + * + * @name POST /api/v1/users/:userID/games/:game/:playtype/targets/goals/add-goal + */ +router.post( + "/add-goal", + RequireAuthedAsUser, + RequirePermissions("manage_targets"), + prValidate({ + criteria: { + // we do proper validation on this later. + key: "string", + value: p.gte(0), + + mode: p.isIn("single", "absolute", "proportion"), + countNum: (self, parent) => { + if (parent.mode === "single") { + return ( + self === undefined || + "Invalid countNum for mode 'single'. Must not have one!" + ); + } + + // proper validation later. + return p.gte(0)(self); + }, + }, + charts: { + type: p.isIn("single", "multi", "folder"), + data: (self, parent) => { + if (parent.type === "single") { + return ( + typeof self === "string" || + "Expected a string in charts.data due to charts.type being 'single'." + ); + } else if (parent.type === "multi") { + return ( + (Array.isArray(self) && + self.every((k) => typeof k === "string") && + self.length <= 10 && + self.length > 1) || + "Expected an array of 2 to 10 strings in charts.data due to charts.type being 'multi'." + ); + /* istanbul ignore next */ + } else if (parent.type === "folder") { + return ( + typeof self === "string" || + "Expected a string in charts.data due to charts.type being 'folder'." + ); + } + + // impossible to reach, so doesn't count for coverage. + /* istanbul ignore next */ + return "Unknown charts.type."; + }, + }, + }), + async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const existingGoalsCount = await db["goal-subs"].count({ + userID: user.id, + game, + playtype, + }); + + if (existingGoalsCount > ServerConfig.MAX_GOAL_SUBSCRIPTIONS) { + return res.status(400).json({ + success: false, + description: `You already have ${ServerConfig.MAX_GOAL_SUBSCRIPTIONS} goals. You cannot have anymore.`, + }); + } + + const gptConfig = GetGamePTConfig(game, playtype); + + const validCriteria = [ + ...Object.keys(gptConfig.providedMetrics), + ...Object.keys(gptConfig.derivedMetrics), + ]; + + if (!validCriteria.includes(req.body.criteria.key)) { + return res.status(400).json({ + success: false, + description: `Invalid criteria '${ + req.body.criteria.key + }', expected any of ${validCriteria.join(", ")}.`, + }); + } + + const data = req.safeBody as GoalCreationBody; + + let goal; + + try { + goal = await ConstructGoal(data.charts, data.criteria, game, playtype); + } catch (e) { + const err = e as Error; + + log.info({ err }, err.message); + + return res.status(400).json({ + success: false, + description: err.message, + }); + } + + const goalSub = await SubscribeToGoal(user.id, goal, true); + + if (goalSub === SubscribeFailReasons.ALREADY_SUBSCRIBED) { + return res.status(409).json({ + success: false, + description: `You are already subscribed to this goal.`, + }); + } + + if (goalSub === SubscribeFailReasons.ALREADY_ACHIEVED) { + return res.status(400).json({ + success: false, + description: `You can't directly assign goals that you would immediately achieve.`, + }); + } + + return res.status(200).json({ + success: true, + description: `Subscribed to ${goal.name}.`, + body: { + goal, + goalSub, + }, + }); + }, +); + +const GetGoalSubscription: RequestHandler = async (req, res, next) => { + const { user, game, playtype } = GetUGPT(req); + + const goalSub = await db["goal-subs"].findOne({ + userID: user.id, + game, + playtype, + goalID: req.params.goalID, + }); + + if (!goalSub) { + return res.status(404).json({ + success: false, + description: `${user.username} is not subscribed to this goal.`, + }); + } + + AssignToReqTachiData(req, { goalSubDoc: goalSub }); + + next(); +}; + +/** + * Reads information about the users subscription to this goal ID. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/targets/goals/:goalID + */ +router.get("/:goalID", GetGoalSubscription, async (req, res) => { + const { user } = GetUGPT(req); + + const goalSub = GetTachiData(req, "goalSubDoc"); + + const quests: Array = await GetQuestsThatContainGoal(goalSub.goalID); + + const goal = await GetGoalForIDGuaranteed(goalSub.goalID); + + return res.status(200).json({ + success: true, + description: `Returned information about goal '${goal.name}'.`, + body: { + goal, + goalSub, + quests, + user, + }, + }); +}); + +/** + * Unsubscribe from a goal. + * + * @name DELETE /api/v1/users/:userID/games/:game/:playtype/targets/goals/:goalID + */ +router.delete( + "/:goalID", + RequireAuthedAsUser, + GetGoalSubscription, + RequirePermissions("manage_targets"), + async (req, res) => { + const goalSub = GetTachiData(req, "goalSubDoc"); + + const fail = await UnsubscribeFromGoal(goalSub, false); + + if (fail) { + switch (fail.reason) { + case "WAS_STANDALONE": + // can't happen. mightaswell handle it though. + return res.status(400).json({ + success: false, + description: `This goal was assigned by you and can't be removed as a consequence of another action.`, + }); + + case "HAS_QUEST_DEPENDENCIES": + return res.status(400).json({ + success: false, + description: `This goal is part of a quest you are subscribed to. It can only be removed by unsubscribing from the relevant quests: ${fail.parentQuests + .map((e) => `'${e.quest.name}'`) + .join(", ")}.`, + }); + } + } + + return res.status(200).json({ + success: true, + description: `Removed this goal from your subscriptions.`, + body: {}, + }); + }, +); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/targets/quests/router.test.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/targets/quests/router.test.ts new file mode 100644 index 000000000..3ee697f4f --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/targets/quests/router.test.ts @@ -0,0 +1,248 @@ +import type { UserDocument, UserGameStats } from "tachi-common"; + +import db from "#services/mongo/db"; +import { CreateFakeAuthCookie } from "#test-utils/fake-auth"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { + IIDXSPQuestGoals, + IIDXSPQuestGoalSubs, + TestingIIDXSPQuest, + TestingIIDXSPQuestSub, +} from "#test-utils/test-data"; +import t from "tap"; + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/targets/quests", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(() => db.quests.insert(TestingIIDXSPQuest)); + + t.test("Should return all quest subscriptions.", async (t) => { + await db["quest-subs"].insert(TestingIIDXSPQuestSub); + await db.goals.insert(IIDXSPQuestGoals); + + const res = await mockApi.get("/api/v1/users/1/games/iidx/SP/targets/quests"); + + t.strictSame(res.body.body, { + quests: [TestingIIDXSPQuest], + questSubs: [TestingIIDXSPQuestSub], + goals: IIDXSPQuestGoals, + }); + + t.end(); + }); + + t.test("Should panic if quest subs are parentless.", async (t) => { + await db.quests.remove({ questID: TestingIIDXSPQuest.questID }); + await db["quest-subs"].insert(TestingIIDXSPQuestSub); + + const res = await mockApi.get("/api/v1/users/1/games/iidx/SP/targets/quests"); + + t.equal(res.statusCode, 500); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/targets/quests/:questID", (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(() => db.quests.insert(TestingIIDXSPQuest)); + + t.test("Should return the user's specific quest sub.", async (t) => { + await db["quest-subs"].insert(TestingIIDXSPQuestSub); + + await db.goals.insert(IIDXSPQuestGoals); + await db["goal-subs"].insert(IIDXSPQuestGoalSubs); + + const res = await mockApi.get( + `/api/v1/users/1/games/iidx/SP/targets/quests/${TestingIIDXSPQuest.questID}`, + ); + + t.strictSame(res.body.body, { + quest: TestingIIDXSPQuest, + questSub: TestingIIDXSPQuestSub, + results: IIDXSPQuestGoalSubs.map((e) => ({ + achieved: e.achieved, + progress: e.progress, + progressHuman: e.progressHuman, + outOf: e.outOf, + outOfHuman: e.outOfHuman, + goalID: e.goalID, + })), + goals: IIDXSPQuestGoals, + }); + + t.end(); + }); + + t.test("Should return 404 if the user is not subscribed to this quest.", async (t) => { + const res = await mockApi.get( + `/api/v1/users/1/games/iidx/SP/targets/quests/${TestingIIDXSPQuest.questID}`, + ); + + t.equal(res.statusCode, 404); + + t.end(); + }); + + t.end(); +}); + +t.test("PUT /api/v1/users/:userID/games/:game/:playtype/targets/quests/:questID", async (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(() => db.quests.insert(TestingIIDXSPQuest)); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should return 404 if this quest doesn't exist.", async (t) => { + const res = await mockApi + .put(`/api/v1/users/1/games/iidx/SP/targets/quests/fake_quest`) + .set("Cookie", cookie); + + t.equal(res.statusCode, 404); + + t.end(); + }); + + t.test("Should return 409 if user is already subscribed to this quest.", async (t) => { + await db["quest-subs"].insert(TestingIIDXSPQuestSub); + + const res = await mockApi + .put(`/api/v1/users/1/games/iidx/SP/targets/quests/${TestingIIDXSPQuest.questID}`) + .set("Cookie", cookie); + + t.equal(res.statusCode, 409); + + t.end(); + }); + + t.test("Should subscribe to a quest.", async (t) => { + await db.goals.insert(IIDXSPQuestGoals); + + const res = await mockApi + .put(`/api/v1/users/1/games/iidx/SP/targets/quests/${TestingIIDXSPQuest.questID}`) + .set("Cookie", cookie); + + t.equal(res.statusCode, 200); + + const dbRes = await db["quest-subs"].findOne({ + userID: 1, + questID: TestingIIDXSPQuest.questID, + }); + + t.not(dbRes, null, "Should have subscribed the user to the quest."); + + t.end(); + }); + + t.test("Should return 401 if the user is not authed.", async (t) => { + const res = await mockApi.put( + `/api/v1/users/1/games/iidx/SP/targets/quests/${TestingIIDXSPQuest.questID}`, + ); + + t.equal(res.statusCode, 401); + + t.end(); + }); + + t.test("Should return 403 if the user is authed as someone else.", async (t) => { + // We have to make sure that the user exists, otherwise we'll just get + // a normal 404. + await db.users.insert({ + id: 2, + username: "fake_person", + usernameLowercase: "fake_person", + } as UserDocument); + + await db["game-stats"].insert({ + game: "iidx", + playtype: "SP", + userID: 2, + } as UserGameStats); + + const res = await mockApi + .put(`/api/v1/users/2/games/iidx/SP/targets/quests/${TestingIIDXSPQuest.questID}`) + .set("Cookie", cookie); + + t.equal(res.statusCode, 403); + + t.end(); + }); + + t.end(); +}); + +t.test("DELETE /api/v1/users/:userID/games/:game/:playtype/targets/quests/:questID", async (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(() => db.quests.insert(TestingIIDXSPQuest)); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should return 409 if the user is not subscribed to this quest.", async (t) => { + const res = await mockApi + .delete(`/api/v1/users/1/games/iidx/SP/targets/quests/${TestingIIDXSPQuest.questID}`) + .set("Cookie", cookie); + + t.equal(res.statusCode, 409); + + t.end(); + }); + + t.test("Should return 401 if the user is not authed.", async (t) => { + const res = await mockApi.delete( + `/api/v1/users/1/games/iidx/SP/targets/quests/${TestingIIDXSPQuest.questID}`, + ); + + t.equal(res.statusCode, 401); + + t.end(); + }); + + t.test("Should return 403 if the user is authed as someone else.", async (t) => { + // We have to make sure that the user exists, otherwise we'll just get + // a normal 404. + await db.users.insert({ + id: 2, + username: "fake_person", + usernameLowercase: "fake_person", + } as UserDocument); + + await db["game-stats"].insert({ + game: "iidx", + playtype: "SP", + userID: 2, + } as UserGameStats); + + const res = await mockApi + .delete(`/api/v1/users/2/games/iidx/SP/targets/quests/${TestingIIDXSPQuest.questID}`) + .set("Cookie", cookie); + + t.equal(res.statusCode, 403); + + t.end(); + }); + + t.test("Should unsubscribe from a quest.", async (t) => { + await db["quest-subs"].insert(TestingIIDXSPQuestSub); + + const res = await mockApi + .delete(`/api/v1/users/1/games/iidx/SP/targets/quests/${TestingIIDXSPQuest.questID}`) + .set("Cookie", cookie); + + t.equal(res.statusCode, 200); + + t.strictSame(res.body.body.quest, TestingIIDXSPQuest); + + const dbRes = await db["quest-subs"].findOne({ + userID: 1, + questID: TestingIIDXSPQuest.questID, + }); + + t.equal(dbRes, null, "Should have removed the quest from the database."); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/targets/quests/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/targets/quests/router.ts new file mode 100644 index 000000000..d6c3d5a73 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/targets/quests/router.ts @@ -0,0 +1,245 @@ +import { SubscribeFailReasons } from "#lib/constants/err-codes"; +import { log } from "#lib/log/log.js"; +import { ServerConfig } from "#lib/setup/config"; +import { + EvaluateQuestProgress, + GetGoalsInQuests, + SubscribeToQuest, + UnsubscribeFromQuest, +} from "#lib/targets/quests"; +import { RequirePermissions } from "#server/middleware/auth"; +import db from "#services/mongo/db"; +import { AssignToReqTachiData, GetGPT, GetTachiData, GetUGPT } from "#utils/req-tachi-data"; +import { FormatUserDoc } from "#utils/user"; +import { type RequestHandler, Router } from "express"; + +import { RequireAuthedAsUser } from "../../../../../middleware"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Retrieves this user's subscribed quests. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/targets/quests + */ +router.get("/", async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const questSubs = await db["quest-subs"].find({ + userID: user.id, + game, + playtype, + }); + + const quests = await db.quests.find({ + questID: { $in: questSubs.map((e) => e.questID) }, + }); + + if (quests.length !== questSubs.length) { + log.error( + `Found ${questSubs.length} subscriptions, but got ${quests.length} parents. This is a state desync.`, + ); + throw new Error("Failed to fetch quests"); + } + + const goals = await GetGoalsInQuests(quests); + + return res.status(200).json({ + success: true, + description: `Retrieved ${questSubs.length} quest(s).`, + body: { + quests, + questSubs, + goals, + }, + }); +}); + +const GetQuestSubscription: RequestHandler = async (req, res, next) => { + const { user, game, playtype } = GetUGPT(req); + + const questSub = await db["quest-subs"].findOne({ + userID: user.id, + game, + playtype, + questID: req.params.questID, + }); + + if (!questSub) { + return res.status(404).json({ + success: false, + description: `${user.username} is not subscribed to this quest.`, + }); + } + + AssignToReqTachiData(req, { questSubDoc: questSub }); + + next(); +}; + +const GetQuest: RequestHandler = async (req, res, next) => { + const { game, playtype } = GetGPT(req); + + const quest = await db.quests.findOne({ + game, + playtype, + questID: req.params.questID, + }); + + if (!quest) { + return res.status(404).json({ + success: false, + description: `Can't find a quest with id '${req.params.questID}'.`, + }); + } + + AssignToReqTachiData(req, { questDoc: quest }); + + next(); +}; + +/** + * Returns this user's progress on this quest. + * This also evaluates individual progress on all of the quests goals. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/targets/quests/:questID + */ +router.get("/:questID", GetQuest, GetQuestSubscription, async (req, res) => { + const { user } = GetUGPT(req); + + const questSub = GetTachiData(req, "questSubDoc"); + const quest = GetTachiData(req, "questDoc"); + + // Evaluate each goal for the user. This operation is much faster if the user is + // subscribed to the quest (they are), as we can just read their goalSub + // for each goal. + const { goalResults: results, goals } = await EvaluateQuestProgress(user.id, quest); + + return res.status(200).json({ + success: true, + description: `Returned information about ${FormatUserDoc(user)}'s progress on ${ + quest.name + }.`, + body: { + questSub, + quest, + results, + goals, + }, + }); +}); + +/** + * Subscribe to a quest. + * + * @name PUT /api/v1/users/:userID/games/:game/:playtype/targets/quests/:questID + */ +router.put( + "/:questID", + RequireAuthedAsUser, + GetQuest, + RequirePermissions("manage_targets"), + async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const existingQuestsCount = await db["quest-subs"].count({ + userID: user.id, + game, + playtype, + }); + + if (existingQuestsCount > ServerConfig.MAX_QUEST_SUBSCRIPTIONS) { + return res.status(400).json({ + success: false, + description: `You already have ${ServerConfig.MAX_QUEST_SUBSCRIPTIONS} quests. You cannot have anymore for this game.`, + }); + } + + const quest = GetTachiData(req, "questDoc"); + + const alreadySubscibed = await db["quest-subs"].findOne({ + userID: user.id, + questID: quest.questID, + }); + + if (alreadySubscibed) { + return res.status(409).json({ + success: false, + description: `You are already subscribed to this goal.`, + }); + } + + const subResult = await SubscribeToQuest(user.id, quest, false); + + // Users should be able to subscribe to quests EVEN IF they would instantly + // achieve them. + + // if (subResult === SubscribeFailReasons.ALREADY_ACHIEVED) { + // return res.status(400).json({ + // success: false, + // description: `You cannot assign a quest that would be immediately achieved.`, + // }); + // } + + if (subResult === SubscribeFailReasons.ALREADY_SUBSCRIBED) { + return res.status(409).json({ + success: false, + description: `You're already subscribed to this quest.`, + }); + } + + return res.status(200).json({ + success: true, + description: `Subscribed to quest '${quest.name}'.`, + body: { ...subResult, quest }, + }); + }, +); + +/** + * Unsubscribe from a quest. + * + * @name DELETE /api/v1/users/:userID/games/:game/:playtype/targets/quests/:questID + */ +router.delete( + "/:questID", + RequireAuthedAsUser, + GetQuest, + RequirePermissions("manage_targets"), + async (req, res) => { + const { user } = GetUGPT(req); + const quest = GetTachiData(req, "questDoc"); + + log.info( + { + quest, + user, + }, + `User ${FormatUserDoc(user)} is unsubscribing from quest '${quest.name}'.`, + ); + + const questSub = await db["quest-subs"].findOne({ + userID: user.id, + questID: quest.questID, + }); + + if (!questSub) { + return res.status(409).json({ + success: false, + description: `Can't unsubscribe from a quest you were never subscribed to.`, + }); + } + + await UnsubscribeFromQuest(questSub, quest); + + return res.status(200).json({ + success: true, + description: `Unsubscribed from quest.`, + body: { + quest, + }, + }); + }, +); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/targets/router.test.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/targets/router.test.ts new file mode 100644 index 000000000..db4d5e46b --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/targets/router.test.ts @@ -0,0 +1,163 @@ +import type { + GoalDocument, + GoalSubscriptionDocument, + QuestDocument, + QuestSubscriptionDocument, +} from "tachi-common"; + +import db from "#services/mongo/db"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { + HC511Goal, + HC511UserGoal, + TestingIIDXSPQuest, + TestingIIDXSPQuestSub, +} from "#test-utils/test-data"; +import dm from "deepmerge"; +import t from "tap"; + +function mkGoalSub(merge: Partial) { + return dm(HC511UserGoal, merge); +} + +function mkGoal(merge: Partial) { + return dm(HC511Goal, merge); +} + +function mkQuest(merge: Partial) { + return dm(TestingIIDXSPQuest, merge); +} + +function mkQuestSub(merge: Partial) { + return dm(TestingIIDXSPQuestSub, merge); +} + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/targets/recently-achieved", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return subscriptions that were recently achieved by this user.", async (t) => { + await db.goals.insert([ + mkGoal({ + goalID: "achieved_goal", + }), + mkGoal({ + goalID: "not_achieved_goal", + }), + ]); + + await db["goal-subs"].insert([ + mkGoalSub({ + achieved: true, + timeAchieved: 1000, + goalID: "achieved_goal", + }), + mkGoalSub({ + achieved: false, + goalID: "not_achieved_goal", + }), + ]); + + await db.quests.insert([ + mkQuest({}), + mkQuest({ + questID: "not_achieved_quest", + }), + ]); + + await db["quest-subs"].insert([ + mkQuestSub({ + achieved: true, + timeAchieved: 2000, + }), + mkQuestSub({ + achieved: false, + questID: "not_achieved_quest", + }), + ]); + + const res = await mockApi.get("/api/v1/users/1/games/iidx/SP/targets/recently-achieved"); + + t.equal(res.statusCode, 200); + + t.hasStrict(res.body.body, { + quests: [{ questID: "example_quest_id" }], + goals: [{ goalID: "achieved_goal" }], + goalSubs: [{ goalID: "achieved_goal" }], + questSubs: [{ questID: "example_quest_id" }], + user: { id: 1 }, + }); + + t.equal(res.body.body.goals.length, 1); + t.equal(res.body.body.quests.length, 1); + t.equal(res.body.body.goalSubs.length, 1); + t.equal(res.body.body.questSubs.length, 1); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/users/:userID/games/:game/:playtype/targets/recently-raised", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return subscriptions that were recently achieved by this user.", async (t) => { + await db.goals.insert([ + mkGoal({ + goalID: "achieved_goal", + }), + mkGoal({ + goalID: "not_achieved_goal", + }), + ]); + + await db["goal-subs"].insert([ + mkGoalSub({ + achieved: true, + timeAchieved: 1000, + goalID: "achieved_goal", + }), + mkGoalSub({ + achieved: false, + lastInteraction: 1000, + goalID: "not_achieved_goal", + }), + ]); + + await db.quests.insert([ + mkQuest({}), + mkQuest({ + questID: "not_achieved_quest", + }), + ]); + + await db["quest-subs"].insert([ + mkQuestSub({ + achieved: true, + timeAchieved: 2000, + }), + mkQuestSub({ + achieved: false, + lastInteraction: 1000, + questID: "not_achieved_quest", + }), + ]); + + const res = await mockApi.get("/api/v1/users/1/games/iidx/SP/targets/recently-raised"); + + t.equal(res.statusCode, 200); + + t.hasStrict(res.body.body, { + quests: [{ questID: "not_achieved_quest" }], + goals: [{ goalID: "not_achieved_goal" }], + goalSubs: [{ goalID: "not_achieved_goal" }], + questSubs: [{ questID: "not_achieved_quest" }], + user: { id: 1 }, + }); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/targets/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/targets/router.ts new file mode 100644 index 000000000..29de5ecbf --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/games/_game/_playtype/targets/router.ts @@ -0,0 +1,217 @@ +import { log } from "#lib/log/log.js"; +import { GetRelevantGoals } from "#lib/targets/goals"; +import { GetParentQuests } from "#lib/targets/quests"; +import db from "#services/mongo/db"; +import { + GetRecentlyAchievedGoals, + GetRecentlyAchievedQuests, + GetRecentlyInteractedGoals, + GetRecentlyInteractedQuests, +} from "#utils/db"; +import { GetFolderChartIDs } from "#utils/folder"; +import { GetUGPT } from "#utils/req-tachi-data"; +import { Router } from "express"; + +import goalsRouter from "./goals/router"; +import questsRouter from "./quests/router"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Return a user's recently achieved goals and quests. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/targets/recently-achieved + */ +router.get("/recently-achieved", async (req, res) => { + const { game, playtype, user } = GetUGPT(req); + + const userID = user.id; + + const [{ goals, goalSubs }, { quests, questSubs }] = await Promise.all([ + GetRecentlyAchievedGoals({ userID, game, playtype }), + GetRecentlyAchievedQuests({ userID, game, playtype }), + ]); + + return res.status(200).json({ + success: true, + description: `Returned ${user.username}'s recently achieved targets.`, + body: { + goals, + quests, + goalSubs, + questSubs, + user, + }, + }); +}); + +/** + * Returns a user's recently interacted with (raised, etc.) goals and quests. + * Note that this does not include recently achieved. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/targets/recently-raised + */ +router.get("/recently-raised", async (req, res) => { + const { game, playtype, user } = GetUGPT(req); + + const userID = user.id; + + const [{ goals, goalSubs }, { quests, questSubs }] = await Promise.all([ + GetRecentlyInteractedGoals({ userID, game, playtype }), + GetRecentlyInteractedQuests({ userID, game, playtype }), + ]); + + return res.status(200).json({ + success: true, + description: `Returned ${user.username}'s recently achieved targets.`, + body: { + goals, + quests, + goalSubs, + questSubs, + user, + }, + }); +}); + +/** + * Find what unachieved targets this user has set that consider this chart. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/targets/on-chart/:chartID + */ +router.get("/on-chart/:chartID", async (req, res) => { + const { game, playtype, user } = GetUGPT(req); + + const chartID = req.params.chartID; + + const chart = await db.anyCharts[game].findOne({ chartID, playtype }); + + if (!chart) { + return res.status(404).json({ + success: false, + description: `Failed to find a chart with chartID '${chartID}'.`, + }); + } + + const { goals, goalSubsMap } = await GetRelevantGoals( + game, + user.id, + new Set([chartID]), + log, + false, + ); + + const goalSubs = [...goalSubsMap.values()]; + + const quests = await GetParentQuests(user.id, game, playtype, goalSubs); + + const questSubs = await db["quest-subs"].find({ + questID: { $in: quests.map((e) => e.questID) }, + }); + + return res.status(200).json({ + success: true, + description: `Found pertinent goals`, + body: { + goals, + goalSubs, + quests, + questSubs, + }, + }); +}); + +/** + * Find what unachieved targets this user has set that involve this folder. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/targets/on-folder/:folderID + */ +router.get("/on-folder/:folderID", async (req, res) => { + const { game, playtype, user } = GetUGPT(req); + + const folderID = req.params.folderID; + + const folder = await db.folders.findOne({ folderID, playtype }); + + if (!folder) { + return res.status(404).json({ + success: false, + description: `Failed to find a folder with folderID '${folderID}'.`, + }); + } + + const folderChartIDs = await GetFolderChartIDs(folderID); + + const allGoalSubs = await db["goal-subs"].find({ + userID: user.id, + game, + playtype, + }); + + const goalIDs = allGoalSubs.map((e) => e.goalID); + + // goals are relevant to a folder if it's part of a folder type goal + // or if it's on any of the charts in the folder. + // this is convenient for the UI, atleast. + const goals = await Promise.all([ + db.goals.find({ + "charts.type": { $in: ["single", "multi"] }, + "charts.data": { $in: folderChartIDs }, + goalID: { $in: goalIDs }, + }), + db.goals.find({ + "charts.type": "folder", + "charts.data": folderID, + goalID: { $in: goalIDs }, + }), + ]).then((r) => r.flat()); + + const goalSubs = await db["goal-subs"].find({ + goalID: { $in: goals.map((e) => e.goalID) }, + userID: user.id, + game, + playtype, + }); + + const quests = await GetParentQuests(user.id, game, playtype, goalSubs); + + const questSubs = await db["quest-subs"].find({ + questID: { $in: quests.map((e) => e.questID) }, + }); + + return res.status(200).json({ + success: true, + description: `Found pertinent goals`, + body: { + goals, + goalSubs, + quests, + questSubs, + }, + }); +}); + +/** + * Retrieve all of this user's target subscriptions. + * + * @name GET /api/v1/users/:userID/games/:game/:playtype/targets/all-subs + */ +router.get("/all-subs", async (req, res) => { + const { user, game, playtype } = GetUGPT(req); + + const [goalSubs, questSubs] = await Promise.all([ + db["goal-subs"].find({ userID: user.id, game, playtype }), + db["quest-subs"].find({ userID: user.id, game, playtype }), + ]); + + return res.status(200).json({ + success: true, + description: `Returned all target subscriptions.`, + body: { goalSubs, questSubs }, + }); +}); + +router.use("/goals", goalsRouter); +router.use("/quests", questsRouter); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/imports/router.test.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/imports/router.test.ts new file mode 100644 index 000000000..6e17f8b43 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/imports/router.test.ts @@ -0,0 +1,4 @@ +import t from "tap"; + +t.todo("GET /api/v1/users/:userID/imports"); +t.todo("GET /api/v1/users/:userID/imports/failed"); diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/imports/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/imports/router.ts new file mode 100644 index 000000000..93ab5b681 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/imports/router.ts @@ -0,0 +1,104 @@ +import type { FilterQuery } from "mongodb"; +import type { ImportTrackerDocument, ImportTypes } from "tachi-common"; + +import { TachiConfig } from "#lib/setup/config"; +import prValidate from "#server/middleware/prudence-validate"; +import db from "#services/mongo/db"; +import { DeleteUndefinedProps } from "#utils/misc"; +import { GetTachiData } from "#utils/req-tachi-data"; +import { Router } from "express"; +import { p } from "prudence"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Query this user's imports. Returns the 500 most recently-finished imports. + * + * @param importType - Optionally, limit the returns to only this import type. + * @param userIntent - Optionally, limit returns to only those with or without userIntent. + * + * @name GET /api/v1/users/:userID/imports + */ +router.get( + "/", + prValidate({ + importType: p.optional(p.isIn(TachiConfig.IMPORT_TYPES)), + userIntent: p.optional(p.isIn("true", "false")), + }), + async (req, res) => { + const userID = GetTachiData(req, "requestedUser").id; + const importType = req.query.importType as ImportTypes | undefined; + + // all query input ends up as strings, so we need convert it into an optional + // boolean + const userIntent = + req.query.userIntent === undefined ? undefined : req.query.userIntent === "true"; + + const query = { + userIntent, + userID, + importType, + }; + + DeleteUndefinedProps(query); + + const imports = await db.imports.find(query, { + sort: { timeFinished: -1 }, + limit: 500, + }); + + return res.status(200).json({ + success: true, + description: `Found ${imports.length} imports.`, + body: imports, + }); + }, +); + +/** + * Return this users 500 most recent failed imports. + * + * @param userIntent - Optionally, Whether to limit returns to only those with userIntent or without. + * @param importType - Optionally, Whether to limit returns to only a specific importType. + * + * @name GET /api/v1/users/:userID/imports/failed + */ +router.get( + "/failed", + prValidate({ + importType: p.optional(p.isIn(TachiConfig.IMPORT_TYPES)), + userIntent: p.optional(p.isIn("true", "false")), + }), + async (req, res) => { + const userID = GetTachiData(req, "requestedUser").id; + + const importType = req.query.importType as ImportTypes | undefined; + + // all query input ends up as strings, so we need convert it into an optional + // boolean + const userIntent = + req.query.userIntent === undefined ? undefined : req.query.userIntent === "true"; + + const query: FilterQuery = { + type: "FAILED", + userIntent, + userID, + importType, + }; + + DeleteUndefinedProps(query); + + const trackers = await db["import-trackers"].find(query, { + sort: { timeStarted: -1 }, + limit: 500, + }); + + return res.status(200).json({ + success: true, + description: `Found ${trackers.length} failed imports.`, + body: trackers, + }); + }, +); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/cg/_cgType/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/cg/_cgType/router.ts new file mode 100644 index 000000000..432a3741c --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/cg/_cgType/router.ts @@ -0,0 +1,132 @@ +import type { CGServices } from "#lib/score-import/import-types/common/api-cg/types"; +import type { RequestHandler } from "express-serve-static-core"; +import type { CGCardInfo } from "tachi-common"; + +import prValidate from "#server/middleware/prudence-validate"; +import db from "#services/mongo/db"; +import { GetTachiData } from "#utils/req-tachi-data"; +import { Router } from "express"; +import { p } from "prudence"; + +import { RequireSelfRequestFromUser } from "../../../middleware"; + +const router: Router = Router({ mergeParams: true }); + +const ValidateCGType: RequestHandler = (req, res, next) => { + if (req.params.cgType === "dev" || req.params.cgType === "nag" || req.params.cgType === "gan") { + next(); + return; + } + + return res.status(404).json({ + success: false, + description: `No such service 'cg/${req.params.cgType}' is supported.`, + }); +}; + +/** + * Retrieve this user's card info (cardID). + * + * @name GET /api/v1/users/:userID/integrations/cg/:cgType + */ +router.get("/", ValidateCGType, RequireSelfRequestFromUser, async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + const cgType = req.params.cgType as CGServices; + + const cardInfo = await db["cg-card-info"].findOne({ + userID: user.id, + service: cgType, + }); + + if (!cardInfo) { + return res.status(200).json({ + success: true, + description: `User has no card info set.`, + body: null, + }); + } + + return res.status(200).json({ + success: true, + description: `Found card info.`, + body: cardInfo, + }); +}); + +/** + * Write new card details for this CG integration. + * + * @name PUT /api/v1/users/:userID/integrations/cg/:cgType + */ +router.put( + "/", + ValidateCGType, + RequireSelfRequestFromUser, + prValidate( + { + cardID: p.regex(/^[a-zA-Z0-9]{16}$/u), + pin: p.regex(/^[0-9]{4}$/u), + }, + { + cardID: "Expected 16 characters.", + pin: "Expected 4 digits.", + }, + ), + async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + const cgType = req.params.cgType as CGServices; + + const { cardID, pin } = req.safeBody as { + cardID: string; + pin: string; + }; + + const newCardInfo: CGCardInfo = { + service: cgType, + cardID, + pin, + userID: user.id, + }; + + await db["cg-card-info"].update( + { + userID: user.id, + service: cgType, + }, + { $set: newCardInfo }, + { + // insert new card info if the user doesn't have it yet. + upsert: true, + }, + ); + + return res.status(200).json({ + success: true, + description: `Updated cardID and pin.`, + body: {}, + }); + }, +); + +/** + * Unset this user's card details for this CG integration. + * + * @name DELETE /api/v1/users/:userID/integrations/cg/:cgType + */ +router.delete("/", ValidateCGType, RequireSelfRequestFromUser, async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + const cgType = req.params.cgType as CGServices; + + await db["cg-card-info"].remove({ + userID: user.id, + service: cgType, + }); + + return res.status(200).json({ + success: true, + description: `Deleted stored card info.`, + body: {}, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/fervidex/router.test.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/fervidex/router.test.ts new file mode 100644 index 000000000..cf6c9729f --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/fervidex/router.test.ts @@ -0,0 +1,135 @@ +import type { UserDocument } from "tachi-common"; + +import db from "#services/mongo/db"; +import { CreateFakeAuthCookie } from "#test-utils/fake-auth"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import t from "tap"; + +t.test("GET /api/v1/users/:userID/integrations/fervidex/settings", async (t) => { + t.beforeEach(ResetDBState); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should return null if this user has no settings set.", async (t) => { + await db["fer-settings"].remove({}); + + const res = await mockApi + .get("/api/v1/users/1/integrations/fervidex/settings") + .set("Cookie", cookie); + + t.equal(res.statusCode, 200); + + t.equal(res.body.body, null); + + t.end(); + }); + + t.test("Should return this users settings if they have them.", async (t) => { + await db["fer-settings"].update({ userID: 1 }, { $set: { cards: ["foo", "bar"] } }); + + const res = await mockApi + .get("/api/v1/users/1/integrations/fervidex/settings") + .set("Cookie", cookie); + + t.equal(res.statusCode, 200); + + t.strictSame(res.body.body, { + userID: 1, + forceStaticImport: false, + cards: ["foo", "bar"], + }); + + t.end(); + }); + + t.test("Must require self-key level authentication.", async (t) => { + const res = await mockApi.get("/api/v1/users/1/integrations/fervidex/settings"); + + t.equal(res.statusCode, 401); + + const res2 = await mockApi + .get("/api/v1/users/1/integrations/fervidex/settings") + .set("Authorization", "Bearer fake_api_token"); + + t.equal(res2.statusCode, 403); + + // insert a fake user doc so this doesn't 404 + await db.users.insert({ + id: 2, + username: "foo", + usernameLowercase: "foo", + } as UserDocument); + + const res3 = await mockApi + .get("/api/v1/users/2/integrations/fervidex/settings") + .set("Cookie", cookie); + + t.equal(res3.statusCode, 403); + + t.end(); + }); + + t.end(); +}); + +t.test("PATCH /api/v1/users/:userID/integrations/fervidex/settings", async (t) => { + t.beforeEach(ResetDBState); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should update a users settings.", async (t) => { + const res = await mockApi + .patch("/api/v1/users/1/integrations/fervidex/settings") + .send({ + cards: ["foo", "bar"], + }) + .set("Cookie", cookie); + + t.strictSame(res.body.body.cards, ["foo", "bar"]); + + const dbRes = await db["fer-settings"].findOne({ userID: 1 }); + + t.strictSame(dbRes?.cards, ["foo", "bar"]); + + t.end(); + }); + + t.test("Should insert a setting filter document if one doesn't exist.", async (t) => { + await db["fer-settings"].remove({}); + + const res = await mockApi + .patch("/api/v1/users/1/integrations/fervidex/settings") + .send({ + cards: ["foo", "bar"], + }) + .set("Cookie", cookie); + + t.strictSame(res.body.body.cards, ["foo", "bar"]); + + const dbRes = await db["fer-settings"].findOne({ userID: 1 }); + + t.strictSame(dbRes?.cards, ["foo", "bar"]); + + t.end(); + }); + + t.test("Should null settings if null is provided.", async (t) => { + const res = await mockApi + .patch("/api/v1/users/1/integrations/fervidex/settings") + .send({ + cards: null, + }) + .set("Cookie", cookie); + + t.strictSame(res.body.body.cards, null); + + const dbRes = await db["fer-settings"].findOne({ userID: 1 }); + + t.strictSame(dbRes?.cards, null); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/fervidex/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/fervidex/router.ts new file mode 100644 index 000000000..fa1f54813 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/fervidex/router.ts @@ -0,0 +1,92 @@ +import prValidate from "#server/middleware/prudence-validate"; +import { RequireKamaitachi } from "#server/middleware/type-require"; +import db from "#services/mongo/db"; +import { DeleteUndefinedProps } from "#utils/misc"; +import { optNull } from "#utils/prudence"; +import { GetTachiData } from "#utils/req-tachi-data"; +import { Router } from "express"; + +import { RequireSelfRequestFromUser } from "../../middleware"; + +const router: Router = Router({ mergeParams: true }); + +router.use(RequireKamaitachi); +router.use(RequireSelfRequestFromUser); + +/** + * Retrieve your fervidex settings. + * + * @name GET /api/v1/users/:userID/integrations/fervidex/settings + */ +router.get("/settings", async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + + const settingsDoc = await db["fer-settings"].findOne({ + userID: user.id, + }); + + return res.status(200).json({ + success: true, + description: `Retrieved Fervidex settings.`, + body: settingsDoc ?? null, + }); +}); + +/** + * Update your fervidex configuration. + * + * @param cards - An array of strings to be used as a cards whitelist. + * @param forceStaticImport - Whether or whether not to force a static import on non-INF2 clients. + * + * @name PUT /api/v1/users/:userID/integrations/fervidex/settings + */ +router.patch( + "/settings", + prValidate({ cards: optNull(["string"]), forceStaticImport: "*?boolean" }), + async (req, res) => { + const body = req.safeBody as { + cards?: Array | null; + forceStaticImport?: boolean | null; + }; + + if (body.cards && body.cards.length > 6) { + return res.status(400).json({ + success: false, + description: `You cannot have more than 6 card filters at once.`, + }); + } + + const user = GetTachiData(req, "requestedUser"); + + const modifyDocument = req.safeBody; + + DeleteUndefinedProps(modifyDocument); + + if (Object.keys(modifyDocument).length === 0) { + return res.status(400).json({ + success: false, + description: `No modifications sent.`, + }); + } + + await db["fer-settings"].update( + { userID: user.id }, + { + $set: modifyDocument, + }, + { + upsert: true, + }, + ); + + const settings = await db["fer-settings"].findOne({ userID: user.id }); + + return res.status(200).json({ + success: true, + description: `Successfully updated settings.`, + body: settings, + }); + }, +); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/kai/_kaiType/middleware.test.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/kai/_kaiType/middleware.test.ts new file mode 100644 index 000000000..ce2c4a427 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/kai/_kaiType/middleware.test.ts @@ -0,0 +1,33 @@ +import { expressRequestMock } from "#test-utils/mock-request"; +import t from "tap"; + +import { ValidateKaiType } from "./middleware"; + +t.test("#ValidateKaiType", (t) => { + const k = async (k: string) => { + const { res } = await expressRequestMock(ValidateKaiType, { params: { kaiType: k } }); + + return res.statusCode; + }; + + t.test("Should allow flo, eag or min, case insensitively.", async (t) => { + t.equal(await k("flo"), 200); + t.equal(await k("eag"), 200); + t.equal(await k("min"), 200); + t.equal(await k("FLO"), 200); + t.equal(await k("EAG"), 200); + t.equal(await k("MIN"), 200); + t.equal(await k("FlO"), 200); + t.equal(await k("EaG"), 200); + t.equal(await k("MiN"), 200); + t.equal(await k("nonsense"), 400); + t.equal(await k("bad"), 400); + t.equal(await k(""), 400); + t.equal(await k("FLO2"), 400); + t.equal(await k("2FLO"), 400); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/kai/_kaiType/middleware.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/kai/_kaiType/middleware.ts new file mode 100644 index 000000000..d3fa54abb --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/kai/_kaiType/middleware.ts @@ -0,0 +1,20 @@ +import type { RequestHandler } from "express"; + +export const ValidateKaiType: RequestHandler = (req, res, next) => { + const kaiType = req.params.kaiType; + + if (kaiType === undefined) { + throw new Error( + `Expected to find kaiType parameter inside ValidateKaiType on route ${req.originalUrl}.`, + ); + } + + if (!["eag", "flo", "min"].includes(kaiType.toLowerCase())) { + return res.status(400).json({ + success: false, + description: `Invalid kaiType - Expected min, flo or eag.`, + }); + } + + next(); +}; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/kai/_kaiType/router.test.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/kai/_kaiType/router.test.ts new file mode 100644 index 000000000..bce471d4b --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/kai/_kaiType/router.test.ts @@ -0,0 +1,65 @@ +import db from "#services/mongo/db"; +import { CreateFakeAuthCookie } from "#test-utils/fake-auth"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import t from "tap"; + +t.test("GET /api/v1/users/:userID/integrations/kai/:kaiType", async (t) => { + t.beforeEach(ResetDBState); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should return false if unauthed with this kaiType", async (t) => { + const res = await mockApi.get("/api/v1/users/1/integrations/kai/flo").set("Cookie", cookie); + + t.equal(res.statusCode, 200); + t.equal(res.body.body.authStatus, false); + + t.end(); + }); + + t.test("Should return true if authed with this kaiType", async (t) => { + await db["kai-auth-tokens"].insert({ + refreshToken: "refresh", + service: "FLO", + token: "bar", + userID: 1, + }); + + const res = await mockApi.get("/api/v1/users/1/integrations/kai/flo").set("Cookie", cookie); + + t.equal(res.statusCode, 200); + t.equal(res.body.body.authStatus, true); + + t.end(); + }); + + t.test("Should return the auth status of this user specifically.", async (t) => { + await db["kai-auth-tokens"].insert([ + { + refreshToken: "refresh", + service: "EAG", + token: "bar", + userID: 1, + }, + { + refreshToken: "refresh", + service: "FLO", + token: "baz", + userID: 2, + }, + ]); + + const res = await mockApi.get("/api/v1/users/1/integrations/kai/flo").set("Cookie", cookie); + + t.equal(res.statusCode, 200); + t.equal(res.body.body.authStatus, false); + + t.end(); + }); + + t.end(); +}); + +// test is currently undoable due to issues with mocking out real Fetch calls. +t.todo("PATCH /api/v1/users/:userID/integrations/kai/:kaiType/oauth2callback"); diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/kai/_kaiType/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/kai/_kaiType/router.ts new file mode 100644 index 000000000..310e7ca9e --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/kai/_kaiType/router.ts @@ -0,0 +1,220 @@ +import { log } from "#lib/log/log.js"; +import { + GetKaiTypeClientCredentials, + KaiTypeToBaseURL, +} from "#lib/score-import/import-types/common/api-kai/utils"; +import prValidate from "#server/middleware/prudence-validate"; +import { RequireKamaitachi } from "#server/middleware/type-require"; +import db from "#services/mongo/db"; +import fetch from "#utils/fetch"; +import { NotNullish } from "#utils/misc"; +import { GetKaiAuth, RevokeKaiAuth } from "#utils/queries/auth"; +import { GetTachiData } from "#utils/req-tachi-data"; +import { FormatUserDoc } from "#utils/user"; +import { Router } from "express"; +import { p } from "prudence"; + +import { RequireSelfRequestFromUser } from "../../../middleware"; +import { ValidateKaiType } from "./middleware"; + +const router: Router = Router({ mergeParams: true }); + +router.use(RequireKamaitachi, RequireSelfRequestFromUser, ValidateKaiType); + +/** + * Return the authentication status for this kaiType. + * @note - Express's types infer arg0 of "/" to mean no params, for some reason. + * the generic overrides this behaviour. + * + * @name GET /api/v1/users/:userID/integrations/kai/:kaiType + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +router.get("/", async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + const kaiType = NotNullish(req.params.kaiType).toUpperCase() as "EAG" | "FLO" | "MIN"; + + const authDoc = await GetKaiAuth(user.id, kaiType); + + return res.status(200).json({ + success: true, + description: authDoc ? `User is authenticated.` : `User is unauthenticated.`, + body: { + authStatus: !!authDoc, + }, + }); +}); + +/** + * Revoke your authentication for this kaiType. + * @note - Express's types infer arg0 of "/" to mean no params, for some reason. + * the generic overrides this behaviour. + * + * @name DELETE /api/v1/users/:userID/integrations/kai/:kaiType + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +router.delete("/", async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + const kaiType = NotNullish(req.params.kaiType).toUpperCase() as "EAG" | "FLO" | "MIN"; + + const authDoc = await GetKaiAuth(user.id, kaiType); + + if (!authDoc) { + return res.status(409).json({ + success: false, + description: `You are not authorised with this service.`, + }); + } + + await RevokeKaiAuth(user.id, kaiType); + + return res.status(200).json({ + success: true, + description: `Revoked authentication for ${kaiType}.`, + body: {}, + }); +}); + +const KAI_OAUTH2_RETURN_SCHEMA = { + access_token: "string", + refresh_token: "string", +}; + +/** + * The OAuth2 callback used by Kai to send an intermediate token to. + * @note The way this is implemented is *really* weird due to the fact that + * the tachi-server code cannot have any knowledge of the tachi-client code, + * and the two must be agnostic. + * + * This means the tachi-client will handle the redirecting, and will check + * query params for ?code=12345 to know when to POST us with the code + * to perform an update. + * + * @param code - An intermediate code to use to get the real auth token. + * + * @name POST /api/v1/users/:userID/integrations/kai/:kaiType/oauth2callback + */ +router.post( + "/oauth2callback", + prValidate({ code: "string" }, {}, { allowExcessKeys: true }), + async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + const kaiType = NotNullish(req.params.kaiType).toUpperCase() as "EAG" | "FLO" | "MIN"; + + const body = req.safeBody as { + code: string; + }; + + const baseUrl = KaiTypeToBaseURL(kaiType); + + const maybeCredentials = GetKaiTypeClientCredentials(kaiType); + + if (!maybeCredentials) { + log.error( + `Attempted to /callback ${kaiType}, but this server has no oauth2 credentials configured for that type.`, + ); + return res.status(500).json({ + success: false, + description: `A fatal error has occured, This has been reported.`, + }); + } + + const { CLIENT_SECRET, CLIENT_ID, REDIRECT_URI } = maybeCredentials; + + const url = `${baseUrl}/oauth/token`; + + const params = new URLSearchParams(); + + params.append("code", body.code); + params.append("grant_type", "authorization_code"); + params.append("client_secret", CLIENT_SECRET); + params.append("client_id", CLIENT_ID); + params.append("redirect_uri", REDIRECT_URI); + + log.info(`Making token reify request from ${baseUrl}/oauth/token`); + let getTokenRes; + + try { + getTokenRes = await fetch(url, { + body: params.toString(), + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + method: "POST", + }); + } catch (err) { + log.error(err, `Completely failed to getTokenRes from ${url}.`); + return res.status(500).json({ + success: false, + description: `We failed to reach this site. Are they down?`, + }); + } + + if (getTokenRes.status !== 200) { + log.error(`Unexpected status of ${getTokenRes.status} from ${url} oauth2 flow.`); + + return res.status(getTokenRes.status < 500 ? 400 : 500).json({ + success: false, + description: `The server you requested returned a status of ${getTokenRes.status}. Either your request was malformed, or the server is malfunctioning.`, + }); + } + + let json: unknown; + + try { + json = await getTokenRes.json(); + } catch (err) { + log.error( + { + res: getTokenRes, + err, + }, + `Error parsing JSON in response body from getTokenRes.`, + ); + + return res.status(500).json({ + success: false, + description: `Failed to parse JSON returned from this service. Is their server malfunctioning?`, + }); + } + + const err = p(json, KAI_OAUTH2_RETURN_SCHEMA, {}, { allowExcessKeys: true }); + + if (err) { + log.error({ err }, `Validation error in JSON return from ${url}.`); + return res.status(500).json({ + success: false, + description: `Failed to validate JSON returned from this service. Is their server malfunctioning?`, + }); + } + + const j = json as { access_token: string; refresh_token: string }; + + await db["kai-auth-tokens"].update( + { + userID: user.id, + service: kaiType, + }, + { + $set: { + userID: user.id, + service: kaiType, + refreshToken: j.refresh_token, + token: j.access_token, + }, + }, + { + upsert: true, + }, + ); + + log.info(`Updated Auth for ${kaiType} for user ${FormatUserDoc(user)}.`); + + return res.status(200).json({ + success: true, + description: `Successfully updated auth for ${kaiType}`, + body: {}, + }); + }, +); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/kshook-sv6c/router.test.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/kshook-sv6c/router.test.ts new file mode 100644 index 000000000..a09d5aa4c --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/kshook-sv6c/router.test.ts @@ -0,0 +1,111 @@ +import type { UserDocument } from "tachi-common"; + +import db from "#services/mongo/db"; +import { CreateFakeAuthCookie } from "#test-utils/fake-auth"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import t from "tap"; + +t.test("GET /api/v1/users/:userID/integrations/kshook-sv6c/settings", async (t) => { + t.beforeEach(ResetDBState); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should return null if this user has no settings set.", async (t) => { + await db["kshook-sv6c-settings"].remove({}); + + const res = await mockApi + .get("/api/v1/users/1/integrations/kshook-sv6c/settings") + .set("Cookie", cookie); + + t.equal(res.statusCode, 200); + + t.equal(res.body.body, null); + + t.end(); + }); + + t.test("Should return this users settings if they have them.", async (t) => { + const res = await mockApi + .get("/api/v1/users/1/integrations/kshook-sv6c/settings") + .set("Cookie", cookie); + + t.equal(res.statusCode, 200); + + t.strictSame(res.body.body, { + userID: 1, + forceStaticImport: true, + }); + + t.end(); + }); + + t.test("Must require self-key level authentication.", async (t) => { + const res = await mockApi.get("/api/v1/users/1/integrations/kshook-sv6c/settings"); + + t.equal(res.statusCode, 401); + + const res2 = await mockApi + .get("/api/v1/users/1/integrations/kshook-sv6c/settings") + .set("Authorization", "Bearer fake_api_token"); + + t.equal(res2.statusCode, 403); + + // insert a fake user doc so this doesn't 404 + await db.users.insert({ + id: 2, + username: "foo", + usernameLowercase: "foo", + } as UserDocument); + + const res3 = await mockApi + .get("/api/v1/users/2/integrations/kshook-sv6c/settings") + .set("Cookie", cookie); + + t.equal(res3.statusCode, 403); + + t.end(); + }); + + t.end(); +}); + +t.test("PATCH /api/v1/users/:userID/integrations/kshook-sv6c/settings", async (t) => { + t.beforeEach(ResetDBState); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should update a users settings.", async (t) => { + const res = await mockApi + .patch("/api/v1/users/1/integrations/kshook-sv6c/settings") + .send({ forceStaticImport: true }) + .set("Cookie", cookie); + + t.strictSame(res.body.body.forceStaticImport, true); + + const dbRes = await db["kshook-sv6c-settings"].findOne({ userID: 1 }); + + t.strictSame(dbRes?.forceStaticImport, true); + + t.end(); + }); + + t.test("Should insert a setting filter document if one doesn't exist.", async (t) => { + await db["kshook-sv6c-settings"].remove({}); + + const res = await mockApi + .patch("/api/v1/users/1/integrations/kshook-sv6c/settings") + .send({ forceStaticImport: true }) + .set("Cookie", cookie); + + t.strictSame(res.body.body.forceStaticImport, true); + + const dbRes = await db["kshook-sv6c-settings"].findOne({ userID: 1 }); + + t.strictSame(dbRes?.forceStaticImport, true); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/kshook-sv6c/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/kshook-sv6c/router.ts new file mode 100644 index 000000000..a73afcb08 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/kshook-sv6c/router.ts @@ -0,0 +1,68 @@ +import prValidate from "#server/middleware/prudence-validate"; +import { RequireKamaitachi } from "#server/middleware/type-require"; +import db from "#services/mongo/db"; +import { GetTachiData } from "#utils/req-tachi-data"; +import { Router } from "express"; + +import { RequireSelfRequestFromUser } from "../../middleware"; + +const router: Router = Router({ mergeParams: true }); + +router.use(RequireKamaitachi); +router.use(RequireSelfRequestFromUser); + +/** + * Retrieve your KsHook SV6C settings. + * + * @name GET /api/v1/users/:userID/integrations/kshook-sv6c/settings + */ +router.get("/settings", async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + + const settingsDoc = await db["kshook-sv6c-settings"].findOne({ + userID: user.id, + }); + + return res.status(200).json({ + success: true, + description: `Retrieved KsHook (S6VC) settings.`, + body: settingsDoc ?? null, + }); +}); + +/** + * Update your KsHook SV6C configuration. + * + * @param forceStaticImport - Whether or whether not to statically import data. + * + * @name PUT /api/v1/users/:userID/integrations/kshook-sv6c/settings + */ +router.patch("/settings", prValidate({ forceStaticImport: "boolean" }), async (req, res) => { + const body = req.safeBody as { + forceStaticImport: boolean; + }; + + const user = GetTachiData(req, "requestedUser"); + + await db["kshook-sv6c-settings"].update( + { userID: user.id }, + { + $set: { + forceStaticImport: body.forceStaticImport, + }, + }, + { + upsert: true, + }, + ); + + const settings = await db["kshook-sv6c-settings"].findOne({ userID: user.id }); + + return res.status(200).json({ + success: true, + description: `Successfully updated settings.`, + body: settings, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/myt/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/myt/router.ts new file mode 100644 index 000000000..b4365f73a --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/myt/router.ts @@ -0,0 +1,99 @@ +import type { MytCardInfo } from "tachi-common"; + +import prValidate from "#server/middleware/prudence-validate"; +import { RequireKamaitachi } from "#server/middleware/type-require"; +import db from "#services/mongo/db"; +import { GetTachiData } from "#utils/req-tachi-data"; +import { Router } from "express"; +import { p } from "prudence"; + +import { RequireSelfRequestFromUser } from "../../middleware"; + +const router: Router = Router({ mergeParams: true }); + +router.use(RequireKamaitachi); +router.use(RequireSelfRequestFromUser); + +/** + * Retrieve this user's card info (cardAccessCode). + * + * @name GET /api/v1/users/:userID/integrations/myt + */ +router.get("/", async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + + const cardInfo = await db["myt-card-info"].findOne({ + userID: user.id, + }); + + if (!cardInfo) { + return res.status(200).json({ + success: true, + description: `User has no card info set.`, + body: null, + }); + } + + return res.status(200).json({ + success: true, + description: `Found card info.`, + body: cardInfo, + }); +}); + +/** + * Write new card details for Myt. + * + * @name PUT /api/v1/users/:userID/integrations/myt + */ +router.put( + "/", + prValidate( + { cardAccessCode: p.regex(/^[0-9]{20}$/u) }, + { cardAccessCode: "Expected 20 digits." }, + ), + async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + + const { cardAccessCode } = req.safeBody as { cardAccessCode: string }; + + const newCardInfo: MytCardInfo = { + userID: user.id, + cardAccessCode, + }; + + await db["myt-card-info"].update( + { userID: user.id }, + { $set: newCardInfo }, + { + // insert new card info if the user doesn't have it yet. + upsert: true, + }, + ); + + return res.status(200).json({ + success: true, + description: `Updated cardAccessCode.`, + body: {}, + }); + }, +); + +/** + * Unset this user's card details for Myt. + * + * @name DELETE /api/v1/users/:userID/integrations/myt + */ +router.delete("/", async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + + await db["cg-card-info"].remove({ userID: user.id }); + + return res.status(200).json({ + success: true, + description: `Deleted stored card info.`, + body: {}, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/router.ts new file mode 100644 index 000000000..a15fca56d --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/integrations/router.ts @@ -0,0 +1,17 @@ +import { Router } from "express"; + +import cgCgTypeRouter from "./cg/_cgType/router"; +import fervidexRouter from "./fervidex/router"; +import kaiKaiTypeRouter from "./kai/_kaiType/router"; +import ksHookSV6CRouter from "./kshook-sv6c/router"; +import mytRouter from "./myt/router"; + +const router: Router = Router({ mergeParams: true }); + +router.use("/cg/:cgType", cgCgTypeRouter); +router.use("/myt", mytRouter); +router.use("/kai/:kaiType", kaiKaiTypeRouter); +router.use("/fervidex", fervidexRouter); +router.use("/kshook-sv6c", ksHookSV6CRouter); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/invites/router.test.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/invites/router.test.ts new file mode 100644 index 000000000..671a27cf2 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/invites/router.test.ts @@ -0,0 +1,163 @@ +import { ONE_MONTH } from "#lib/constants/time"; +import db from "#services/mongo/db"; +import { CreateFakeAuthCookie } from "#test-utils/fake-auth"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { type InviteCodeDocument, UserAuthLevels, type UserDocument } from "tachi-common"; +import t from "tap"; + +t.test("GET /api/v1/users/:userID/invites", async (t) => { + t.beforeEach(ResetDBState); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should return all of this users created invites and who used them.", async (t) => { + await db.users.insert({ + id: 2, + username: "other_dude", + usernameLowercase: "other_dude", + } as UserDocument); + + const res = await mockApi.get("/api/v1/users/1/invites").set("Cookie", cookie); + + t.strictSame( + (res.body.body.invites as Array).sort( + (a, b) => a.createdAt - b.createdAt, + ), + [ + { + code: "example_invite", + createdBy: 1, + createdAt: 0, + consumed: false, + consumedBy: null, + consumedAt: null, + }, + { + code: "example_consumed_invite", + createdBy: 1, + createdAt: 1, + consumed: true, + consumedBy: 2, + consumedAt: 123, + }, + ], + ); + + t.strictSame(res.body.body.consumers, [ + { + id: 2, + username: "other_dude", + usernameLowercase: "other_dude", + }, + ]); + + t.end(); + }); + + t.test("Should require self-key level authentication.", async (t) => { + const res = await mockApi.get("/api/v1/users/1/invites"); + + t.equal(res.statusCode, 401); + + const res2 = await mockApi + .get("/api/v1/users/1/invites") + .set("Authorization", "Bearer fake_api_token"); + + t.equal(res2.statusCode, 403); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/users/:userID/invites/limit", async (t) => { + t.beforeEach(ResetDBState); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should return this users current limit on invites.", async (t) => { + // because this thing is time-based, we need to make sure + // this is always relative to right now. + + await db.users.update({ id: 1 }, { $set: { joinDate: Date.now() - ONE_MONTH * 2.5 } }); + const res = await mockApi.get("/api/v1/users/1/invites/limit").set("Cookie", cookie); + + t.equal(res.body.body.invites, 2); + t.equal(res.body.body.limit, 4); + + t.end(); + }); + + t.test("Should require self-key level authentication.", async (t) => { + const res = await mockApi.get("/api/v1/users/1/invites/limit"); + + t.equal(res.statusCode, 401); + + const res2 = await mockApi + .get("/api/v1/users/1/invites/limit") + .set("Authorization", "Bearer fake_api_token"); + + t.equal(res2.statusCode, 403); + + t.end(); + }); + + t.end(); +}); + +t.test("POST /api/v1/users/:userID/invites/create", async (t) => { + t.beforeEach(ResetDBState); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should create a new invite.", async (t) => { + await db.users.update({ id: 1 }, { $set: { joinDate: Date.now() - ONE_MONTH * 2.5 } }); + + const res = await mockApi.post("/api/v1/users/1/invites/create").set("Cookie", cookie); + + t.equal(res.statusCode, 200); + + const dbRes = await db.invites.findOne({ + code: res.body.body.code, + }); + + t.not(dbRes, null, "Should exist in the database."); + + t.end(); + }); + + t.test("Should honor invite limit.", async (t) => { + await db.invites.remove({}); + + // users with less than a month of life in them dont get invites, + // so this will force an invite limit honor. + await db.users.update( + { id: 1 }, + { $set: { joinDate: Date.now(), authLevel: UserAuthLevels.USER } }, + ); + + const res = await mockApi.post("/api/v1/users/1/invites/create").set("Cookie", cookie); + + t.equal(res.statusCode, 400); + + t.end(); + }); + + t.test("Should require self-key level authentication.", async (t) => { + const res = await mockApi.post("/api/v1/users/1/invites/create"); + + t.equal(res.statusCode, 401); + + const res2 = await mockApi + .post("/api/v1/users/1/invites/create") + .set("Authorization", "Bearer fake_api_token"); + + t.equal(res2.statusCode, 403); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/invites/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/invites/router.ts new file mode 100644 index 000000000..ee2240b86 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/invites/router.ts @@ -0,0 +1,149 @@ +import { GetTotalAllowedInvites } from "#lib/invites/invites"; +import { RequireInvitesEnabled } from "#server/middleware/type-require"; +import db from "#services/mongo/db"; +import { Random20Hex } from "#utils/misc"; +import { GetTachiData } from "#utils/req-tachi-data"; +import { GetUsersWithIDs } from "#utils/user"; +import { Router } from "express"; +import { type InviteCodeDocument, UserAuthLevels } from "tachi-common"; + +import { RequireSelfRequestFromUser } from "../middleware"; + +const router: Router = Router({ mergeParams: true }); + +router.use(RequireInvitesEnabled); +router.use(RequireSelfRequestFromUser); + +/** + * Retrieve all of this users created invites. + * + * @name GET /api/v1/users/:userID/invites + */ +router.get("/", async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + + const invites = await db.invites.find( + { + createdBy: user.id, + }, + { + sort: { + consumedAt: -1, + }, + }, + ); + + const consumers = await GetUsersWithIDs( + invites.map((e) => e.consumedBy).filter((e) => e !== null) as Array, + ); + + return res.status(200).json({ + success: true, + description: `Found ${invites.length} invites.`, + body: { invites, consumers }, + }); +}); + +/** + * Return how many invites this user can create, and how many they + * have already created. + * + * @name GET /api/v1/users/:userID/invites/limit + */ +router.get("/limit", async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + + const invites = await db.invites.count({ createdBy: user.id }); + const limit = GetTotalAllowedInvites(user); + + return res.status(200).json({ + success: true, + description: `Calculated invite limit.`, + body: { + invites, + limit, + }, + }); +}); + +/** + * Create a new invite. + * + * @name POST /api/v1/users/:userID/invites/create + */ +router.post("/create", async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + const userID = user.id; + + try { + const lockExists = await db["invite-locks"].findOne({ + userID, + }); + + if (!lockExists) { + await db["invite-locks"].insert({ + userID, + locked: false, + }); + } + + const isNotLocked = await db["invite-locks"].findOneAndUpdate( + { + userID, + locked: false, + }, + { + $set: { locked: true }, + }, + ); + + // race condition protection + // to avoid users double-creating invites. + if (!isNotLocked) { + return res.status(409).json({ + success: false, + description: `You already have an outgoing invite creation request.`, + }); + } + + const existingInvites = await db.invites.count({ createdBy: user.id }); + + if ( + existingInvites >= GetTotalAllowedInvites(user) && + user.authLevel !== UserAuthLevels.ADMIN + ) { + return res.status(400).json({ + success: false, + description: `You already have your maximum amount of outgoing invites.`, + }); + } + + const inviteDoc: InviteCodeDocument = { + code: Random20Hex(), + consumed: false, + consumedAt: null, + consumedBy: null, + createdAt: Date.now(), + createdBy: user.id, + }; + + await db.invites.insert(inviteDoc); + + return res.status(200).json({ + success: true, + description: `Created Invite.`, + body: inviteDoc, + }); + } finally { + await db["invite-locks"].findOneAndUpdate( + { + userID, + }, + { + $set: { locked: false }, + }, + ); + } +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/middleware.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/middleware.ts new file mode 100644 index 000000000..8e87f14b2 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/middleware.ts @@ -0,0 +1,118 @@ +import type { RequestHandler } from "express"; + +import { SYMBOL_TACHI_API_AUTH } from "#lib/constants/tachi"; +import { log } from "#lib/log/log.js"; +import { IsNullish } from "#utils/misc"; +import { AssignToReqTachiData, GetTachiData } from "#utils/req-tachi-data"; +import { GetUserWithID, ResolveUser } from "#utils/user"; +import { UserAuthLevels } from "tachi-common"; + +export const GetUserFromParam: RequestHandler = async (req, res, next) => { + if (!req.params.userID) { + return res.status(400).json({ + success: false, + description: "No userID given.", + }); + } + + let userID = req.params.userID; + + if (req.params.userID === "me") { + const authUserID = req[SYMBOL_TACHI_API_AUTH].userID; + + if (authUserID === null) { + return res.status(401).json({ + success: false, + description: "Cannot use 'me' userID with no authentication.", + }); + } + + // fast assign using JWT + if (req.session.tachi?.user) { + AssignToReqTachiData(req, { requestedUser: req.session.tachi.user }); + next(); + return; + } + + userID = authUserID.toString(); + } + + const user = await ResolveUser(userID); + + if (!user) { + return res.status(404).json({ + success: false, + description: `The user ${userID} does not exist.`, + }); + } + + AssignToReqTachiData(req, { requestedUser: user }); + + next(); +}; + +/** + * Require the user making this request to also be the user in the :userID param. + */ +export const RequireAuthedAsUser: RequestHandler = async (req, res, next) => { + const user = GetTachiData(req, "requestedUser"); + + const requestingUserID = req[SYMBOL_TACHI_API_AUTH].userID; + + if (requestingUserID === null) { + return res.status(401).json({ + success: false, + description: `Authentication is required for this endpoint.`, + }); + } + + const requestingUser = await GetUserWithID(requestingUserID); + + if (!requestingUser) { + log.error(`${requestingUserID} is signed in as someone who does not exist.`); + return res.status(500).json({ + success: false, + description: `You are signed in as someone who does not exist.`, + }); + } + + // admins can do whatever. + if (requestingUser.authLevel === UserAuthLevels.ADMIN) { + next(); + return; + } + + if (requestingUserID !== user.id) { + return res.status(403).json({ + success: false, + description: "You are not authorised as this user.", + }); + } + + next(); +}; + +/** + * Require that this request is made with a Cookie, instead of any + * API key. This is for things that services should not be allowed to + * alter/access, like integration information. + */ +export const RequireSelfRequestFromUser: RequestHandler = (req, res, next) => { + const user = GetTachiData(req, "requestedUser"); + + if (req[SYMBOL_TACHI_API_AUTH].userID === null) { + return res.status(401).json({ + success: false, + description: `This endpoint requires session-level authentication.`, + }); + } + + if (IsNullish(req.session.tachi?.user.id) || req[SYMBOL_TACHI_API_AUTH].userID !== user.id) { + return res.status(403).json({ + success: false, + description: `This request cannot be performed by an API key, and requires authentication.`, + }); + } + + next(); +}; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/notifications/router.test.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/notifications/router.test.ts new file mode 100644 index 000000000..d7de7d3f5 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/notifications/router.test.ts @@ -0,0 +1,197 @@ +import type { NotificationDocument } from "tachi-common"; + +import db from "#services/mongo/db"; +import { CreateFakeAuthCookie } from "#test-utils/fake-auth"; +import { mkFakeNotification, mkFakeUser } from "#test-utils/misc"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import t from "tap"; + +t.test("GET /api/v1/users/:userID/notifications", async (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(() => + Promise.all([ + db.notifications.insert([ + mkFakeNotification({ notifID: "read", read: true, sentAt: 2 }), + mkFakeNotification({ notifID: "unread", read: false, sentAt: 3 }), + mkFakeNotification({ notifID: "not_ours", sentTo: 2, sentAt: 4 }), + ]), + db.users.insert(mkFakeUser(2)), + ]), + ); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should return all of this user's notifications, read or unread.", async (t) => { + const res = await mockApi.get("/api/v1/users/1/notifications").set("Cookie", cookie); + + t.equal(res.statusCode, 200, "Should return 200"); + + t.strictSame( + res.body.body.map((e: NotificationDocument) => e.notifID), + ["unread", "read"], + "Should return the exact notifications we expected (in most-recent order), and no more.", + ); + + t.end(); + }); + + t.test("Should return 401 if not authenticated.", async (t) => { + const res = await mockApi.get("/api/v1/users/1/notifications"); + + t.equal(res.statusCode, 401); + + t.end(); + }); + + t.test("Should return 403 if authed as someone else.", async (t) => { + const res = await mockApi.get("/api/v1/users/2/notifications").set("Cookie", cookie); + + t.equal(res.statusCode, 403); + + t.end(); + }); + + t.test("Should return 403 if authed as right user without self-key", async (t) => { + const res = await mockApi + .get("/api/v1/users/1/notifications") + .set("Authorization", "Bearer fake_api_token"); + + t.equal(res.statusCode, 403); + + t.end(); + }); + + t.end(); +}); + +t.test("POST /api/v1/users/:userID/notifications/delete-all", async (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(() => + Promise.all([ + db.notifications.insert([ + mkFakeNotification({ notifID: "read", read: true, sentAt: 2 }), + mkFakeNotification({ notifID: "unread", read: false, sentAt: 3 }), + mkFakeNotification({ notifID: "unread_2", read: false, sentAt: 4 }), + mkFakeNotification({ notifID: "not_ours", sentTo: 2, sentAt: 5 }), + ]), + db.users.insert(mkFakeUser(2)), + ]), + ); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should mark all of a user's notifications as read.", async (t) => { + const res = await mockApi + .post("/api/v1/users/1/notifications/mark-all-read") + .set("Cookie", cookie); + + t.equal(res.statusCode, 200, "Should return 200."); + + t.strictSame(res.body.body, {}, "Should have no response body."); + + const dbRes = await db.notifications.findOne({ + sentTo: 1, + read: false, + }); + + t.equal(dbRes, null, "Should not find any unread messages in the users inbox."); + + t.end(); + }); + + t.test("Should return 401 if not authenticated.", async (t) => { + const res = await mockApi.post("/api/v1/users/1/notifications/mark-all-read"); + + t.equal(res.statusCode, 401); + + t.end(); + }); + + t.test("Should return 403 if authed as someone else.", async (t) => { + const res = await mockApi + .post("/api/v1/users/2/notifications/mark-all-read") + .set("Cookie", cookie); + + t.equal(res.statusCode, 403); + + t.end(); + }); + + t.test("Should return 403 if authed as right user without self-key", async (t) => { + const res = await mockApi + .post("/api/v1/users/1/notifications/mark-all-read") + .set("Authorization", "Bearer fake_api_token"); + + t.equal(res.statusCode, 403); + + t.end(); + }); + + t.end(); +}); + +t.test("POST /api/v1/users/:userID/notifications/delete-all", async (t) => { + t.beforeEach(ResetDBState); + t.beforeEach(() => + Promise.all([ + db.notifications.insert([ + mkFakeNotification({ notifID: "read", read: true, sentAt: 2 }), + mkFakeNotification({ notifID: "unread", read: false, sentAt: 3 }), + mkFakeNotification({ notifID: "unread_2", read: false, sentAt: 4 }), + mkFakeNotification({ notifID: "not_ours", sentTo: 2, sentAt: 5 }), + ]), + db.users.insert(mkFakeUser(2)), + ]), + ); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should empty a user's notification inbox.", async (t) => { + const res = await mockApi + .post("/api/v1/users/1/notifications/delete-all") + .set("Cookie", cookie); + + t.equal(res.statusCode, 200, "Should return 200."); + + t.strictSame(res.body.body, {}, "Should have no response body."); + + const dbRes = await db.notifications.findOne({ + sentTo: 1, + }); + + t.equal(dbRes, null, "Should not find any messages in the users inbox."); + + t.end(); + }); + + t.test("Should return 401 if not authenticated.", async (t) => { + const res = await mockApi.post("/api/v1/users/1/notifications/delete-all"); + + t.equal(res.statusCode, 401); + + t.end(); + }); + + t.test("Should return 403 if authed as someone else.", async (t) => { + const res = await mockApi + .post("/api/v1/users/2/notifications/delete-all") + .set("Cookie", cookie); + + t.equal(res.statusCode, 403); + + t.end(); + }); + + t.test("Should return 403 if authed as right user without self-key", async (t) => { + const res = await mockApi + .post("/api/v1/users/1/notifications/delete-all") + .set("Authorization", "Bearer fake_api_token"); + + t.equal(res.statusCode, 403); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/notifications/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/notifications/router.ts new file mode 100644 index 000000000..b18a13898 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/notifications/router.ts @@ -0,0 +1,99 @@ +import { ONE_SECOND } from "#lib/constants/time"; +import db from "#services/mongo/db"; +import { GetTachiData } from "#utils/req-tachi-data"; +import { Router } from "express"; + +import { RequireSelfRequestFromUser } from "../middleware"; + +const router: Router = Router({ mergeParams: true }); + +// Notifications aren't really for anyone else to interact with. Only the requesting user +// should be able to see their notifications. +router.use(RequireSelfRequestFromUser); + +/** + * Return all of this user's notifications, this is sorted on most recently sent first. + * + * @name GET /api/v1/users/:userID/notifications + */ +router.get("/", async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + + const notifs = await db.notifications.find( + { + sentTo: user.id, + }, + { + sort: { + sentAt: -1, + }, + }, + ); + + return res.status(200).json({ + success: true, + description: `Found ${notifs.length} notifications.`, + body: notifs, + }); +}); + +/** + * Mark all notifications in this user's inbox as read. + * + * @name POST /api/v1/users/:userID/notifications/mark-all-read + */ +router.post("/mark-all-read", async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + + const updateRes = await db.notifications.update( + { + sentTo: user.id, + + // insanely rare edge case, but if someone submits an empty-my-inbox + // request, and then gets a notif at the same time, they run the risk of + // emptying something so immediately they don't actually ever see it. + // This hack mitigates that, slightly. + sentAt: { + $lt: Date.now() - ONE_SECOND * 2, + }, + }, + { + $set: { read: true }, + }, + { + multi: true, + }, + ); + + return res.status(200).json({ + success: true, + description: `Marked ${updateRes.n} notifications as read.`, + body: {}, + }); +}); + +/** + * Clear all notifications from your inbox. + * + * @name POST /api/v1/users/:userID/notifications/delete-all + */ +router.post("/delete-all", async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + + const deleted = await db.notifications.remove({ + sentTo: user.id, + + // See mark-all-read for an explanation of this behaviour. + sentAt: { + $lt: Date.now() - ONE_SECOND * 2, + }, + }); + + return res.status(200).json({ + success: true, + description: `Deleted ${deleted.deletedCount ?? 0} notification(s).`, + body: {}, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/pfp/router.test.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/pfp/router.test.ts new file mode 100644 index 000000000..dbea92d20 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/pfp/router.test.ts @@ -0,0 +1,87 @@ +import { CDNStoreOrOverwrite } from "#lib/cdn/cdn"; +import { GetProfilePictureURL } from "#lib/cdn/url-format"; +import db from "#services/mongo/db"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { GetKTDataBuffer } from "#test-utils/test-data"; +import t from "tap"; + +t.test("GET /api/v1/users/:userID/pfp", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return the default profile picture if user has no custom pfp", async (t) => { + await CDNStoreOrOverwrite("/users/default/pfp", "test"); + + // we have to follow redirs here lol + const res = await mockApi.get("/api/v1/users/1/pfp").redirects(1); + + t.equal(res.body.toString(), "test"); + + t.end(); + }); + + t.test("Should work with a .png extension", async (t) => { + await CDNStoreOrOverwrite("/users/default/pfp", "test"); + + // we have to follow redirs here lol + const res = await mockApi.get("/api/v1/users/1/pfp.png").redirects(2); + + t.equal(res.body.toString(), "test"); + + t.end(); + }); + + t.test("Should return a custom profile picture if one is set", async (t) => { + await CDNStoreOrOverwrite(GetProfilePictureURL(1, "checksum"), "foo"); + await db.users.update({ id: 1 }, { $set: { customPfpLocation: "checksum" } }); + const res = await mockApi.get("/api/v1/users/1/pfp").redirects(1); + + t.equal(res.body.toString(), "foo"); + + t.end(); + }); + + t.end(); +}); + +t.test("PUT /api/v1/users/:userID/pfp", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should set a profile picture if user has no custom pfp", async (t) => { + const img = GetKTDataBuffer("/images/acorn.png"); + + const res = await mockApi + .put("/api/v1/users/1/pfp") + .set("Authorization", "Bearer fake_api_token") + .attach("pfp", img, "file.jpg"); + + t.equal(res.statusCode, 200); + + const get = await mockApi.get(res.body.body.get).redirects(1); + + t.strictSame(img, get.body, "Profile picture should be stored."); + + t.end(); + }); + + t.test("Should set a profile picture if user has custom pfp", async (t) => { + await db.users.update({ id: 1 }, { $set: { customPfpLocation: "checksum" } }); + + const img = GetKTDataBuffer("/images/acorn.png"); + + const res = await mockApi + .put("/api/v1/users/1/pfp") + .set("Authorization", "Bearer fake_api_token") + .attach("pfp", img, "file.png"); + + t.equal(res.statusCode, 200); + + const get = await mockApi.get(res.body.body.get).redirects(1); + + t.strictSame(img, get.body, "Profile picture should be stored."); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/pfp/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/pfp/router.ts new file mode 100644 index 000000000..cb891a368 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/pfp/router.ts @@ -0,0 +1,134 @@ +import { CDNDelete, CDNRedirect, CDNStoreOrOverwrite } from "#lib/cdn/cdn"; +import { GetProfilePictureURL } from "#lib/cdn/url-format"; +import { ONE_MEGABYTE } from "#lib/constants/filesize"; +import { log } from "#lib/log/log.js"; +import { RequirePermissions } from "#server/middleware/auth"; +import { CreateMulterSingleUploadMiddleware } from "#server/middleware/multer-upload"; +import db from "#services/mongo/db"; +import { HashSHA256 } from "#utils/crypto"; +import { GetTachiData } from "#utils/req-tachi-data"; +import { FormatUserDoc } from "#utils/user"; +import { Router } from "express"; + +import { RequireAuthedAsUser } from "../middleware"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Sets a profile picture. + * + * @param pfp - A JPG, PNG or GIF file less than 1mb. + * @note although GIFs are supported, this functionality isn't documented on the site. + * this is kind of an easter egg. + * + * @name PUT /api/v1/users/:userID/pfp + */ +router.put( + "/", + RequireAuthedAsUser, + RequirePermissions("customise_profile"), + CreateMulterSingleUploadMiddleware("pfp", ONE_MEGABYTE), + async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + + if (!user.customPfpLocation) { + log.debug(`User ${FormatUserDoc(user)} set a custom profile picture.`); + } else { + log.debug(`User ${FormatUserDoc(user)} updated their profile picture.`); + } + + if (!req.file) { + log.error( + `Conflicting state - no req.file has been populated but passed middleware? (${FormatUserDoc( + user, + )})`, + ); + return res.status(500).json({ + success: false, + description: `An internal error has occured.`, + }); + } + + const contentHash = HashSHA256(req.file.buffer); + + if ( + req.file.mimetype === "image/jpeg" || + req.file.mimetype === "image/png" || + req.file.mimetype === "image/gif" + ) { + await CDNStoreOrOverwrite(GetProfilePictureURL(user.id, contentHash), req.file.buffer); + } else { + return res.status(400).json({ + success: false, + description: `Invalid file - only JPG and PNG files are supported.`, + }); + } + + if (req.session.tachi?.user) { + req.session.tachi.user.customPfpLocation = contentHash; + } + + await db.users.update({ id: user.id }, { $set: { customPfpLocation: contentHash } }); + + return res.status(200).json({ + success: true, + description: `Stored profile picture.`, + body: { + get: req.originalUrl, + }, + }); + }, +); + +/** + * Returns this user's profile picture. If the user does not have a custom profile picture, + * return the default profile picture. + * + * @name GET /api/v1/users/:userID/pfp + */ +router.get("/", (req, res) => { + const user = GetTachiData(req, "requestedUser"); + + log.debug(user, "User Info for /:userID/pfp request is "); + + if (!user.customPfpLocation) { + res.setHeader("Content-Type", "image/png"); + CDNRedirect(res, "/users/default/pfp"); + return; + } + + CDNRedirect(res, GetProfilePictureURL(user.id, user.customPfpLocation)); +}); + +/** + * Deletes this user's profile picture, and go back to the default profile picture. + * + * @name DELETE /api/v1/users/:userID/pfp + */ +router.delete( + "/", + RequireAuthedAsUser, + RequirePermissions("customise_profile"), + async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + + if (!user.customPfpLocation) { + return res.status(404).json({ + success: false, + description: `You do not have a custom profile picture to delete.`, + }); + } + + await CDNDelete(GetProfilePictureURL(user.id, user.customPfpLocation)); + + await db.users.update({ id: user.id }, { $set: { customPfpLocation: null } }); + + return res.status(200).json({ + success: true, + description: `Removed custom profile picture.`, + body: {}, + }); + }, +); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/router.test.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/router.test.ts new file mode 100644 index 000000000..dbb15833e --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/router.test.ts @@ -0,0 +1,481 @@ +import type { GameGroup, ImportDocument, ImportTypes, UserGameStats } from "tachi-common"; + +import { ONE_DAY, ONE_YEAR } from "#lib/constants/time"; +import db from "#services/mongo/db"; +import { CreateFakeAuthCookie } from "#test-utils/fake-auth"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import { Random20Hex } from "#utils/misc"; +import t from "tap"; + +import { PasswordCompare } from "../../auth/auth"; + +t.test("GET /api/v1/users/:userID", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should retrieve a user on their ID.", async (t) => { + const res = await mockApi.get("/api/v1/users/1"); + + t.hasStrict(res.body, { + success: true, + description: "Found user test_zkldi.", + body: { + id: 1, + username: "test_zkldi", + }, + }); + + t.end(); + }); + + t.test("Should retrieve a user on their name.", async (t) => { + const res = await mockApi.get("/api/v1/users/test_zkldi"); + + t.hasStrict(res.body, { + success: true, + description: "Found user test_zkldi.", + body: { + id: 1, + username: "test_zkldi", + }, + }); + + t.end(); + }); + + t.test("Should retrieve a user on their name case insensitively.", async (t) => { + const res = await mockApi.get("/api/v1/users/TeSt_ZklDI"); + + t.hasStrict(res.body, { + success: true, + description: "Found user test_zkldi.", + body: { + id: 1, + username: "test_zkldi", + }, + }); + + t.end(); + }); + + t.test("Should return 404 on users that don't exist.", async (t) => { + const res = await mockApi.get("/api/v1/users/someguy"); + + t.hasStrict(res.body, { + success: false, + description: "The user someguy does not exist.", + }); + + t.equal(res.statusCode, 404); + + t.end(); + }); + + t.end(); +}); + +t.test("PATCH /api/v1/users/:userID", async (t) => { + t.beforeEach(ResetDBState); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should require authentication", async (t) => { + const res = await mockApi.patch("/api/v1/users/1"); + + t.equal(res.statusCode, 401); + + // needs self key auth + await db["api-tokens"].insert({ + token: "noperm", + permissions: {}, + identifier: "No permissions token", + userID: 1, + fromAPIClient: null, + }); + + const res2 = await mockApi.patch("/api/v1/users/1").set("Authorization", "Bearer noperm"); + + t.equal(res2.statusCode, 403); + + t.end(); + }); + + t.test("Should reject empty updates.", async (t) => { + const res = await mockApi.patch("/api/v1/users/1").set("Cookie", cookie); + + t.equal(res.statusCode, 400); + + t.end(); + }); + + t.test("Should update the user doc.", async (t) => { + const res = await mockApi.patch("/api/v1/users/1").set("Cookie", cookie).send({ + status: "Hello World!", + }); + + t.equal(res.body.body.status, "Hello World!"); + + const dbUser = await db.users.findOne({ id: 1 }); + + t.equal(dbUser?.status, "Hello World!"); + + t.end(); + }); + + t.test("Should allow empty strings for about me.", async (t) => { + const res = await mockApi.patch("/api/v1/users/1").set("Cookie", cookie).send({ + about: "", + }); + + t.equal(res.statusCode, 200); + + const dbUser = await db.users.findOne({ id: 1 }); + + t.equal(dbUser?.about, ""); + + t.end(); + }); + + t.test("Shouldn't allow about me to be set to null.", async (t) => { + const res = await mockApi.patch("/api/v1/users/1").set("Cookie", cookie).send({ + about: null, + }); + + t.equal(res.statusCode, 400); + + const dbUser = await db.users.findOne({ id: 1 }); + + t.equal(dbUser?.about, "test_user_not_real"); + + t.end(); + }); + + t.test("Shouldn't alter other properties.", async (t) => { + await db.users.update({ id: 1 }, { $set: { "socialMedia.discord": "foo#123" } }); + + const res = await mockApi.patch("/api/v1/users/1").set("Cookie", cookie).send({ + status: "Hello World!", + }); + + t.equal(res.body.body.status, "Hello World!"); + + const dbUser = await db.users.findOne({ id: 1 }); + + t.equal(dbUser?.status, "Hello World!"); + t.equal(dbUser?.about, "test_user_not_real"); + t.equal(dbUser?.socialMedia.discord, "foo#123"); + + t.end(); + }); + + t.test("Should correctly strip twitter urls.", async (t) => { + const res = await mockApi.patch("/api/v1/users/1").set("Cookie", cookie).send({ + twitter: "https://twitter.com/zkldi", + }); + + t.equal(res.body.body.socialMedia.twitter, "zkldi"); + + const dbUser = await db.users.findOne({ id: 1 }); + + t.equal(dbUser?.socialMedia.twitter, "zkldi"); + + t.end(); + }); + + t.test("Should correctly strip youtube urls.", async (t) => { + const res = await mockApi.patch("/api/v1/users/1").set("Cookie", cookie).send({ + youtube: "https://youtube.com/user/zkldi", + }); + + t.equal(res.body.body.socialMedia.youtube, "zkldi"); + + const dbUser = await db.users.findOne({ id: 1 }); + + t.equal(dbUser?.socialMedia.youtube, "zkldi"); + + const res2 = await mockApi.patch("/api/v1/users/1").set("Cookie", cookie).send({ + youtube: "https://youtube.com/channel/zkldi", + }); + + t.equal(res2.body.body.socialMedia.youtube, "zkldi"); + + const dbUser2 = await db.users.findOne({ id: 1 }); + + t.equal(dbUser2?.socialMedia.youtube, "zkldi"); + + const res3 = await mockApi.patch("/api/v1/users/1").set("Cookie", cookie).send({ + youtube: "https://youtube.com/@zkldi", + }); + + t.equal(res3.body.body.socialMedia.youtube, "zkldi"); + + const dbUser3 = await db.users.findOne({ id: 1 }); + + t.equal(dbUser3?.socialMedia.youtube, "zkldi"); + + t.end(); + }); + + t.test("Should correctly strip github urls.", async (t) => { + const res = await mockApi.patch("/api/v1/users/1").set("Cookie", cookie).send({ + github: "https://github.com/zkldi", + }); + + t.equal(res.body.body.socialMedia.github, "zkldi"); + + const dbUser = await db.users.findOne({ id: 1 }); + + t.equal(dbUser?.socialMedia.github, "zkldi"); + + t.end(); + }); + + t.test("Should correctly strip twitch urls.", async (t) => { + const res = await mockApi.patch("/api/v1/users/1").set("Cookie", cookie).send({ + twitch: "https://twitch.tv/zkldi", + }); + + t.equal(res.body.body.socialMedia.twitch, "zkldi"); + + const dbUser = await db.users.findOne({ id: 1 }); + + t.equal(dbUser?.socialMedia.twitch, "zkldi"); + + t.end(); + }); + + t.test("Should correctly strip steam urls.", async (t) => { + const res = await mockApi.patch("/api/v1/users/1").set("Cookie", cookie).send({ + steam: "https://steamcommunity.com/id/zkldi", + }); + + t.equal(res.body.body.socialMedia.steam, "zkldi"); + + const dbUser = await db.users.findOne({ id: 1 }); + + t.equal(dbUser?.socialMedia.steam, "zkldi"); + + t.end(); + }); + + t.end(); +}); + +t.test("POST /api/v1/users/:userID/change-password", async (t) => { + t.beforeEach(ResetDBState); + const cookie = await CreateFakeAuthCookie(mockApi); + + function send(content: Record) { + return mockApi.post("/api/v1/users/1/change-password").set("Cookie", cookie).send(content); + } + + t.test("Must require !password and !oldPassword to be a valid password.", async (t) => { + const res = await send({ + "!password": null, + "!oldPassword": "heres_my_old_password", + }); + + t.equal(res.statusCode, 400); + t.match( + res.body.description, + /!password/gu, + "Should be related to the invalid password field.", + ); + + const res2 = await send({ + "!password": "heres_my_new_password", + "!oldPassword": "short", + }); + + t.equal(res2.statusCode, 400); + t.match( + res2.body.description, + /!oldPassword/gu, + "Should be related to the invalid !oldPassword field.", + ); + + t.end(); + }); + + t.test("Must require !oldPassword to match.", async (t) => { + const res = await send({ + "!password": "new_password", + "!oldPassword": "NOT_MY_PASSWORD", + }); + + t.equal(res.statusCode, 401); + t.match(res.body.description, /old password doesn't match/iu); + + t.end(); + }); + + t.test("Should update password if everything checks out.", async (t) => { + const res = await send({ + "!password": "NEW_PASSWORD", + "!oldPassword": "password", + }); + + t.equal(res.statusCode, 200); + + const newPrivateInfo = await db["user-private-information"].findOne({ + userID: 1, + }); + + t.not(newPrivateInfo, null, "newPrivateInfo should not be null."); + + t.ok( + PasswordCompare("NEW_PASSWORD", newPrivateInfo!.password), + "Should update the users password to the hash of NEW_PASSWORD.", + ); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/users/:userID/game-stats", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return all of a user's game stats.", async (t) => { + await db["game-stats"].remove({}); + + const stats: Array = [ + { + userID: 1, + game: "iidx", + playtype: "SP", + classes: {}, + ratings: { + ktLampRating: 12, + }, + }, + { + userID: 1, + game: "iidx", + playtype: "DP", + classes: {}, + ratings: { + ktLampRating: 11, + }, + }, + { + userID: 1, + game: "gitadora", + playtype: "Dora", + classes: {}, + ratings: { + naiveSkill: 4843, + }, + }, + ]; + + await db["game-stats"].insert(stats); + + const res = await mockApi.get("/api/v1/users/test_zkldi/game-stats"); + + t.hasStrict(res.body, { + success: true, + description: "Returned 3 stats objects.", + }); + + const returns = res.body.body.map((e: UserGameStats) => `${e.game}-${e.playtype}`); + + // amusing small hacks + t.equal(returns.length, 3); + t.ok(returns.includes("iidx-SP")); + t.ok(returns.includes("iidx-DP")); + t.ok(returns.includes("gitadora-Dora")); + + t.end(); + }); + + t.end(); +}); + +t.test("GET /api/v1/users/:userID/recent-imports", (t) => { + t.beforeEach(ResetDBState); + + function mkImport( + game: GameGroup, + importType: ImportTypes, + timeFinished: number, + userIntent: boolean, + ): ImportDocument { + return { + classDeltas: [], + createdSessions: [], + errors: [], + game, + importType, + importID: Random20Hex(), + goalInfo: [], + gptStrings: [], + questInfo: [], + playtypes: [], + scoreIDs: [], + timeFinished, + timeStarted: 0, + userID: 1, + userIntent, + }; + } + + t.test("Should work cross game and ignore imports without userIntent.", async (t) => { + await db.imports.insert([ + mkImport("iidx", "api/flo-iidx", Date.now() - ONE_DAY, true), + mkImport("iidx", "api/flo-iidx", Date.now() - ONE_DAY, true), + mkImport("sdvx", "api/flo-sdvx", Date.now() - ONE_DAY, false), + mkImport("iidx", "api/flo-iidx", Date.now() - ONE_DAY, false), + mkImport("sdvx", "api/flo-sdvx", Date.now() - ONE_DAY, true), + ]); + + const res = await mockApi.get("/api/v1/users/1/recent-imports"); + + t.equal(res.statusCode, 200); + + t.strictSame(res.body.body, [ + { + importType: "api/flo-iidx", + count: 2, + }, + { + importType: "api/flo-sdvx", + count: 1, + }, + ]); + + t.end(); + }); + + t.test("Should ignore imports that were too long ago.", async (t) => { + await db.imports.insert([ + mkImport("iidx", "api/flo-iidx", Date.now() - ONE_DAY, true), + mkImport("iidx", "ir/fervidex", Date.now() - ONE_YEAR, true), + mkImport("iidx", "ir/fervidex", Date.now() - ONE_YEAR, true), + mkImport("iidx", "ir/fervidex", Date.now() - ONE_YEAR, true), + mkImport("iidx", "ir/fervidex", Date.now() - ONE_YEAR, true), + mkImport("sdvx", "api/flo-sdvx", Date.now() - ONE_DAY, true), + mkImport("sdvx", "api/flo-sdvx", Date.now() - ONE_DAY, true), + ]); + + const res = await mockApi.get("/api/v1/users/1/recent-imports"); + + t.equal(res.statusCode, 200); + + t.strictSame(res.body.body, [ + { + importType: "api/flo-sdvx", + count: 2, + }, + { + importType: "api/flo-iidx", + count: 1, + }, + ]); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/router.ts new file mode 100644 index 000000000..311bdf6d6 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/router.ts @@ -0,0 +1,842 @@ +import type { + AnyProfileRatingAlg, + GPTString, + ImportTypes, + integer, + UserGameStats, +} from "tachi-common"; + +import { GetRecentActivity } from "#lib/activity/activity"; +import { ONE_MONTH } from "#lib/constants/time"; +import { SendEmail } from "#lib/email/client"; +import { EmailFormatVerifyEmail } from "#lib/email/formats"; +import { log } from "#lib/log/log.js"; +import { GetRivalIDs } from "#lib/rivals/rivals"; +import { ServerConfig } from "#lib/setup/config"; +import prValidate from "#server/middleware/prudence-validate"; +import db from "#services/mongo/db"; +import { DeleteUndefinedProps, IsNonEmptyString, Random20Hex, StripUrl } from "#utils/misc"; +import { optNullFluffStrField } from "#utils/prudence"; +import { + GetGoalSummary, + GetRecentlyViewedFoldersAnyGPT, + GetRecentPlaycount, + GetRecentSessions, +} from "#utils/queries/summary"; +import { GetUser } from "#utils/req-tachi-data"; +import { + CanChangeUsername, + CheckIfEmailInUse, + FormatUserDoc, + GetAllRankings, + GetNextAvailableUsernameChange, + GetUserCaseInsensitive, + GetUserWithID, +} from "#utils/user"; +import { Router } from "express"; +import { p } from "prudence"; + +import { HashPassword, PasswordCompare, ValidateEmail, ValidatePassword } from "../../auth/auth"; +import apiTokensRouter from "./api-tokens/router"; +import bannerRouter from "./banner/router"; +import followingRouter from "./following/router"; +import gameSpecificRouter from "./games/@gameSpecificRoutes/router"; +import gamePTRouter from "./games/_game/_playtype/router"; +import importsRouter from "./imports/router"; +import integrationsRouter from "./integrations/router"; +import invitesRouter from "./invites/router"; +import { GetUserFromParam, RequireSelfRequestFromUser } from "./middleware"; +import notifsRouter from "./notifications/router"; +import pfpRouter from "./pfp/router"; +import sessionsRouter from "./sessions/router"; +import settingsRouter from "./settings/router"; + +const router: Router = Router({ mergeParams: true }); + +router.use(GetUserFromParam); + +/** + * Get the user at this ID or name. + * @name GET /api/v1/users/:userID + */ +router.get("/", (req, res) => { + const user = GetUser(req); + + return res.status(200).json({ + success: true, + description: `Found user ${user.username}.`, + body: user, + }); +}); + +interface UserPatchBody { + about?: string | null; + status?: string | null; + discord?: string | null; + twitter?: string | null; + twitch?: string | null; + youtube?: string | null; + github?: string | null; + steam?: string | null; +} + +/** + * Modify this user document. All parameters are optional. + * + * @param about - An about me, this is rendered as markdown. + * @param status - A user status. This is not rendered as markdown, and is short. + * @param discord - The user's discord tag. + * @param twitter - The user's twitter tag. + * @param github - The user's github. + * @param steam - The user's steamID. + * @param youtube - The user's youtube. + * @param twitch - The user's twitch. + * + * @name PATCH /api/v1/users/:userID + */ +router.patch( + "/", + RequireSelfRequestFromUser, + prValidate( + { + about: p.optional(p.isBoundedString(0, 2000)), + status: optNullFluffStrField, + discord: optNullFluffStrField, + twitter: optNullFluffStrField, + github: optNullFluffStrField, + steam: optNullFluffStrField, + youtube: optNullFluffStrField, + twitch: optNullFluffStrField, + }, + { + about: "Your about me is too long.", + }, + ), + async (req, res) => { + const user = GetUser(req); + + const body = req.safeBody as UserPatchBody; + + if (Object.keys(body).length === 0) { + return res.status(400).json({ + success: false, + description: `Nothing was provided to modify.`, + }); + } + + // Hack stuff for user experience. + // In kt1, users would repeatedly mess up these fields. + if (IsNonEmptyString(body.twitter)) { + body.twitter = StripUrl("twitter.com/", body.twitter); + } + + if (IsNonEmptyString(body.github)) { + body.github = StripUrl("github.com/", body.github); + } + + if (IsNonEmptyString(body.youtube)) { + // youtube has THREE user urls lol + body.youtube = StripUrl("youtube.com/user/", body.youtube); + body.youtube = StripUrl("youtube.com/channel/", body.youtube); + body.youtube = StripUrl("youtube.com/@", body.youtube); + } + + if (IsNonEmptyString(body.twitch)) { + body.twitch = StripUrl("twitch.tv/", body.twitch); + } + + if (IsNonEmptyString(body.steam)) { + body.steam = StripUrl("steamcommunity.com/id/", body.steam); + } + + if (body.about === null) { + return res.status(400).json({ + success: false, + description: `Cannot set about me to null.`, + }); + } + + // :( + const modifyObject: Partial< + { about: string } & Record< + | "status" + | `socialMedia.${ + | "discord" + | "github" + | "steam" + | "twitch" + | "twitter" + | "youtube"}`, + string | null + > + > = { + about: body.about, + status: body.status, + }; + + for (const socMed of [ + "twitch", + "github", + "youtube", + "steam", + "twitter", + "discord", + ] as const) { + modifyObject[`socialMedia.${socMed}` as const] = body[socMed]; + } + + DeleteUndefinedProps(modifyObject); + + await db.users.update( + { + id: user.id, + }, + { + $set: modifyObject, + }, + ); + + const newUser = await GetUserWithID(user.id); + + if (!newUser) { + log.error( + { user }, + `User ${FormatUserDoc(user)} updated profile but user doc no longer exists?`, + ); + + return res.status(500).json({ + success: false, + description: `An internal error has occured.`, + }); + } + + if (req.session.tachi?.user) { + req.session.tachi.user = newUser; + } + + return res.status(200).json({ + success: true, + description: `Successfully updated user.`, + body: newUser, + }); + }, +); + +/** + * Returns all of the game-stats this user has. + * Additionally, adds a __rankingData property, which contains this users + * ranking information. + * This endpoint doubles up as a way of checking what games a user has played. + * + * @name GET /api/v1/users/:userID/game-stats + */ +router.get("/game-stats", async (req, res) => { + const user = GetUser(req); + + // a user has played a game if and only if they have stats for it. + const stats: Array< + { + __rankingData?: Record; + } & UserGameStats + > = await db["game-stats"].find({ userID: user.id }); + + await Promise.all( + stats.map(async (s) => { + const data = await GetAllRankings(s); + + s.__rankingData = data; + }), + ); + + return res.status(200).json({ + success: true, + description: `Returned ${stats.length} stats objects.`, + body: stats, + }); +}); + +/** + * Returns a summary of what the user has achieved in the past 16 hours. + * Used on the main dashboard page to give users quick links to sessions, + * alongside other information. + * + * @name GET /api/v1/users/:userID/recent-summary + */ +router.get("/recent-summary", async (req, res) => { + const user = GetUser(req); + + const [ + recentPlaycount, + recentSessions, + { folders: recentFolders, stats: recentFolderStats }, + { achievedGoals, goals, improvedGoals }, + ] = await Promise.all([ + GetRecentPlaycount(user.id), + GetRecentSessions(user.id), + GetRecentlyViewedFoldersAnyGPT(user.id), + GetGoalSummary(user.id), + ]); + + return res.status(200).json({ + success: true, + description: `Retrieved information about ${FormatUserDoc(user)}.`, + body: { + recentPlaycount, + recentSessions, + recentFolders, + recentFolderStats, + recentAchievedGoals: achievedGoals, + recentGoals: goals, + recentImprovedGoals: improvedGoals, + }, + }); +}); + +/** + * Returns whether the user has verified their email or not. + * Requires self-key level permissions. + * + * @name GET /api/v1/users/:userID/is-email-verified + */ +router.get("/is-email-verified", RequireSelfRequestFromUser, async (req, res) => { + const user = GetUser(req); + + const verifyInfo = await db["verify-email-codes"].findOne({ + userID: user.id, + }); + + if (verifyInfo) { + return res.status(200).json({ + success: true, + description: `User has not verified email.`, + body: false, + }); + } + + return res.status(200).json({ + success: true, + description: `User has verified email.`, + body: true, + }); +}); + +/** + * Get what email this user signed up with. + * + * @name GET /api/v1/users/:userID/email + */ +router.get("/email", RequireSelfRequestFromUser, async (req, res) => { + const user = GetUser(req); + + const email = await db["user-private-information"].findOne({ + userID: user.id, + }); + + if (email) { + return res.status(200).json({ + success: true, + description: `User signed up with this email.`, + body: email.email, + }); + } + + log.error(`User ${user.id} doesn't have private info?`); + + return res.status(500).json({ + success: false, + description: `Internal Server Error`, + }); +}); + +/** + * Change what email is associated with this account. + * + * @name GET /api/v1/users/:userID/email + */ +router.post( + "/change-email", + RequireSelfRequestFromUser, + prValidate({ + email: ValidateEmail, + "!password": ValidatePassword, + }), + async (req, res) => { + const user = GetUser(req); + + const body = req.safeBody as { + "!password": string; + email: string; + }; + + const privateInfo = await db["user-private-information"].findOne({ + userID: user.id, + }); + + if (!privateInfo) { + log.error(`User ${user.id} has no associated private info?`); + return res.status(500).json({ + success: false, + description: `Internal server error.`, + }); + } + + const isPasswordValid = await PasswordCompare(body["!password"], privateInfo.password); + + if (!isPasswordValid) { + return res.status(403).json({ + success: false, + description: `Invalid password.`, + }); + } + + const existingEmail = await CheckIfEmailInUse(body.email); + + if (existingEmail) { + log.info(`User attempted to change to email that was already in use.`); + return res.status(409).json({ + success: false, + description: `This email is already in use.`, + }); + } + + log.info(`User ${user.id} changed email from ${privateInfo.email} to ${body.email}`); + + await db["user-private-information"].update( + { + userID: user.id, + }, + { + $set: { + email: body.email, + }, + }, + ); + + if (ServerConfig.EMAIL_CONFIG) { + const resetEmailCode = Random20Hex(); + + // clear out the previous email code! + await db["verify-email-codes"].remove({ + userID: user.id, + }); + + await db["verify-email-codes"].insert({ + code: resetEmailCode, + userID: user.id, + email: body.email, + }); + + const { text, html } = EmailFormatVerifyEmail(user.username, resetEmailCode); + + void SendEmail(body.email, "Email Verification", html, text); + } + + return res.status(200).json({ + success: true, + description: `Re-sent email verification to new email`, + body: null, + }); + }, +); + +/** + * Changes the users password. + * Requires self-key level permissions. + * + * @param !password - The new password. Must pass password validation rules. + * @param !oldPassword - The old password. + * + * @name POST /api/v1/users/:userID/change-password + */ +router.post( + "/change-password", + RequireSelfRequestFromUser, + prValidate({ + "!password": ValidatePassword, + "!oldPassword": ValidatePassword, + }), + async (req, res) => { + const body = req.safeBody as { + "!oldPassword": string; + "!password": string; + }; + + const user = req.session.tachi?.user; + + /* istanbul ignore next */ + if (!user) { + log.error( + `IP ${req.ip} got to /change-password without a user, but passed RequireSelfRequest?`, + ); + + // this should be a 500, but lie to them. + return res.status(403).json({ + success: false, + description: `You are not authorised to perform this action.`, + }); + } + + const privateInfo = await db["user-private-information"].findOne({ + userID: user.id, + }); + + /* istanbul ignore next */ + if (!privateInfo) { + log.error({ user }, `User ${FormatUserDoc(user)} has no private information?`); + return res.status(500).json({ + success: false, + description: `An internal server error has occured.`, + }); + } + + const isLastPasswordValid = await PasswordCompare( + body["!oldPassword"], + privateInfo.password, + ); + + if (!isLastPasswordValid) { + return res.status(401).json({ + success: false, + description: `Old Password doesn't match what we have in our records.`, + }); + } + + const newPasswordHash = await HashPassword(body["!password"]); + + await db["user-private-information"].update( + { + userID: user.id, + }, + { + $set: { + password: newPasswordHash, + }, + }, + ); + + return res.status(200).json({ + success: true, + description: `Updated Password.`, + body: {}, + }); + }, +); + +/** + * Changes the users username. + * Requires self-key level permissions. + * + * @param !password - The new password. Must pass password validation rules. + * @param newUsername - The new username. Must pass username validation rules. + * + * @name POST /api/v1/users/:userID/change-username + */ +router.post( + "/change-username", + RequireSelfRequestFromUser, + prValidate( + { + "!password": ValidatePassword, + newUsername: p.regex(/^[a-zA-Z_-][a-zA-Z0-9_-]{2,20}$/u), + }, + { + newUsername: + "Username must be between 3 and 20 characters long, can only contain alphanumeric characters and cannot start with a number.", + "!password": "Invalid password.", + }, + ), + async (req, res) => { + const body = req.safeBody as { + "!password": string; + newUsername: string; + }; + + const user = req.session.tachi?.user; + + /* istanbul ignore next */ + if (!user) { + log.error( + `IP ${req.ip} got to /change-username without a user, but passed RequireSelfRequest?`, + ); + + // this should be a 500, but lie to them. + return res.status(403).json({ + success: false, + description: `You are not authorised to perform this action.`, + }); + } + + const privateInfo = await db["user-private-information"].findOne({ + userID: user.id, + }); + + /* istanbul ignore next */ + if (!privateInfo) { + log.error({ user }, `User ${FormatUserDoc(user)} has no private information?`); + return res.status(500).json({ + success: false, + description: `An internal server error has occured.`, + }); + } + + const isPasswordValid = await PasswordCompare(body["!password"], privateInfo.password); + + if (!isPasswordValid) { + return res.status(401).json({ + success: false, + description: `Invalid password.`, + }); + } + + const existingUser = await GetUserCaseInsensitive(body.newUsername); + + if (existingUser) { + log.debug(`Invalid username ${body.newUsername}, already in use.`); + return res.status(409).json({ + success: false, + description: "This username is already in use.", + }); + } + + const canChangeUsername = await CanChangeUsername(user.id); + + if (!canChangeUsername) { + return res.status(403).json({ + success: false, + description: "You can only change your username every 6 months.", + }); + } + + await db.users.update( + { + id: user.id, + }, + { + $set: { + username: body.newUsername, + usernameLowercase: body.newUsername.toLowerCase(), + }, + }, + ); + + await db["user-name-changes"].insert({ + userID: user.id, + username: body.newUsername, + timestamp: Date.now(), + previousUsername: user.username, + }); + + if (req.session.tachi?.user) { + req.session.tachi.user = { + ...user, + username: body.newUsername, + }; + req.session.save(); + } + + return res.status(200).json({ + success: true, + description: `Updated your username!`, + body: {}, + }); + }, +); + +/** + * Get the last time the user changed their username, + * and whether they can change their username again. + * + * @name GET /api/v1/users/:userID/last-username-change + */ +router.get("/last-username-change", async (req, res) => { + const user = GetUser(req); + + const nextAvailableChange = await GetNextAvailableUsernameChange(user.id); + + const canChange = await CanChangeUsername(user.id); + + let body; + + if (canChange) { + body = { + canChange: true, + }; + } else { + body = { + canChange: false, + nextAvailableChange, + }; + } + + return res.status(200).json({ + success: true, + description: `Next available username change.`, + body, + }); +}); +/** + * Get the recent import types this user has used. + * + * @name GET /api/v1/users/:userID/recent-imports + */ +router.get("/recent-imports", async (req, res) => { + const user = GetUser(req); + + const recentImports: Array<{ _id: ImportTypes; count: integer }> = await db.imports.aggregate([ + { + $match: { + userID: user.id, + timeFinished: { $gt: Date.now() - ONE_MONTH }, + userIntent: true, + importType: { + $nin: ["file/mypagescraper-records-csv", "file/mypagescraper-player-csv"], + }, + }, + }, + { + $group: { + _id: "$importType", + count: { $sum: 1 }, + }, + }, + ]); + + // rename _id to importType. + const imports = recentImports.map((e) => ({ importType: e._id, count: e.count })); + + return res.status(200).json({ + success: true, + description: `Found ${recentImports.length} imports.`, + body: imports.sort((a, b) => b.count - a.count), + }); +}); + +/** + * Get stats for this user on all games. + * + * @name GET /api/v1/users/:userID/stats + */ +router.get("/stats", async (req, res) => { + const user = GetUser(req); + + const scoreCount = await db.scores.count({ userID: user.id }); + const sessionCount = await db.sessions.count({ userID: user.id }); + + return res.status(200).json({ + success: true, + description: `Retrieved stats.`, + body: { + scores: scoreCount, + sessions: sessionCount, + }, + }); +}); + +/** + * Fetch this users recent activity, and all of their rivals for each GPT they've played. + * + * @name GET /api/v1/users/:userID/activity + */ +router.get( + "/activity", + prValidate({ + startTime: "*string", + includeRivals: p.optional(p.isIn("true", "false")), + includeFollowers: p.optional(p.isIn("true", "false")), + }), + async (req, res) => { + const qStartTime = req.query.startTime as string | undefined; + + const includeRivals = req.query.includeRivals === "true"; + const includeFollowers = req.query.includeFollowers === "true"; + + const startTime = qStartTime ? Number(qStartTime) : null; + + if (Number.isNaN(startTime)) { + return res.status(400).json({ + success: false, + description: `Invalid startTime, got a non number.`, + }); + } + + const user = GetUser(req); + + const gpts = await db["game-stats"].find({ + userID: user.id, + }); + + const data: Partial> = {}; + + const settings = await db["user-settings"].findOne({ userID: user.id }); + + if (!settings) { + log.error(`User ${FormatUserDoc(user)} doesn't have any settings?`); + return res.status(500).json({ + success: false, + description: `This user has no settings.`, + }); + } + + await Promise.all( + gpts.map(async (e) => { + const userIDs: Array = [user.id]; + + if (includeRivals) { + const rivalIDs = await GetRivalIDs(user.id, e.game, e.playtype); + + userIDs.push(...rivalIDs); + } + + // n.b. it is intentional behaviour that you only get updates for + // people you follow on games you play. + if (includeFollowers) { + userIDs.push(...settings.following); + } + + const activity = await GetRecentActivity( + e.game, + { + game: e.game, + playtype: e.playtype, + userID: { $in: userIDs }, + }, + 30, + startTime, + ); + + data[`${e.game}:${e.playtype}` as GPTString] = activity; + }), + ); + + return res.status(200).json({ + success: true, + description: `Returned recent activity.`, + body: data, + }); + }, +); + +router.use("/games", gameSpecificRouter); +router.use("/games/:game/:playtype", gamePTRouter); +router.use("/pfp", pfpRouter); + +router.use("/banner", bannerRouter); +router.use("/integrations", integrationsRouter); +router.use("/settings", settingsRouter); +router.use("/api-tokens", apiTokensRouter); +router.use("/invites", invitesRouter); +router.use("/imports", importsRouter); +router.use("/notifications", notifsRouter); +router.use("/following", followingRouter); +router.use("/sessions", sessionsRouter); + +// Shims for discord functionality; discord checks that a url ends with ".png" +// to use as an image +router.get("/pfp.png", (req, res) => { + res.redirect("./pfp"); +}); +router.get("/banner.png", (req, res) => { + res.redirect("./banner"); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/sessions/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/sessions/router.ts new file mode 100644 index 000000000..da499dbab --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/sessions/router.ts @@ -0,0 +1,40 @@ +import db from "#services/mongo/db"; +import { GetUser } from "#utils/req-tachi-data"; +import { Router } from "express"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Returns all sessions, FOR ALL GPTs + * but with unecessary properties removed so as to reduce + * bandwidth. This is used for the calendar view in tachi-client, hence the name. + * + * @name GET /api/v1/users/:userID/sessions/calendar + */ +router.get("/calendar", async (req, res) => { + const user = GetUser(req); + + const sessions = await db.sessions.find( + { userID: user.id }, + { + projection: { + sessionID: 1, + name: 1, + desc: 1, + highlight: 1, + timeStarted: 1, + timeEnded: 1, + game: 1, + playtype: 1, + }, + }, + ); + + return res.status(200).json({ + success: true, + description: `Found ${sessions.length} events.`, + body: sessions, + }); +}); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/settings/router.test.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/settings/router.test.ts new file mode 100644 index 000000000..8efd3937e --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/settings/router.test.ts @@ -0,0 +1,205 @@ +import type { UserDocument } from "tachi-common"; + +import db from "#services/mongo/db"; +import { CreateFakeAuthCookie } from "#test-utils/fake-auth"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import deepmerge from "deepmerge"; +import t from "tap"; + +t.test("GET /api/v1/users/:userID/settings", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should return the users settings.", async (t) => { + const res = await mockApi.get("/api/v1/users/1/settings"); + + t.strictSame(res.body.body, { + userID: 1, + preferences: { + invisible: false, + developerMode: true, + advancedMode: false, + contentiousContent: false, + deletableScores: false, + }, + }); + + t.end(); + }); + + t.end(); +}); + +t.test("PATCH /api/v1/users/:userID/settings", async (t) => { + t.beforeEach(ResetDBState); + + const cookie = await CreateFakeAuthCookie(mockApi); + + t.test("Should mutate the users settings.", async (t) => { + const res = await mockApi.patch("/api/v1/users/1/settings").set("Cookie", cookie).send({ + developerMode: false, + invisible: true, + }); + + t.strictSame(res.body.body, { + userID: 1, + preferences: { + invisible: true, + developerMode: false, + advancedMode: false, + contentiousContent: false, + deletableScores: false, + }, + }); + + const dbRes = await db["user-settings"].findOne({ userID: 1 }); + + t.strictSame(dbRes, { + userID: 1, + preferences: { + invisible: true, + developerMode: false, + advancedMode: false, + contentiousContent: false, + deletableScores: false, + }, + }); + + t.end(); + }); + + t.test("Should 400 if body is empty.", async (t) => { + const res = await mockApi.patch("/api/v1/users/1/settings").set("Cookie", cookie).send({}); + + t.equal(res.statusCode, 400); + + const dbRes = await db["user-settings"].findOne({ userID: 1 }); + + t.strictSame( + dbRes, + { + userID: 1, + preferences: { + invisible: false, + developerMode: true, + advancedMode: false, + contentiousContent: false, + deletableScores: false, + }, + }, + "User Settings should be unmodified.", + ); + + t.end(); + }); + + t.test("Should validate input.", async (t) => { + const res = await mockApi.patch("/api/v1/users/1/settings").set("Cookie", cookie).send({ + developerMode: "true", + }); + + t.equal(res.statusCode, 400); + + const res2 = await mockApi.patch("/api/v1/users/1/settings").set("Cookie", cookie).send({ + invalid_prop: true, + }); + + t.equal(res2.statusCode, 400); + + const res3 = await mockApi + .patch("/api/v1/users/1/settings") + .set("Cookie", cookie) + .send({ + invisible: { $where: "alert(1)" }, + }); + + t.equal(res3.statusCode, 400); + + t.end(); + }); + + t.test("Must be authenticated as that user.", async (t) => { + const user = await db.users.findOne({}); + + await db.users.insert( + deepmerge(user!, { + id: 2, + username: "something_else", + usernameLowercase: "something_else", + }) as UserDocument, + ); + + const res = await mockApi + .patch("/api/v1/users/2/settings") + + // this token is for user 1, not 2 + .set("Cookie", cookie) + .send({ + developerMode: false, + }); + + t.equal(res.statusCode, 403); + + const dbRes = await db["user-settings"].findOne({ userID: 1 }); + + t.equal( + dbRes?.preferences.developerMode, + true, + "Settings should not be modified in the database.", + ); + + t.end(); + }); + + t.test("Must not work with an API key.", async (t) => { + await db["api-tokens"].insert({ + identifier: "no perm", + permissions: { + // has relevant permissions + customise_profile: true, + }, + token: "no_perm", + userID: 1, + fromAPIClient: null, + }); + + const res = await mockApi + .patch("/api/v1/users/1/settings") + .set("Authorization", "Bearer no_perm") + .send({ + developerMode: false, + }); + + t.equal(res.statusCode, 403); + + const dbRes = await db["user-settings"].findOne({ userID: 1 }); + + t.equal( + dbRes?.preferences.developerMode, + true, + "Settings should not be modified in the database.", + ); + + t.end(); + }); + + t.test("Must be authenticated.", async (t) => { + const res = await mockApi.patch("/api/v1/users/1/settings").send({ + developerMode: false, + }); + + t.equal(res.statusCode, 401); + + const dbRes = await db["user-settings"].findOne({ userID: 1 }); + + t.equal( + dbRes?.preferences.developerMode, + true, + "Settings should not be modified in the database.", + ); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/users/_userID/settings/router.ts b/typescript/server/src/server/router/api/v1postgres/users/_userID/settings/router.ts new file mode 100644 index 000000000..2ccbd1dea --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/_userID/settings/router.ts @@ -0,0 +1,115 @@ +import { log } from "#lib/log/log.js"; +import prValidate from "#server/middleware/prudence-validate"; +import db from "#services/mongo/db"; +import { GetTachiData } from "#utils/req-tachi-data"; +import { FormatUserDoc, GetSettingsForUser } from "#utils/user"; +import { Router } from "express"; + +import { RequireSelfRequestFromUser } from "../middleware"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Retrieve this users settings. Note that these settings are NOT private. + * + * @name GET /api/v1/users/:userID/settings + */ +router.get("/", async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + + const settings = await db["user-settings"].findOne({ + userID: user.id, + }); + + if (!settings) { + log.error(`User ${FormatUserDoc(user)} has no settings?`); + return res.status(500).json({ + success: false, + description: `An internal server error has occured.`, + }); + } + + return res.status(200).json({ + success: true, + description: `Retrieved settings.`, + body: settings, + }); +}); + +/** + * Update a user's settings. + * + * @param invisible - Whether to set the user to invisible or not. + * @param developerMode - Whether to display developer specific information in the WebUI. + * @param advancedMode - Whether to display more advanced options in the WebUI. + * @param contentiousContent - Whether to display slightly inappropriate splash messages. + * + * @name PATCH /api/v1/users/:userID/settings + */ +router.patch( + "/", + RequireSelfRequestFromUser, + prValidate({ + invisible: "*boolean", + developerMode: "*boolean", + contentiousContent: "*boolean", + advancedMode: "*boolean", + deletableScores: "*boolean", + }), + async (req, res) => { + const user = GetTachiData(req, "requestedUser"); + + const preferences = req.safeBody as { + advancedMode?: boolean; + contentiousContent?: boolean; + deletableScores?: boolean; + developerMode?: boolean; + invisible?: boolean; + }; + + if (Object.keys(preferences).length === 0) { + return res.status(400).json({ + success: false, + description: `Nothing was provided to change!`, + }); + } + + const modifyObject: Record = {}; + + for (const [k, v] of Object.entries(preferences)) { + modifyObject[`preferences.${k}`] = v; + } + + await db["user-settings"].update( + { + userID: user.id, + }, + { $set: modifyObject }, + ); + + const settings = await GetSettingsForUser(user.id); + + if (!settings) { + log.error( + { user }, + `User ${FormatUserDoc(user)} has no settings, yet just successfully updated them?`, + ); + return res.status(500).json({ + success: false, + description: `An internal server error has occured.`, + }); + } + + if (req.session.tachi?.settings) { + req.session.tachi.settings = settings; + } + + return res.status(200).json({ + success: true, + description: `Updated settings.`, + body: settings, + }); + }, +); + +export default router; diff --git a/typescript/server/src/server/router/api/v1postgres/users/router.test.ts b/typescript/server/src/server/router/api/v1postgres/users/router.test.ts new file mode 100644 index 000000000..3bf27e133 --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/router.test.ts @@ -0,0 +1,77 @@ +import type { UserDocument } from "tachi-common"; + +import db from "#services/mongo/db"; +import mockApi from "#test-utils/mock-api"; +import ResetDBState from "#test-utils/resets"; +import t from "tap"; + +t.test("GET /api/v1/users", (t) => { + t.beforeEach(ResetDBState); + + t.test("Should search users if search param is set.", async (t) => { + const res = await mockApi.get("/api/v1/users?search=zkldi"); + + t.equal(res.body.body.length, 1); + t.equal(res.body.body[0].username, "test_zkldi"); + + const res2 = await mockApi.get("/api/v1/users?search=nothing"); + + t.equal(res2.body.body.length, 0); + + const res3 = await mockApi.get("/api/v1/users?search=ZklDI"); + + t.equal(res3.body.body.length, 1); + t.equal(res3.body.body[0].username, "test_zkldi"); + + t.end(); + }); + + t.test("Should sanitise input for regex stuff.", async (t) => { + const res = await mockApi.get("/api/v1/users?search=.*"); + + t.equal(res.body.body.length, 0); + + t.end(); + }); + + t.test("Should restrict returns to only online users if online is set.", async (t) => { + const res = await mockApi.get("/api/v1/users?online=true"); + + t.equal(res.body.body.length, 0); + + await db.users.insert({ + username: "online_dude", + usernameLowercase: "online_dude", + lastSeen: Date.now(), + id: 2, + } as UserDocument); + + const res2 = await mockApi.get("/api/v1/users?online=true"); + + t.equal(res2.body.body.length, 1); + t.equal(res2.body.body[0].usernameLowercase, "online_dude"); + + t.end(); + }); + + t.test("Should return users sorted by lastSeen if no arguments are passed.", async (t) => { + await db.users.insert({ + username: "online_dude", + usernameLowercase: "online_dude", + lastSeen: Date.now(), + id: 2, + } as UserDocument); + + const res = await mockApi.get("/api/v1/users"); + + t.equal(res.body.body.length, 2); + t.strictSame( + res.body.body.map((e: UserDocument) => e.usernameLowercase), + ["online_dude", "test_zkldi"], + ); + + t.end(); + }); + + t.end(); +}); diff --git a/typescript/server/src/server/router/api/v1postgres/users/router.ts b/typescript/server/src/server/router/api/v1postgres/users/router.ts new file mode 100644 index 000000000..baf655d8d --- /dev/null +++ b/typescript/server/src/server/router/api/v1postgres/users/router.ts @@ -0,0 +1,54 @@ +import { SearchUsersRegExp } from "#lib/search/search"; +import db from "#services/mongo/db"; +import { IsString } from "#utils/misc"; +import { GetOnlineCutoff } from "#utils/user"; +import { Router } from "express"; + +import userIDRouter from "./_userID/router"; + +const router: Router = Router({ mergeParams: true }); + +/** + * Search users. + * + * @param online - Restrict returned users to those who are online. + * @param search - Search for users where their name contains this string. If not present, returns + * users sorted by last appearance. + * + * @name GET /api/v1/users + */ +router.get("/", async (req, res) => { + const onlyOnline = req.query.online !== undefined; + + let users; + + const search = req.query.search; + + if (search !== undefined) { + if (!IsString(search)) { + return res.status(400).json({ + success: false, + description: `Search parameter was invalid.`, + }); + } + + users = await SearchUsersRegExp(search, onlyOnline); + } else { + const query = onlyOnline ? { lastSeen: { $gt: GetOnlineCutoff() } } : {}; + + users = await db.users.find(query, { + sort: { lastSeen: -1 }, + limit: 100, + }); + } + + return res.status(200).json({ + success: true, + description: `Returned ${users.length} users.`, + body: users, + }); +}); + +router.use("/:userID", userIDRouter); + +export default router; diff --git a/typescript/server/src/server/router/router.ts b/typescript/server/src/server/router/router.ts index 7314f57c1..eda342eeb 100644 --- a/typescript/server/src/server/router/router.ts +++ b/typescript/server/src/server/router/router.ts @@ -4,7 +4,7 @@ import { Router } from "express"; import { RejectIfBanned, SetRequestPermissions } from "../middleware/auth"; import { NormalRateLimitMiddleware } from "../middleware/rate-limiter"; -import apiRouterV1 from "./api/v1/router"; +import apiRouterV1Mongo from "./api/v1/router"; import irRouter from "./ir/router"; const router: Router = Router({ mergeParams: true }); @@ -18,14 +18,14 @@ router.use("/ir", NormalRateLimitMiddleware, irRouter); router.use(SetRequestPermissions); router.use(UpdateLastSeen); -router.use("/api/v1", apiRouterV1); +router.use("/api/v1mongo", apiRouterV1Mongo); // if in localdev, add a debug endpoint to tell users when they got a successful fetch // on the root endpoint. // That is to say, if a user is hitting 127.0.0.1:8080/ // instead of "cannot GET /", they should get a nice message. if (Env.NODE_ENV === "dev") { - router.get("/", (req, res) => + router.get("/", (_req, res) => res.send( `Server is live and running. All is good!
This is a DEBUG endpoint and only exists in local dev.