From 69c151162e0dc23aeb9dd5817399f1ff5ac40d42 Mon Sep 17 00:00:00 2001 From: Scott Gould Date: Thu, 19 Sep 2024 08:36:43 -0400 Subject: [PATCH] It runs now, wont let me connect to instances though Signed-off-by: Scott Gould --- eslint.config.mjs | 1 + package-lock.json | 1074 +----------- package.json | 13 +- src/webpage/localuser.ts | 3516 +++++++++++++++++++------------------- tsconfig.json | 1 + 5 files changed, 1772 insertions(+), 2833 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 83a917c..af7b39e 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -16,6 +16,7 @@ export default tseslint.config( }, }, files: ["**/*.ts", "**/*.html"], + ignores: ["dist/**/*", "node_modules/**/*"], rules: { "array-callback-return": 2, "block-scoped-var": 2, diff --git a/package-lock.json b/package-lock.json index fa622ac..025864c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.1.0", "license": "GPL-3.0", "dependencies": { + "@html-eslint/parser": "^0.27.0", "compression": "^1.7.4", "express": "^4.19.2", "node-fetch": "^3.3.2", @@ -17,145 +18,18 @@ "devDependencies": { "@eslint/js": "^9.10.0", "@html-eslint/eslint-plugin": "^0.25.0", - "@html-eslint/parser": "^0.25.0", - "@stylistic/eslint-plugin": "^2.3.0", "@types/compression": "^1.7.5", "@types/eslint__js": "^8.42.3", "@types/express": "^4.17.21", "@types/node-fetch": "^2.6.11", "eslint": "^8.57.1", - "eslint-plugin-html": "^8.1.1", - "eslint-plugin-sonarjs": "^1.0.4", - "eslint-plugin-unicorn": "^55.0.0", "gulp": "^5.0.0", "gulp-copy": "^5.0.0", "gulp-typescript": "^6.0.0-alpha.1", - "ts-node": "^10.9.2", "typescript": "^5.6.2", "typescript-eslint": "^7.18.0" } }, - "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.24.7", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -333,10 +207,9 @@ } }, "node_modules/@html-eslint/parser": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@html-eslint/parser/-/parser-0.25.0.tgz", - "integrity": "sha512-dj6U1klMorS/g1QFI6j15AXknsqMDtdingSF6Sdtm1Z7WOVISfDwVyeNbb+JLUG+ATo9aECPQP5A7MHqgP6J9A==", - "dev": true, + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@html-eslint/parser/-/parser-0.27.0.tgz", + "integrity": "sha512-F/A1M0jnDAYoRvJiiSC7pIBD9DAsf4EhbndbvEi81aozD/wI8WWXON50xZPUaGHCI1C+2syTVifxDz8MvDKaQA==", "license": "MIT", "dependencies": { "es-html-parser": "^0.0.9" @@ -431,34 +304,6 @@ "dev": true, "license": "BSD-3-Clause" }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -491,91 +336,6 @@ "node": ">= 8" } }, - "node_modules/@stylistic/eslint-plugin": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.3.0.tgz", - "integrity": "sha512-rtiz6u5gRyyEZp36FcF1/gHJbsbT3qAgXZ1qkad6Nr/xJ9wrSJkiSFFQhpYVTIZ7FJNRJurEcumZDCwN9dEI4g==", - "dev": true, - "dependencies": { - "@stylistic/eslint-plugin-js": "2.3.0", - "@stylistic/eslint-plugin-jsx": "2.3.0", - "@stylistic/eslint-plugin-plus": "2.3.0", - "@stylistic/eslint-plugin-ts": "2.3.0", - "@types/eslint": "^8.56.10" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "peerDependencies": { - "eslint": ">=8.40.0" - } - }, - "node_modules/@stylistic/eslint-plugin-js": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.3.0.tgz", - "integrity": "sha512-lQwoiYb0Fs6Yc5QS3uT8+T9CPKK2Eoxc3H8EnYJgM26v/DgtW+1lvy2WNgyBflU+ThShZaHm3a6CdD9QeKx23w==", - "dev": true, - "dependencies": { - "@types/eslint": "^8.56.10", - "acorn": "^8.11.3", - "eslint-visitor-keys": "^4.0.0", - "espree": "^10.0.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "peerDependencies": { - "eslint": ">=8.40.0" - } - }, - "node_modules/@stylistic/eslint-plugin-jsx": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-2.3.0.tgz", - "integrity": "sha512-tsQ0IEKB195H6X9A4iUSgLLLKBc8gUBWkBIU8tp1/3g2l8stu+PtMQVV/VmK1+3bem5FJCyvfcZIQ/WF1fsizA==", - "dev": true, - "dependencies": { - "@stylistic/eslint-plugin-js": "^2.3.0", - "@types/eslint": "^8.56.10", - "estraverse": "^5.3.0", - "picomatch": "^4.0.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "peerDependencies": { - "eslint": ">=8.40.0" - } - }, - "node_modules/@stylistic/eslint-plugin-plus": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-2.3.0.tgz", - "integrity": "sha512-xboPWGUU5yaPlR+WR57GwXEuY4PSlPqA0C3IdNA/+1o2MuBi95XgDJcZiJ9N+aXsqBXAPIpFFb+WQ7QEHo4f7g==", - "dev": true, - "dependencies": { - "@types/eslint": "^8.56.10", - "@typescript-eslint/utils": "^7.12.0" - }, - "peerDependencies": { - "eslint": "*" - } - }, - "node_modules/@stylistic/eslint-plugin-ts": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.3.0.tgz", - "integrity": "sha512-wqOR38/uz/0XPnHX68ftp8sNMSAqnYGjovOTN7w00xnjS6Lxr3Sk7q6AaxWWqbMvOj7V2fQiMC5HWAbTruJsCg==", - "dev": true, - "dependencies": { - "@stylistic/eslint-plugin-js": "2.3.0", - "@types/eslint": "^8.56.10", - "@typescript-eslint/utils": "^7.12.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "peerDependencies": { - "eslint": ">=8.40.0" - } - }, "node_modules/@ts-morph/common": { "version": "0.22.0", "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.22.0.tgz", @@ -588,34 +348,6 @@ "path-browserify": "^1.0.1" } }, - "node_modules/@tsconfig/node10": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/body-parser": { "version": "1.19.5", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", @@ -740,12 +472,6 @@ "form-data": "^4.0.0" } }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", - "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", - "dev": true - }, "node_modules/@types/qs": { "version": "6.9.16", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz", @@ -1105,19 +831,6 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/acorn-walk": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", - "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -1218,13 +931,6 @@ "node": ">=0.10.0" } }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, - "license": "MIT" - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -1471,38 +1177,6 @@ "node": ">=8" } }, - "node_modules/browserslist": { - "version": "4.23.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", - "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001640", - "electron-to-chromium": "^1.4.820", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.1.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, "node_modules/buffer": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", @@ -1541,18 +1215,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -1590,26 +1252,6 @@ "node": ">=6" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001643", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001643.tgz", - "integrity": "sha512-ERgWGNleEilSrHM6iUz/zJNSQTP8Mr21wDWpdgvRwcTXGAq6jMtOUPP4dqFPTdKqZ2wKTdtB+uucZ3MRpAUSmg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -1664,42 +1306,6 @@ "node": ">= 6" } }, - "node_modules/ci-info": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.0.0.tgz", - "integrity": "sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "node_modules/clean-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", - "integrity": "sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/clean-regexp/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -1896,19 +1502,6 @@ "node": ">= 10.13.0" } }, - "node_modules/core-js-compat": { - "version": "3.37.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", - "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", - "dev": true, - "dependencies": { - "browserslist": "^4.23.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -1916,13 +1509,6 @@ "dev": true, "license": "MIT" }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, - "license": "MIT" - }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -2035,16 +1621,6 @@ "node": ">=0.10.0" } }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -2070,61 +1646,6 @@ "node": ">=6.0.0" } }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "dev": true, - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, "node_modules/duplexify": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", @@ -2158,12 +1679,6 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "license": "MIT" }, - "node_modules/electron-to-chromium": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.1.tgz", - "integrity": "sha512-FKbOCOQ5QRB3VlIbl1LZQefWIYwszlBloaXcY2rbfpu9ioJnNh3TK03YtIDKDo3WKBi8u+YV4+Fn2CkEozgf4w==", - "dev": true - }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -2190,27 +1705,6 @@ "once": "^1.4.0" } }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, "node_modules/es-define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", @@ -2235,8 +1729,7 @@ "node_modules/es-html-parser": { "version": "0.0.9", "resolved": "https://registry.npmjs.org/es-html-parser/-/es-html-parser-0.0.9.tgz", - "integrity": "sha512-oniQMi+466VFsDzcdron9Ry/sqUJpDJg1bbDn0jFJKDdxXhwIOYDr4DgBnO5/yPLGj2xv+n5yy4L1Q0vAC5TYQ==", - "dev": true + "integrity": "sha512-oniQMi+466VFsDzcdron9Ry/sqUJpDJg1bbDn0jFJKDdxXhwIOYDr4DgBnO5/yPLGj2xv+n5yy4L1Q0vAC5TYQ==" }, "node_modules/escalade": { "version": "3.1.2", @@ -2321,75 +1814,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-plugin-html": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-8.1.1.tgz", - "integrity": "sha512-6qmlJsc40D2m3Dn9oEH+0PAOkJhxVu0f5sVItqpCE0YWgYnyP4xCjBc3UWTHaJcY9ARkWOLIIuXLq0ndRnQOHw==", - "dev": true, - "dependencies": { - "htmlparser2": "^9.1.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/eslint-plugin-sonarjs": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-1.0.4.tgz", - "integrity": "sha512-jF0eGCUsq/HzMub4ExAyD8x1oEgjOyB9XVytYGyWgSFvdiJQJp6IuP7RmtauCf06o6N/kZErh+zW4b10y1WZ+Q==", - "dev": true, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "eslint": "^8.0.0 || ^9.0.0" - } - }, - "node_modules/eslint-plugin-unicorn": { - "version": "55.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-55.0.0.tgz", - "integrity": "sha512-n3AKiVpY2/uDcGrS3+QsYDkjPfaOrNrsfQxU9nt5nitd9KuvVXrfAvgCO9DYPSfap+Gqjw9EOrXIsBp5tlHZjA==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.24.5", - "@eslint-community/eslint-utils": "^4.4.0", - "ci-info": "^4.0.0", - "clean-regexp": "^1.0.0", - "core-js-compat": "^3.37.0", - "esquery": "^1.5.0", - "globals": "^15.7.0", - "indent-string": "^4.0.0", - "is-builtin-module": "^3.2.1", - "jsesc": "^3.0.2", - "pluralize": "^8.0.0", - "read-pkg-up": "^7.0.1", - "regexp-tree": "^0.1.27", - "regjsparser": "^0.10.0", - "semver": "^7.6.1", - "strip-indent": "^3.0.0" - }, - "engines": { - "node": ">=18.18" - }, - "funding": { - "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" - }, - "peerDependencies": { - "eslint": ">=8.56.0" - } - }, - "node_modules/eslint-plugin-unicorn/node_modules/globals": { - "version": "15.8.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.8.0.tgz", - "integrity": "sha512-VZAJ4cewHTExBWDHR6yptdIBlx9YSSZuwojj9Nt5mBRXQzrKakDsVKQ1J63sklLvzAJm0X5+RpO4i3Y2hcOnFw==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", @@ -2406,18 +1830,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-visitor-keys": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", - "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/eslint/node_modules/@eslint/js": { "version": "8.57.1", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", @@ -2502,23 +1914,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/espree": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", - "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", - "dev": true, - "dependencies": { - "acorn": "^8.12.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/esquery": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", @@ -3645,31 +3040,6 @@ "node": ">=0.10.0" } }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/htmlparser2": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", - "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==", - "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.1.0", - "entities": "^4.5.0" - } - }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -3753,15 +3123,6 @@ "node": ">=0.8.19" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -3819,12 +3180,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -3845,21 +3200,6 @@ "dev": true, "license": "MIT" }, - "node_modules/is-builtin-module": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", - "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", - "dev": true, - "dependencies": { - "builtin-modules": "^3.3.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-core-module": { "version": "2.15.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", @@ -4043,12 +3383,6 @@ "node": ">=0.10.0" } }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -4061,30 +3395,12 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsesc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -4171,12 +3487,6 @@ "node": ">=10.13.0" } }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -4198,13 +3508,6 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "license": "ISC" - }, "node_modules/map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", @@ -4307,15 +3610,6 @@ "node": ">= 0.6" } }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -4413,33 +3707,6 @@ "url": "https://opencollective.com/node-fetch" } }, - "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -4620,15 +3887,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -4656,24 +3914,6 @@ "node": ">=0.8" } }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", @@ -4778,24 +4018,6 @@ "node": ">=8" } }, - "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "dev": true - }, - "node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/plugin-error": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-2.0.1.tgz", @@ -4822,15 +4044,6 @@ "node": ">=0.10.0" } }, - "node_modules/pluralize": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", - "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -4957,108 +4170,6 @@ "node": ">= 0.8" } }, - "node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", @@ -5121,36 +4232,6 @@ "node": ">= 10.13.0" } }, - "node_modules/regexp-tree": { - "version": "0.1.27", - "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", - "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==", - "dev": true, - "bin": { - "regexp-tree": "bin/regexp-tree" - } - }, - "node_modules/regjsparser": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.10.0.tgz", - "integrity": "sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==", - "dev": true, - "dependencies": { - "jsesc": "~0.5.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - } - }, "node_modules/remove-bom-buffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", @@ -5514,38 +4595,6 @@ "node": ">= 10.13.0" } }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.18", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", - "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", - "dev": true - }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -5638,18 +4687,6 @@ "node": ">=8" } }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -5824,50 +4861,6 @@ "code-block-writer": "^12.0.0" } }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, - "license": "MIT", - "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" - }, - "bin": { - "ts-node": "dist/bin.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", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, "node_modules/ts-to-jsdoc": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ts-to-jsdoc/-/ts-to-jsdoc-2.2.0.tgz", @@ -6038,36 +5031,6 @@ "node": ">= 0.8" } }, - "node_modules/update-browserslist-db": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -6093,13 +5056,6 @@ "node": ">= 0.4.0" } }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, - "license": "MIT" - }, "node_modules/v8flags": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-4.0.1.tgz", @@ -6110,16 +5066,6 @@ "node": ">= 10.13.0" } }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, "node_modules/value-or-function": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-4.0.0.tgz", @@ -6415,16 +5361,6 @@ "node": ">=10" } }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index b963062..21e97f9 100644 --- a/package.json +++ b/package.json @@ -12,23 +12,24 @@ "author": "MathMan05", "license": "GPL-3.0", "dependencies": { + "@html-eslint/parser": "^0.27.0", "compression": "^1.7.4", "express": "^4.19.2", "node-fetch": "^3.3.2", "ts-to-jsdoc": "^2.2.0" }, "devDependencies": { - "typescript": "^5.6.2", - "eslint": "^8.57.1", "@eslint/js": "^9.10.0", - "@types/eslint__js": "^8.42.3", - "typescript-eslint": "^7.18.0", "@html-eslint/eslint-plugin": "^0.25.0", "@types/compression": "^1.7.5", + "@types/eslint__js": "^8.42.3", "@types/express": "^4.17.21", "@types/node-fetch": "^2.6.11", + "eslint": "^8.57.1", "gulp": "^5.0.0", "gulp-copy": "^5.0.0", - "gulp-typescript": "^6.0.0-alpha.1" + "gulp-typescript": "^6.0.0-alpha.1", + "typescript": "^5.6.2", + "typescript-eslint": "^7.18.0" } -} \ No newline at end of file +} diff --git a/src/webpage/localuser.ts b/src/webpage/localuser.ts index 127e810..40caa46 100644 --- a/src/webpage/localuser.ts +++ b/src/webpage/localuser.ts @@ -6,14 +6,14 @@ import { User } from "./user.js"; import { Dialog } from "./dialog.js"; import { getapiurls, getBulkInfo, setTheme, Specialuser } from "./login.js"; import { -channeljson, -guildjson, -memberjson, -messageCreateJson, -presencejson, -readyjson, -startTypingjson, -wsjson, + channeljson, + guildjson, + memberjson, + messageCreateJson, + presencejson, + readyjson, + startTypingjson, + wsjson, } from "./jsontypes.js"; import { Member } from "./member.js"; import { FormError, Settings } from "./settings.js"; @@ -22,1803 +22,1803 @@ import { MarkDown } from "./markdown.js"; const wsCodesRetry = new Set([4000, 4003, 4005, 4007, 4008, 4009]); class Localuser { -badges: Map< -string, -{ id: string; description: string; icon: string; link: string } -> = new Map(); -lastSequence: number | null = null; -token!: string; -userinfo!: Specialuser; -serverurls!: Specialuser["serverurls"]; -initialized!: boolean; -info!: Specialuser["serverurls"]; -headers!: { "Content-type": string; Authorization: string }; -userConnections!: Dialog; -devPortal!: Dialog; -ready!: readyjson; -guilds!: Guild[]; -guildids: Map = new Map(); - user!: User; - status!: string; - channelfocus: Channel | undefined; - lookingguild: Guild | undefined; - guildhtml: Map = new Map(); - ws: WebSocket | undefined; - connectionSucceed = 0; - errorBackoff = 0; - channelids: Map = new Map(); - readonly userMap: Map = new Map(); - instancePing = { - name: "Unknown", - }; - mfa_enabled!: boolean; - get perminfo() { - return this.userinfo.localuserStore; - } - set perminfo(e) { - this.userinfo.localuserStore = e; - } - constructor(userinfo: Specialuser | -1) { - if (userinfo === -1) { - return; - } - this.token = userinfo.token; - this.userinfo = userinfo; - this.perminfo.guilds ??= {}; - this.serverurls = this.userinfo.serverurls; - this.initialized = false; - this.info = this.serverurls; - this.headers = { - "Content-type": "application/json; charset=UTF-8", - Authorization: this.userinfo.token, - }; - } - gottenReady(ready: readyjson): void { - this.initialized = true; - this.ready = ready; - this.guilds = []; - this.guildids = new Map(); - this.user = new User(ready.d.user, this); - this.user.setstatus("online"); - this.mfa_enabled = ready.d.user.mfa_enabled as boolean; - this.userinfo.username = this.user.username; - this.userinfo.pfpsrc = this.user.getpfpsrc(); - this.status = this.ready.d.user_settings.status; - this.channelfocus = undefined; - this.lookingguild = undefined; - this.guildhtml = new Map(); - const members: { [key: string]: memberjson } = {}; - for (const thing of ready.d.merged_members) { - members[thing[0].guild_id] = thing[0]; - } + badges: Map< + string, + { id: string; description: string; icon: string; link: string } + > = new Map(); + lastSequence: number | null = null; + token!: string; + userinfo!: Specialuser; + serverurls!: Specialuser["serverurls"]; + initialized!: boolean; + info!: Specialuser["serverurls"]; + headers!: { "Content-type": string; Authorization: string }; + userConnections!: Dialog; + devPortal!: Dialog; + ready!: readyjson; + guilds!: Guild[]; + guildids: Map = new Map(); + user!: User; + status!: string; + channelfocus: Channel | undefined; + lookingguild: Guild | undefined; + guildhtml: Map = new Map(); + ws: WebSocket | undefined; + connectionSucceed = 0; + errorBackoff = 0; + channelids: Map = new Map(); + readonly userMap: Map = new Map(); + instancePing = { + name: "Unknown", + }; + mfa_enabled!: boolean; + get perminfo() { + return this.userinfo.localuserStore; + } + set perminfo(e) { + this.userinfo.localuserStore = e; + } + constructor(userinfo: Specialuser | -1) { + if (userinfo === -1) { + return; + } + this.token = userinfo.token; + this.userinfo = userinfo; + this.perminfo.guilds ??= {}; + this.serverurls = this.userinfo.serverurls; + this.initialized = false; + this.info = this.serverurls; + this.headers = { + "Content-type": "application/json; charset=UTF-8", + Authorization: this.userinfo.token, + }; + } + gottenReady(ready: readyjson): void { + this.initialized = true; + this.ready = ready; + this.guilds = []; + this.guildids = new Map(); + this.user = new User(ready.d.user, this); + this.user.setstatus("online"); + this.mfa_enabled = ready.d.user.mfa_enabled as boolean; + this.userinfo.username = this.user.username; + this.userinfo.pfpsrc = this.user.getpfpsrc(); + this.status = this.ready.d.user_settings.status; + this.channelfocus = undefined; + this.lookingguild = undefined; + this.guildhtml = new Map(); + const members: { [key: string]: memberjson } = {}; + for (const thing of ready.d.merged_members) { + members[thing[0].guild_id] = thing[0]; + } - for (const thing of ready.d.guilds) { - const temp = new Guild(thing, this, members[thing.id]); - this.guilds.push(temp); - this.guildids.set(temp.id, temp); - } - { - const temp = new Direct(ready.d.private_channels, this); - this.guilds.push(temp); - this.guildids.set(temp.id, temp); - } - console.log(ready.d.user_guild_settings.entries); + for (const thing of ready.d.guilds) { + const temp = new Guild(thing, this, members[thing.id]); + this.guilds.push(temp); + this.guildids.set(temp.id, temp); + } + { + const temp = new Direct(ready.d.private_channels, this); + this.guilds.push(temp); + this.guildids.set(temp.id, temp); + } + console.log(ready.d.user_guild_settings.entries); - for (const thing of ready.d.user_guild_settings.entries) { - (this.guildids.get(thing.guild_id) as Guild).notisetting(thing); - } + for (const thing of ready.d.user_guild_settings.entries) { + (this.guildids.get(thing.guild_id) as Guild).notisetting(thing); + } - for (const thing of ready.d.read_state.entries) { - const channel = this.channelids.get(thing.channel_id); - if (!channel) { - continue; - } - channel.readStateInfo(thing); - } - for (const thing of ready.d.relationships) { - const user = new User(thing.user, this); - user.nickname = thing.nickname; - user.relationshipType = thing.type; - } + for (const thing of ready.d.read_state.entries) { + const channel = this.channelids.get(thing.channel_id); + if (!channel) { + continue; + } + channel.readStateInfo(thing); + } + for (const thing of ready.d.relationships) { + const user = new User(thing.user, this); + user.nickname = thing.nickname; + user.relationshipType = thing.type; + } - this.pingEndpoint(); - this.userinfo.updateLocal(); - } - outoffocus(): void { - const servers = document.getElementById("servers") as HTMLDivElement; - servers.innerHTML = ""; - const channels = document.getElementById("channels") as HTMLDivElement; - channels.innerHTML = ""; - if (this.channelfocus) { - this.channelfocus.infinite.delete(); - } - this.lookingguild = undefined; - this.channelfocus = undefined; - } - unload(): void { - this.initialized = false; - this.outoffocus(); - this.guilds = []; - this.guildids = new Map(); - if (this.ws) { - this.ws.close(4001); - } - } - swapped = false; - async initwebsocket(): Promise { - let returny: () => void; - const ws = new WebSocket( - this.serverurls.gateway.toString() + - "?encoding=json&v=9" + - (DecompressionStream ? "&compress=zlib-stream" : "") - ); - this.ws = ws; - let ds: DecompressionStream; - let w: WritableStreamDefaultWriter; - let r: ReadableStreamDefaultReader; - let arr: Uint8Array; - let build = ""; - if (DecompressionStream) { - ds = new DecompressionStream("deflate"); - w = ds.writable.getWriter(); - r = ds.readable.getReader(); - arr = new Uint8Array(); - } - const promise = new Promise((res) => { - returny = res; - ws.addEventListener("open", (_event) => { - console.log("WebSocket connected"); - ws.send( - JSON.stringify({ - op: 2, - d: { - token: this.token, - capabilities: 16381, - properties: { - browser: "Jank Client", - client_build_number: 0, //might update this eventually lol - release_channel: "Custom", - browser_user_agent: navigator.userAgent, - }, - compress: Boolean(DecompressionStream), - presence: { - status: "online", - since: null, //new Date().getTime() - activities: [], - afk: false, - }, - }, - }) - ); - }); - const textdecode = new TextDecoder(); - if (DecompressionStream) { - (async () => { - while (true) { - const read = await r.read(); - const data = textdecode.decode(read.value); - build += data; - try { - const temp = JSON.parse(build); - build = ""; - if (temp.op === 0 && temp.t === "READY") { - returny(); - } - await this.handleEvent(temp); - } catch {} - } - })(); - } - }); + this.pingEndpoint(); + this.userinfo.updateLocal(); + } + outoffocus(): void { + const servers = document.getElementById("servers") as HTMLDivElement; + servers.innerHTML = ""; + const channels = document.getElementById("channels") as HTMLDivElement; + channels.innerHTML = ""; + if (this.channelfocus) { + this.channelfocus.infinite.delete(); + } + this.lookingguild = undefined; + this.channelfocus = undefined; + } + unload(): void { + this.initialized = false; + this.outoffocus(); + this.guilds = []; + this.guildids = new Map(); + if (this.ws) { + this.ws.close(4001); + } + } + swapped = false; + async initwebsocket(): Promise { + let returny: () => void; + const ws = new WebSocket( + this.serverurls.gateway.toString() + + "?encoding=json&v=9" + + (DecompressionStream ? "&compress=zlib-stream" : "") + ); + this.ws = ws; + let ds: DecompressionStream; + let w: WritableStreamDefaultWriter; + let r: ReadableStreamDefaultReader; + let arr: Uint8Array; + let build = ""; + if (DecompressionStream) { + ds = new DecompressionStream("deflate"); + w = ds.writable.getWriter(); + r = ds.readable.getReader(); + arr = new Uint8Array(); + } + const promise = new Promise((res) => { + returny = res; + ws.addEventListener("open", (_event) => { + console.log("WebSocket connected"); + ws.send( + JSON.stringify({ + op: 2, + d: { + token: this.token, + capabilities: 16381, + properties: { + browser: "Jank Client", + client_build_number: 0, //might update this eventually lol + release_channel: "Custom", + browser_user_agent: navigator.userAgent, + }, + compress: Boolean(DecompressionStream), + presence: { + status: "online", + since: null, //new Date().getTime() + activities: [], + afk: false, + }, + }, + }) + ); + }); + const textdecode = new TextDecoder(); + if (DecompressionStream) { + (async () => { + while (true) { + const read = await r.read(); + const data = textdecode.decode(read.value); + build += data; + try { + const temp = JSON.parse(build); + build = ""; + if (temp.op === 0 && temp.t === "READY") { + returny(); + } + await this.handleEvent(temp); + } catch {} + } + })(); + } + }); - let order = new Promise((res) => res()); + let order = new Promise((res) => res()); - ws.addEventListener("message", async (event) => { - const temp2 = order; - order = new Promise(async (res) => { - await temp2; - let temp: { op: number; t: string }; - try { - if (event.data instanceof Blob) { - const buff = await event.data.arrayBuffer(); - const array = new Uint8Array(buff); + ws.addEventListener("message", async (event) => { + const temp2 = order; + order = new Promise(async (res) => { + await temp2; + let temp: { op: number; t: string }; + try { + if (event.data instanceof Blob) { + const buff = await event.data.arrayBuffer(); + const array = new Uint8Array(buff); - const temparr = new Uint8Array(array.length + arr.length); - temparr.set(arr, 0); - temparr.set(array, arr.length); - arr = temparr; + const temparr = new Uint8Array(array.length + arr.length); + temparr.set(arr, 0); + temparr.set(array, arr.length); + arr = temparr; - const len = array.length; - if ( - !( - array[len - 1] === 255 && - array[len - 2] === 255 && - array[len - 3] === 0 && - array[len - 4] === 0 - ) - ) { - return; - } - w.write(arr.buffer); - arr = new Uint8Array(); - return; //had to move the while loop due to me being dumb - } else { - temp = JSON.parse(event.data); - } - if (temp.op === 0 && temp.t === "READY") { - returny(); - } - await this.handleEvent(temp as readyjson); - } catch (e) { - console.error(e); - } finally { - res(); - } - }); - }); + const len = array.length; + if ( + !( + array[len - 1] === 255 && + array[len - 2] === 255 && + array[len - 3] === 0 && + array[len - 4] === 0 + ) + ) { + return; + } + w.write(arr.buffer); + arr = new Uint8Array(); + return; //had to move the while loop due to me being dumb + } else { + temp = JSON.parse(event.data); + } + if (temp.op === 0 && temp.t === "READY") { + returny(); + } + await this.handleEvent(temp as readyjson); + } catch (e) { + console.error(e); + } finally { + res(); + } + }); + }); - ws.addEventListener("close", async (event) => { - this.ws = undefined; - console.log("WebSocket closed with code " + event.code); + ws.addEventListener("close", async (event) => { + this.ws = undefined; + console.log("WebSocket closed with code " + event.code); - this.unload(); - (document.getElementById("loading") as HTMLElement).classList.remove( - "doneloading" - ); - (document.getElementById("loading") as HTMLElement).classList.add( - "loading" - ); - this.fetchingmembers = new Map(); - this.noncemap = new Map(); - this.noncebuild = new Map(); - if ( - (event.code > 1000 && event.code < 1016) || - wsCodesRetry.has(event.code) - ) { - if ( - this.connectionSucceed !== 0 && - Date.now() > this.connectionSucceed + 20000 - ) - this.errorBackoff = 0; - else this.errorBackoff++; - this.connectionSucceed = 0; + this.unload(); + (document.getElementById("loading") as HTMLElement).classList.remove( + "doneloading" + ); + (document.getElementById("loading") as HTMLElement).classList.add( + "loading" + ); + this.fetchingmembers = new Map(); + this.noncemap = new Map(); + this.noncebuild = new Map(); + if ( + (event.code > 1000 && event.code < 1016) || + wsCodesRetry.has(event.code) + ) { + if ( + this.connectionSucceed !== 0 && + Date.now() > this.connectionSucceed + 20000 + ) + this.errorBackoff = 0; + else this.errorBackoff++; + this.connectionSucceed = 0; - (document.getElementById("load-desc") as HTMLElement).innerHTML = - "Unable to connect to the Spacebar server, retrying in " + - Math.round(0.2 + this.errorBackoff * 2.8) + - " seconds..."; - switch ( - this.errorBackoff //try to recover from bad domain - ) { - case 3: - const newurls = await getapiurls(this.info.wellknown); - if (newurls) { - this.info = newurls; - this.serverurls = newurls; - this.userinfo.json.serverurls = this.info; - this.userinfo.updateLocal(); - break; - } - break; + (document.getElementById("load-desc") as HTMLElement).innerHTML = + "Unable to connect to the Spacebar server, retrying in " + + Math.round(0.2 + this.errorBackoff * 2.8) + + " seconds..."; + switch ( + this.errorBackoff //try to recover from bad domain + ) { + case 3: + const newurls = await getapiurls(this.info.wellknown); + if (newurls) { + this.info = newurls; + this.serverurls = newurls; + this.userinfo.json.serverurls = this.info; + this.userinfo.updateLocal(); + break; + } + break; - case 4: { - const newurls = await getapiurls( - new URL(this.info.wellknown).origin - ); - if (newurls) { - this.info = newurls; - this.serverurls = newurls; - this.userinfo.json.serverurls = this.info; - this.userinfo.updateLocal(); - break; - } - break; - } - case 5: { - const breakappart = new URL(this.info.wellknown).origin.split("."); - const url = - "https://" + breakappart.at(-2) + "." + breakappart.at(-1); - const newurls = await getapiurls(url); - if (newurls) { - this.info = newurls; - this.serverurls = newurls; - this.userinfo.json.serverurls = this.info; - this.userinfo.updateLocal(); - } - break; - } - } - setTimeout(() => { - if (this.swapped) return; - (document.getElementById("load-desc") as HTMLElement).textContent = - "Retrying..."; - this.initwebsocket().then(() => { - this.loaduser(); - this.init(); - const loading = document.getElementById("loading") as HTMLElement; - loading.classList.add("doneloading"); - loading.classList.remove("loading"); - console.log("done loading"); - }); - }, 200 + this.errorBackoff * 2800); - } else - (document.getElementById("load-desc") as HTMLElement).textContent = - "Unable to connect to the Spacebar server. Please try logging out and back in."; - }); + case 4: { + const newurls = await getapiurls( + new URL(this.info.wellknown).origin + ); + if (newurls) { + this.info = newurls; + this.serverurls = newurls; + this.userinfo.json.serverurls = this.info; + this.userinfo.updateLocal(); + break; + } + break; + } + case 5: { + const breakappart = new URL(this.info.wellknown).origin.split("."); + const url = + "https://" + breakappart.at(-2) + "." + breakappart.at(-1); + const newurls = await getapiurls(url); + if (newurls) { + this.info = newurls; + this.serverurls = newurls; + this.userinfo.json.serverurls = this.info; + this.userinfo.updateLocal(); + } + break; + } + } + setTimeout(() => { + if (this.swapped) return; + (document.getElementById("load-desc") as HTMLElement).textContent = + "Retrying..."; + this.initwebsocket().then(() => { + this.loaduser(); + this.init(); + const loading = document.getElementById("loading") as HTMLElement; + loading.classList.add("doneloading"); + loading.classList.remove("loading"); + console.log("done loading"); + }); + }, 200 + this.errorBackoff * 2800); + } else + (document.getElementById("load-desc") as HTMLElement).textContent = + "Unable to connect to the Spacebar server. Please try logging out and back in."; + }); - await promise; - } - async handleEvent(temp: wsjson) { - console.debug(temp); - if (temp.s) this.lastSequence = temp.s; - if (temp.op == 0) { - switch (temp.t) { - case "MESSAGE_CREATE": - if (this.initialized) { - this.messageCreate(temp); - } - break; - case "MESSAGE_DELETE": { - temp.d.guild_id ??= "@me"; - const channel = this.channelids.get(temp.d.channel_id); - if (!channel) break; - const message = channel.messages.get(temp.d.id); - if (!message) break; - message.deleteEvent(); - break; - } - case "READY": - this.gottenReady(temp as readyjson); - break; - case "MESSAGE_UPDATE": { - temp.d.guild_id ??= "@me"; - const channel = this.channelids.get(temp.d.channel_id); - if (!channel) break; - const message = channel.messages.get(temp.d.id); - if (!message) break; - message.giveData(temp.d); - break; - } - case "TYPING_START": - if (this.initialized) { - this.typingStart(temp); - } - break; - case "USER_UPDATE": - if (this.initialized) { - const users = this.userMap.get(temp.d.id); - if (users) { - users.userupdate(temp.d); - } - } - break; - case "CHANNEL_UPDATE": - if (this.initialized) { - this.updateChannel(temp.d); - } - break; - case "CHANNEL_CREATE": - if (this.initialized) { - this.createChannel(temp.d); - } - break; - case "CHANNEL_DELETE": - if (this.initialized) { - this.delChannel(temp.d); - } - break; - case "GUILD_DELETE": { - const guildy = this.guildids.get(temp.d.id); - if (guildy) { - this.guildids.delete(temp.d.id); - this.guilds.splice(this.guilds.indexOf(guildy), 1); - guildy.html.remove(); - } - break; - } - case "GUILD_CREATE": { - const guildy = new Guild(temp.d, this, this.user); - this.guilds.push(guildy); - this.guildids.set(guildy.id, guildy); - (document.getElementById("servers") as HTMLDivElement).insertBefore( - guildy.generateGuildIcon(), - document.getElementById("bottomseparator") - ); - break; - } - case "MESSAGE_REACTION_ADD": - { - temp.d.guild_id ??= "@me"; - const guild = this.guildids.get(temp.d.guild_id); - if (!guild) break; - const channel = this.channelids.get(temp.d.channel_id); - if (!channel) break; - const message = channel.messages.get(temp.d.message_id); - if (!message) break; - let thing: Member | { id: string }; - if (temp.d.member) { - thing = (await Member.new(temp.d.member, guild)) as Member; - } else { - thing = { id: temp.d.user_id }; - } - message.reactionAdd(temp.d.emoji, thing); - } - break; - case "MESSAGE_REACTION_REMOVE": - { - temp.d.guild_id ??= "@me"; - const channel = this.channelids.get(temp.d.channel_id); - if (!channel) break; - const message = channel.messages.get(temp.d.message_id); - if (!message) break; - message.reactionRemove(temp.d.emoji, temp.d.user_id); - } - break; - case "MESSAGE_REACTION_REMOVE_ALL": - { - temp.d.guild_id ??= "@me"; - const channel = this.channelids.get(temp.d.channel_id); - if (!channel) break; - const message = channel.messages.get(temp.d.message_id); - if (!message) break; - message.reactionRemoveAll(); - } - break; - case "MESSAGE_REACTION_REMOVE_EMOJI": - { - temp.d.guild_id ??= "@me"; - const channel = this.channelids.get(temp.d.channel_id); - if (!channel) break; - const message = channel.messages.get(temp.d.message_id); - if (!message) break; - message.reactionRemoveEmoji(temp.d.emoji); - } - break; - case "GUILD_MEMBERS_CHUNK": - this.gotChunk(temp.d); - break; - } - } else if (temp.op === 10) { - if (!this.ws) return; - console.log("heartbeat down"); - this.heartbeat_interval = temp.d.heartbeat_interval; - this.ws.send(JSON.stringify({ op: 1, d: this.lastSequence })); - } else if (temp.op === 11) { - setTimeout((_: any) => { - if (!this.ws) return; - if (this.connectionSucceed === 0) this.connectionSucceed = Date.now(); - this.ws.send(JSON.stringify({ op: 1, d: this.lastSequence })); - }, this.heartbeat_interval); - } - } - heartbeat_interval: number = 0; - updateChannel(json: channeljson): void { - const guild = this.guildids.get(json.guild_id); - if (guild) { - guild.updateChannel(json); - if (json.guild_id === this.lookingguild?.id) { - this.loadGuild(json.guild_id); - } - } - } - createChannel(json: channeljson): undefined | Channel { - json.guild_id ??= "@me"; - const guild = this.guildids.get(json.guild_id); - if (!guild) return; - const channel = guild.createChannelpac(json); - if (json.guild_id === this.lookingguild?.id) { - this.loadGuild(json.guild_id); - } - if (channel.id === this.gotoid) { - guild.loadGuild(); - guild.loadChannel(channel.id); - this.gotoid = undefined; - } - return channel; // Add this line to return the 'channel' variable - } - gotoid: string | undefined; - async goToChannel(id: string) { - const channel = this.channelids.get(id); - if (channel) { - const guild = channel.guild; - guild.loadGuild(); - guild.loadChannel(id); - } else { - this.gotoid = id; - } - } - delChannel(json: channeljson): void { - let guild_id = json.guild_id; - guild_id ??= "@me"; - const guild = this.guildids.get(guild_id); - if (guild) { - guild.delChannel(json); - } + await promise; + } + async handleEvent(temp: wsjson) { + console.debug(temp); + if (temp.s) this.lastSequence = temp.s; + if (temp.op == 0) { + switch (temp.t) { + case "MESSAGE_CREATE": + if (this.initialized) { + this.messageCreate(temp); + } + break; + case "MESSAGE_DELETE": { + temp.d.guild_id ??= "@me"; + const channel = this.channelids.get(temp.d.channel_id); + if (!channel) break; + const message = channel.messages.get(temp.d.id); + if (!message) break; + message.deleteEvent(); + break; + } + case "READY": + this.gottenReady(temp as readyjson); + break; + case "MESSAGE_UPDATE": { + temp.d.guild_id ??= "@me"; + const channel = this.channelids.get(temp.d.channel_id); + if (!channel) break; + const message = channel.messages.get(temp.d.id); + if (!message) break; + message.giveData(temp.d); + break; + } + case "TYPING_START": + if (this.initialized) { + this.typingStart(temp); + } + break; + case "USER_UPDATE": + if (this.initialized) { + const users = this.userMap.get(temp.d.id); + if (users) { + users.userupdate(temp.d); + } + } + break; + case "CHANNEL_UPDATE": + if (this.initialized) { + this.updateChannel(temp.d); + } + break; + case "CHANNEL_CREATE": + if (this.initialized) { + this.createChannel(temp.d); + } + break; + case "CHANNEL_DELETE": + if (this.initialized) { + this.delChannel(temp.d); + } + break; + case "GUILD_DELETE": { + const guildy = this.guildids.get(temp.d.id); + if (guildy) { + this.guildids.delete(temp.d.id); + this.guilds.splice(this.guilds.indexOf(guildy), 1); + guildy.html.remove(); + } + break; + } + case "GUILD_CREATE": { + const guildy = new Guild(temp.d, this, this.user); + this.guilds.push(guildy); + this.guildids.set(guildy.id, guildy); + (document.getElementById("servers") as HTMLDivElement).insertBefore( + guildy.generateGuildIcon(), + document.getElementById("bottomseparator") + ); + break; + } + case "MESSAGE_REACTION_ADD": + { + temp.d.guild_id ??= "@me"; + const guild = this.guildids.get(temp.d.guild_id); + if (!guild) break; + const channel = this.channelids.get(temp.d.channel_id); + if (!channel) break; + const message = channel.messages.get(temp.d.message_id); + if (!message) break; + let thing: Member | { id: string }; + if (temp.d.member) { + thing = (await Member.new(temp.d.member, guild)) as Member; + } else { + thing = { id: temp.d.user_id }; + } + message.reactionAdd(temp.d.emoji, thing); + } + break; + case "MESSAGE_REACTION_REMOVE": + { + temp.d.guild_id ??= "@me"; + const channel = this.channelids.get(temp.d.channel_id); + if (!channel) break; + const message = channel.messages.get(temp.d.message_id); + if (!message) break; + message.reactionRemove(temp.d.emoji, temp.d.user_id); + } + break; + case "MESSAGE_REACTION_REMOVE_ALL": + { + temp.d.guild_id ??= "@me"; + const channel = this.channelids.get(temp.d.channel_id); + if (!channel) break; + const message = channel.messages.get(temp.d.message_id); + if (!message) break; + message.reactionRemoveAll(); + } + break; + case "MESSAGE_REACTION_REMOVE_EMOJI": + { + temp.d.guild_id ??= "@me"; + const channel = this.channelids.get(temp.d.channel_id); + if (!channel) break; + const message = channel.messages.get(temp.d.message_id); + if (!message) break; + message.reactionRemoveEmoji(temp.d.emoji); + } + break; + case "GUILD_MEMBERS_CHUNK": + this.gotChunk(temp.d); + break; + } + } else if (temp.op === 10) { + if (!this.ws) return; + console.log("heartbeat down"); + this.heartbeat_interval = temp.d.heartbeat_interval; + this.ws.send(JSON.stringify({ op: 1, d: this.lastSequence })); + } else if (temp.op === 11) { + setTimeout((_: any) => { + if (!this.ws) return; + if (this.connectionSucceed === 0) this.connectionSucceed = Date.now(); + this.ws.send(JSON.stringify({ op: 1, d: this.lastSequence })); + }, this.heartbeat_interval); + } + } + heartbeat_interval: number = 0; + updateChannel(json: channeljson): void { + const guild = this.guildids.get(json.guild_id); + if (guild) { + guild.updateChannel(json); + if (json.guild_id === this.lookingguild?.id) { + this.loadGuild(json.guild_id); + } + } + } + createChannel(json: channeljson): undefined | Channel { + json.guild_id ??= "@me"; + const guild = this.guildids.get(json.guild_id); + if (!guild) return; + const channel = guild.createChannelpac(json); + if (json.guild_id === this.lookingguild?.id) { + this.loadGuild(json.guild_id); + } + if (channel.id === this.gotoid) { + guild.loadGuild(); + guild.loadChannel(channel.id); + this.gotoid = undefined; + } + return channel; // Add this line to return the 'channel' variable + } + gotoid: string | undefined; + async goToChannel(id: string) { + const channel = this.channelids.get(id); + if (channel) { + const guild = channel.guild; + guild.loadGuild(); + guild.loadChannel(id); + } else { + this.gotoid = id; + } + } + delChannel(json: channeljson): void { + let guild_id = json.guild_id; + guild_id ??= "@me"; + const guild = this.guildids.get(guild_id); + if (guild) { + guild.delChannel(json); + } - if (json.guild_id === this.lookingguild?.id) { - this.loadGuild(json.guild_id); - } - } - init(): void { - const location = window.location.href.split("/"); - this.buildservers(); - if (location[3] === "channels") { - const guild = this.loadGuild(location[4]); - if (!guild) { - return; - } - guild.loadChannel(location[5]); - this.channelfocus = this.channelids.get(location[5]); - } - } - loaduser(): void { - (document.getElementById("username") as HTMLSpanElement).textContent = - this.user.username; - (document.getElementById("userpfp") as HTMLImageElement).src = - this.user.getpfpsrc(); - (document.getElementById("status") as HTMLSpanElement).textContent = - this.status; - } - isAdmin(): boolean { - if (this.lookingguild) { - return this.lookingguild.isAdmin(); - } else { - return false; - } - } - loadGuild(id: string): Guild | undefined { - let guild = this.guildids.get(id); - if (!guild) { - guild = this.guildids.get("@me"); - } - if (this.lookingguild === guild) { - return guild; - } - if (this.channelfocus) { - this.channelfocus.infinite.delete(); - this.channelfocus = undefined; - } - if (this.lookingguild) { - this.lookingguild.html.classList.remove("serveropen"); - } + if (json.guild_id === this.lookingguild?.id) { + this.loadGuild(json.guild_id); + } + } + init(): void { + const location = window.location.href.split("/"); + this.buildservers(); + if (location[3] === "channels") { + const guild = this.loadGuild(location[4]); + if (!guild) { + return; + } + guild.loadChannel(location[5]); + this.channelfocus = this.channelids.get(location[5]); + } + } + loaduser(): void { + (document.getElementById("username") as HTMLSpanElement).textContent = + this.user.username; + (document.getElementById("userpfp") as HTMLImageElement).src = + this.user.getpfpsrc(); + (document.getElementById("status") as HTMLSpanElement).textContent = + this.status; + } + isAdmin(): boolean { + if (this.lookingguild) { + return this.lookingguild.isAdmin(); + } else { + return false; + } + } + loadGuild(id: string): Guild | undefined { + let guild = this.guildids.get(id); + if (!guild) { + guild = this.guildids.get("@me"); + } + if (this.lookingguild === guild) { + return guild; + } + if (this.channelfocus) { + this.channelfocus.infinite.delete(); + this.channelfocus = undefined; + } + if (this.lookingguild) { + this.lookingguild.html.classList.remove("serveropen"); + } - if (!guild) return; - if (guild.html) { - guild.html.classList.add("serveropen"); - } - this.lookingguild = guild; - (document.getElementById("serverName") as HTMLElement).textContent = - guild.properties.name; - //console.log(this.guildids,id) - const channels = document.getElementById("channels") as HTMLDivElement; - channels.innerHTML = ""; - const html = guild.getHTML(); - channels.appendChild(html); - return guild; - } - buildservers(): void { - const serverlist = document.getElementById("servers") as HTMLDivElement; // - const outdiv = document.createElement("div"); - const home: any = document.createElement("span"); - const div = document.createElement("div"); - div.classList.add("home", "servericon"); + if (!guild) return; + if (guild.html) { + guild.html.classList.add("serveropen"); + } + this.lookingguild = guild; + (document.getElementById("serverName") as HTMLElement).textContent = + guild.properties.name; + //console.log(this.guildids,id) + const channels = document.getElementById("channels") as HTMLDivElement; + channels.innerHTML = ""; + const html = guild.getHTML(); + channels.appendChild(html); + return guild; + } + buildservers(): void { + const serverlist = document.getElementById("servers") as HTMLDivElement; // + const outdiv = document.createElement("div"); + const home: any = document.createElement("span"); + const div = document.createElement("div"); + div.classList.add("home", "servericon"); - home.classList.add("svgtheme", "svgicon", "svg-home"); - home["all"] = this.guildids.get("@me"); - (this.guildids.get("@me") as Guild).html = outdiv; - const unread = document.createElement("div"); - unread.classList.add("unread"); - outdiv.append(unread); - outdiv.append(div); - div.appendChild(home); + home.classList.add("svgtheme", "svgicon", "svg-home"); + home["all"] = this.guildids.get("@me"); + (this.guildids.get("@me") as Guild).html = outdiv; + const unread = document.createElement("div"); + unread.classList.add("unread"); + outdiv.append(unread); + outdiv.append(div); + div.appendChild(home); - outdiv.classList.add("servernoti"); - serverlist.append(outdiv); - home.onclick = function () { - this["all"].loadGuild(); - this["all"].loadChannel(); - }; - const sentdms = document.createElement("div"); - sentdms.classList.add("sentdms"); - serverlist.append(sentdms); - sentdms.id = "sentdms"; + outdiv.classList.add("servernoti"); + serverlist.append(outdiv); + home.onclick = function () { + this["all"].loadGuild(); + this["all"].loadChannel(); + }; + const sentdms = document.createElement("div"); + sentdms.classList.add("sentdms"); + serverlist.append(sentdms); + sentdms.id = "sentdms"; - const br = document.createElement("hr"); - br.classList.add("lightbr"); - serverlist.appendChild(br); - for (const thing of this.guilds) { - if (thing instanceof Direct) { - (thing as Direct).unreaddms(); - continue; - } - const divy = thing.generateGuildIcon(); - serverlist.append(divy); - } - { - const br = document.createElement("hr"); - br.classList.add("lightbr"); - serverlist.appendChild(br); - br.id = "bottomseparator"; + const br = document.createElement("hr"); + br.classList.add("lightbr"); + serverlist.appendChild(br); + for (const thing of this.guilds) { + if (thing instanceof Direct) { + (thing as Direct).unreaddms(); + continue; + } + const divy = thing.generateGuildIcon(); + serverlist.append(divy); + } + { + const br = document.createElement("hr"); + br.classList.add("lightbr"); + serverlist.appendChild(br); + br.id = "bottomseparator"; - const div = document.createElement("div"); - div.textContent = "+"; - div.classList.add("home", "servericon"); - serverlist.appendChild(div); - div.onclick = (_) => { - this.createGuild(); - }; - const guilddsdiv = document.createElement("div"); - const guildDiscoveryContainer = document.createElement("span"); - guildDiscoveryContainer.classList.add( - "svgtheme", - "svgicon", - "svg-explore" - ); - guilddsdiv.classList.add("home", "servericon"); - guilddsdiv.appendChild(guildDiscoveryContainer); - serverlist.appendChild(guilddsdiv); - guildDiscoveryContainer.addEventListener("click", () => { - this.guildDiscovery(); - }); - } - this.unreads(); - } - createGuild() { - let inviteurl = ""; - const error = document.createElement("span"); - const fields: { name: string; icon: string | null } = { - name: "", - icon: null, - }; - const full = new Dialog([ - "tabs", - [ - [ - "Join using invite", - [ - "vdiv", - [ - "textbox", - "Invite Link/Code", - "", - function (this: HTMLInputElement) { - inviteurl = this.value; - }, - ], - ["html", error], - [ - "button", - "", - "Submit", - (_: any) => { - let parsed = ""; - if (inviteurl.includes("/")) { - parsed = - inviteurl.split("/")[inviteurl.split("/").length - 1]; - } else { - parsed = inviteurl; - } - fetch(this.info.api + "/invites/" + parsed, { - method: "POST", - headers: this.headers, - }) - .then((r) => r.json()) - .then((_) => { - if (_.message) { - error.textContent = _.message; - } - }); - }, - ], - ], - ], - [ - "Create Guild", - [ - "vdiv", - ["title", "Create a guild"], - [ - "fileupload", - "Icon:", - function (event: Event) { - const target = event.target as HTMLInputElement; - if (!target.files) return; - const reader = new FileReader(); - reader.readAsDataURL(target.files[0]); - reader.onload = () => { - fields.icon = reader.result as string; - }; - }, - ], - [ - "textbox", - "Name:", - "", - function (this: HTMLInputElement, event: Event) { - const target = event.target as HTMLInputElement; - fields.name = target.value; - }, - ], - [ - "button", - "", - "submit", - () => { - this.makeGuild(fields).then((_) => { - if (_.message) { - alert(_.errors.name._errors[0].message); - } else { - full.hide(); - } - }); - }, - ], - ], - ], - ], - ]); - full.show(); - } - async makeGuild(fields: { name: string; icon: string | null }) { - return await ( - await fetch(this.info.api + "/guilds", { - method: "POST", - headers: this.headers, - body: JSON.stringify(fields), - }) - ).json(); - } - async guildDiscovery() { - const content = document.createElement("div"); - content.classList.add("guildy"); - content.textContent = "Loading..."; - const full = new Dialog(["html", content]); - full.show(); + const div = document.createElement("div"); + div.textContent = "+"; + div.classList.add("home", "servericon"); + serverlist.appendChild(div); + div.onclick = (_) => { + this.createGuild(); + }; + const guilddsdiv = document.createElement("div"); + const guildDiscoveryContainer = document.createElement("span"); + guildDiscoveryContainer.classList.add( + "svgtheme", + "svgicon", + "svg-explore" + ); + guilddsdiv.classList.add("home", "servericon"); + guilddsdiv.appendChild(guildDiscoveryContainer); + serverlist.appendChild(guilddsdiv); + guildDiscoveryContainer.addEventListener("click", () => { + this.guildDiscovery(); + }); + } + this.unreads(); + } + createGuild() { + let inviteurl = ""; + const error = document.createElement("span"); + const fields: { name: string; icon: string | null } = { + name: "", + icon: null, + }; + const full = new Dialog([ + "tabs", + [ + [ + "Join using invite", + [ + "vdiv", + [ + "textbox", + "Invite Link/Code", + "", + function (this: HTMLInputElement) { + inviteurl = this.value; + }, + ], + ["html", error], + [ + "button", + "", + "Submit", + (_: any) => { + let parsed = ""; + if (inviteurl.includes("/")) { + parsed = + inviteurl.split("/")[inviteurl.split("/").length - 1]; + } else { + parsed = inviteurl; + } + fetch(this.info.api + "/invites/" + parsed, { + method: "POST", + headers: this.headers, + }) + .then((r) => r.json()) + .then((_) => { + if (_.message) { + error.textContent = _.message; + } + }); + }, + ], + ], + ], + [ + "Create Guild", + [ + "vdiv", + ["title", "Create a guild"], + [ + "fileupload", + "Icon:", + function (event: Event) { + const target = event.target as HTMLInputElement; + if (!target.files) return; + const reader = new FileReader(); + reader.readAsDataURL(target.files[0]); + reader.onload = () => { + fields.icon = reader.result as string; + }; + }, + ], + [ + "textbox", + "Name:", + "", + function (this: HTMLInputElement, event: Event) { + const target = event.target as HTMLInputElement; + fields.name = target.value; + }, + ], + [ + "button", + "", + "submit", + () => { + this.makeGuild(fields).then((_) => { + if (_.message) { + alert(_.errors.name._errors[0].message); + } else { + full.hide(); + } + }); + }, + ], + ], + ], + ], + ]); + full.show(); + } + async makeGuild(fields: { name: string; icon: string | null }) { + return await ( + await fetch(this.info.api + "/guilds", { + method: "POST", + headers: this.headers, + body: JSON.stringify(fields), + }) + ).json(); + } + async guildDiscovery() { + const content = document.createElement("div"); + content.classList.add("guildy"); + content.textContent = "Loading..."; + const full = new Dialog(["html", content]); + full.show(); - const res = await fetch(this.info.api + "/discoverable-guilds?limit=50", { - headers: this.headers, - }); - const json = await res.json(); + const res = await fetch(this.info.api + "/discoverable-guilds?limit=50", { + headers: this.headers, + }); + const json = await res.json(); - content.innerHTML = ""; - const title = document.createElement("h2"); - title.textContent = "Guild discovery (" + json.total + " entries)"; - content.appendChild(title); + content.innerHTML = ""; + const title = document.createElement("h2"); + title.textContent = "Guild discovery (" + json.total + " entries)"; + content.appendChild(title); - const guilds = document.createElement("div"); - guilds.id = "discovery-guild-content"; + const guilds = document.createElement("div"); + guilds.id = "discovery-guild-content"; - json.guilds.forEach((guild: guildjson["properties"]) => { - const content = document.createElement("div"); - content.classList.add("discovery-guild"); + json.guilds.forEach((guild: guildjson["properties"]) => { + const content = document.createElement("div"); + content.classList.add("discovery-guild"); - if (guild.banner) { - const banner = document.createElement("img"); - banner.classList.add("banner"); - banner.crossOrigin = "anonymous"; - banner.src = - this.info.cdn + - "/icons/" + - guild.id + - "/" + - guild.banner + - ".png?size=256"; - banner.alt = ""; - content.appendChild(banner); - } + if (guild.banner) { + const banner = document.createElement("img"); + banner.classList.add("banner"); + banner.crossOrigin = "anonymous"; + banner.src = + this.info.cdn + + "/icons/" + + guild.id + + "/" + + guild.banner + + ".png?size=256"; + banner.alt = ""; + content.appendChild(banner); + } - const nameContainer = document.createElement("div"); - nameContainer.classList.add("flex"); - const img = document.createElement("img"); - img.classList.add("icon"); - img.crossOrigin = "anonymous"; - img.src = - this.info.cdn + - (guild.icon - ? "/icons/" + guild.id + "/" + guild.icon + ".png?size=48" - : "/embed/avatars/3.png"); - img.alt = ""; - nameContainer.appendChild(img); + const nameContainer = document.createElement("div"); + nameContainer.classList.add("flex"); + const img = document.createElement("img"); + img.classList.add("icon"); + img.crossOrigin = "anonymous"; + img.src = + this.info.cdn + + (guild.icon + ? "/icons/" + guild.id + "/" + guild.icon + ".png?size=48" + : "/embed/avatars/3.png"); + img.alt = ""; + nameContainer.appendChild(img); - const name = document.createElement("h3"); - name.textContent = guild.name; - nameContainer.appendChild(name); - content.appendChild(nameContainer); - const desc = document.createElement("p"); - desc.textContent = guild.description; - content.appendChild(desc); + const name = document.createElement("h3"); + name.textContent = guild.name; + nameContainer.appendChild(name); + content.appendChild(nameContainer); + const desc = document.createElement("p"); + desc.textContent = guild.description; + content.appendChild(desc); - content.addEventListener("click", async () => { - const joinRes = await fetch( - this.info.api + "/guilds/" + guild.id + "/members/@me", - { - method: "PUT", - headers: this.headers, - } - ); - if (joinRes.ok) full.hide(); - }); - guilds.appendChild(content); - }); - content.appendChild(guilds); - } - messageCreate(messagep: messageCreateJson): void { - messagep.d.guild_id ??= "@me"; - const channel = this.channelids.get(messagep.d.channel_id); - if (channel) { - channel.messageCreate(messagep); - this.unreads(); - } - } - unreads(): void { - for (const thing of this.guilds) { - if (thing.id === "@me") { - continue; - } - const html = this.guildhtml.get(thing.id); - thing.unreads(html); - } - } - async typingStart(typing: startTypingjson): Promise { - const channel = this.channelids.get(typing.d.channel_id); - if (!channel) return; - channel.typingStart(typing); - } - updatepfp(file: Blob): void { - const reader = new FileReader(); - reader.readAsDataURL(file); - reader.onload = () => { - fetch(this.info.api + "/users/@me", { - method: "PATCH", - headers: this.headers, - body: JSON.stringify({ - avatar: reader.result, - }), - }); - }; - } - updatebanner(file: Blob | null): void { - if (file) { - const reader = new FileReader(); - reader.readAsDataURL(file); - reader.onload = () => { - fetch(this.info.api + "/users/@me", { - method: "PATCH", - headers: this.headers, - body: JSON.stringify({ - banner: reader.result, - }), - }); - }; - } else { - fetch(this.info.api + "/users/@me", { - method: "PATCH", - headers: this.headers, - body: JSON.stringify({ - banner: null, - }), - }); - } - } - updateProfile(json: { - bio?: string; - pronouns?: string; - accent_color?: number; - }) { - fetch(this.info.api + "/users/@me/profile", { - method: "PATCH", - headers: this.headers, - body: JSON.stringify(json), - }); - } - async showusersettings() { - const settings = new Settings("Settings"); - { - const userOptions = settings.addButton("User Settings", { ltr: true }); - const hypotheticalProfile = document.createElement("div"); - let file: undefined | File | null; - let newpronouns: string | undefined; - let newbio: string | undefined; - const hypouser = this.user.clone(); - let color: string; - async function regen() { - hypotheticalProfile.textContent = ""; - const hypoprofile = await hypouser.buildprofile(-1, -1); + content.addEventListener("click", async () => { + const joinRes = await fetch( + this.info.api + "/guilds/" + guild.id + "/members/@me", + { + method: "PUT", + headers: this.headers, + } + ); + if (joinRes.ok) full.hide(); + }); + guilds.appendChild(content); + }); + content.appendChild(guilds); + } + messageCreate(messagep: messageCreateJson): void { + messagep.d.guild_id ??= "@me"; + const channel = this.channelids.get(messagep.d.channel_id); + if (channel) { + channel.messageCreate(messagep); + this.unreads(); + } + } + unreads(): void { + for (const thing of this.guilds) { + if (thing.id === "@me") { + continue; + } + const html = this.guildhtml.get(thing.id); + thing.unreads(html); + } + } + async typingStart(typing: startTypingjson): Promise { + const channel = this.channelids.get(typing.d.channel_id); + if (!channel) return; + channel.typingStart(typing); + } + updatepfp(file: Blob): void { + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = () => { + fetch(this.info.api + "/users/@me", { + method: "PATCH", + headers: this.headers, + body: JSON.stringify({ + avatar: reader.result, + }), + }); + }; + } + updatebanner(file: Blob | null): void { + if (file) { + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = () => { + fetch(this.info.api + "/users/@me", { + method: "PATCH", + headers: this.headers, + body: JSON.stringify({ + banner: reader.result, + }), + }); + }; + } else { + fetch(this.info.api + "/users/@me", { + method: "PATCH", + headers: this.headers, + body: JSON.stringify({ + banner: null, + }), + }); + } + } + updateProfile(json: { + bio?: string; + pronouns?: string; + accent_color?: number; + }) { + fetch(this.info.api + "/users/@me/profile", { + method: "PATCH", + headers: this.headers, + body: JSON.stringify(json), + }); + } + async showusersettings() { + const settings = new Settings("Settings"); + { + const userOptions = settings.addButton("User Settings", { ltr: true }); + const hypotheticalProfile = document.createElement("div"); + let file: undefined | File | null; + let newpronouns: string | undefined; + let newbio: string | undefined; + const hypouser = this.user.clone(); + let color: string; + async function regen() { + hypotheticalProfile.textContent = ""; + const hypoprofile = await hypouser.buildprofile(-1, -1); - hypotheticalProfile.appendChild(hypoprofile); - } - regen(); - const settingsLeft = userOptions.addOptions(""); - const settingsRight = userOptions.addOptions(""); - settingsRight.addHTMLArea(hypotheticalProfile); + hypotheticalProfile.appendChild(hypoprofile); + } + regen(); + const settingsLeft = userOptions.addOptions(""); + const settingsRight = userOptions.addOptions(""); + settingsRight.addHTMLArea(hypotheticalProfile); - const finput = settingsLeft.addFileInput( - "Upload pfp:", - (_) => { - if (file) { - this.updatepfp(file); - } - }, - { clear: true } - ); - finput.watchForChange((_) => { - if (!_) { - file = null; - hypouser.avatar = null; - hypouser.hypotheticalpfp = true; - regen(); - return; - } - if (_.length) { - file = _[0]; - const blob = URL.createObjectURL(file); - hypouser.avatar = blob; - hypouser.hypotheticalpfp = true; - regen(); - } - }); - let bfile: undefined | File | null; - const binput = settingsLeft.addFileInput( - "Upload banner:", - (_) => { - if (bfile !== undefined) { - this.updatebanner(bfile); - } - }, - { clear: true } - ); - binput.watchForChange((_) => { - if (!_) { - bfile = null; - hypouser.banner = undefined; - hypouser.hypotheticalbanner = true; - regen(); - return; - } - if (_.length) { - bfile = _[0]; - const blob = URL.createObjectURL(bfile); - hypouser.banner = blob; - hypouser.hypotheticalbanner = true; - regen(); - } - }); - let changed = false; - const pronounbox = settingsLeft.addTextInput( - "Pronouns", - (_) => { - if (newpronouns || newbio || changed) { - this.updateProfile({ - pronouns: newpronouns, - bio: newbio, - accent_color: Number.parseInt("0x" + color.substr(1), 16), - }); - } - }, - { initText: this.user.pronouns } - ); - pronounbox.watchForChange((_) => { - hypouser.pronouns = _; - newpronouns = _; - regen(); - }); - const bioBox = settingsLeft.addMDInput("Bio:", (_) => {}, { - initText: this.user.bio.rawString, - }); - bioBox.watchForChange((_) => { - newbio = _; - hypouser.bio = new MarkDown(_, this); - regen(); - }); + const finput = settingsLeft.addFileInput( + "Upload pfp:", + (_) => { + if (file) { + this.updatepfp(file); + } + }, + { clear: true } + ); + finput.watchForChange((_) => { + if (!_) { + file = null; + hypouser.avatar = null; + hypouser.hypotheticalpfp = true; + regen(); + return; + } + if (_.length) { + file = _[0]; + const blob = URL.createObjectURL(file); + hypouser.avatar = blob; + hypouser.hypotheticalpfp = true; + regen(); + } + }); + let bfile: undefined | File | null; + const binput = settingsLeft.addFileInput( + "Upload banner:", + (_) => { + if (bfile !== undefined) { + this.updatebanner(bfile); + } + }, + { clear: true } + ); + binput.watchForChange((_) => { + if (!_) { + bfile = null; + hypouser.banner = undefined; + hypouser.hypotheticalbanner = true; + regen(); + return; + } + if (_.length) { + bfile = _[0]; + const blob = URL.createObjectURL(bfile); + hypouser.banner = blob; + hypouser.hypotheticalbanner = true; + regen(); + } + }); + let changed = false; + const pronounbox = settingsLeft.addTextInput( + "Pronouns", + (_) => { + if (newpronouns || newbio || changed) { + this.updateProfile({ + pronouns: newpronouns, + bio: newbio, + accent_color: Number.parseInt("0x" + color.substr(1), 16), + }); + } + }, + { initText: this.user.pronouns } + ); + pronounbox.watchForChange((_) => { + hypouser.pronouns = _; + newpronouns = _; + regen(); + }); + const bioBox = settingsLeft.addMDInput("Bio:", (_) => {}, { + initText: this.user.bio.rawString, + }); + bioBox.watchForChange((_) => { + newbio = _; + hypouser.bio = new MarkDown(_, this); + regen(); + }); - if (this.user.accent_color) { - color = "#" + this.user.accent_color.toString(16); - } else { - color = "transparent"; - } - const colorPicker = settingsLeft.addColorInput( - "Profile color", - (_) => {}, - { initColor: color } - ); - colorPicker.watchForChange((_) => { - console.log(); - color = _; - hypouser.accent_color = Number.parseInt("0x" + _.substr(1), 16); - changed = true; - regen(); - }); - } - { - const tas = settings.addButton("Themes & sounds"); - { - const themes = ["Dark", "WHITE", "Light"]; - tas.addSelect( - "Theme:", - (_) => { - localStorage.setItem("theme", themes[_]); - setTheme(); - }, - themes, - { - defaultIndex: themes.indexOf( - localStorage.getItem("theme") as string - ), - } - ); - } - { - const sounds = Voice.sounds; - tas - .addSelect( - "Notification sound:", - (_) => { - Voice.setNotificationSound(sounds[_]); - }, - sounds, - { defaultIndex: sounds.indexOf(Voice.getNotificationSound()) } - ) - .watchForChange((_) => { - Voice.noises(sounds[_]); - }); - } + if (this.user.accent_color) { + color = "#" + this.user.accent_color.toString(16); + } else { + color = "transparent"; + } + const colorPicker = settingsLeft.addColorInput( + "Profile color", + (_) => {}, + { initColor: color } + ); + colorPicker.watchForChange((_) => { + console.log(); + color = _; + hypouser.accent_color = Number.parseInt("0x" + _.substr(1), 16); + changed = true; + regen(); + }); + } + { + const tas = settings.addButton("Themes & sounds"); + { + const themes = ["Dark", "WHITE", "Light"]; + tas.addSelect( + "Theme:", + (_) => { + localStorage.setItem("theme", themes[_]); + setTheme(); + }, + themes, + { + defaultIndex: themes.indexOf( + localStorage.getItem("theme") as string + ), + } + ); + } + { + const sounds = Voice.sounds; + tas + .addSelect( + "Notification sound:", + (_) => { + Voice.setNotificationSound(sounds[_]); + }, + sounds, + { defaultIndex: sounds.indexOf(Voice.getNotificationSound()) } + ) + .watchForChange((_) => { + Voice.noises(sounds[_]); + }); + } - { - const userinfos = getBulkInfo(); - tas.addColorInput( - "Accent color:", - (_) => { - userinfos.accent_color = _; - localStorage.setItem("userinfos", JSON.stringify(userinfos)); - document.documentElement.style.setProperty( - "--accent-color", - userinfos.accent_color - ); - }, - { initColor: userinfos.accent_color } - ); - } - } - { - const security = settings.addButton("Account Settings"); - const genSecurity = () => { - security.removeAll(); - if (this.mfa_enabled) { - security.addButtonInput("", "Disable 2FA", () => { - const form = security.addSubForm( - "2FA Disable", - (_: any) => { - if (_.message) { - switch (_.code) { - case 60008: - form.error("code", "Invalid code"); - break; - } - } else { - this.mfa_enabled = false; - security.returnFromSub(); - genSecurity(); - } - }, - { - fetchURL: this.info.api + "/users/@me/mfa/totp/disable", - headers: this.headers, - } - ); - form.addTextInput("Code:", "code", { required: true }); - }); - } else { - security.addButtonInput("", "Enable 2FA", async () => { - let secret = ""; - for (let i = 0; i < 18; i++) { - secret += "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"[ - Math.floor(Math.random() * 32) - ]; - } - const form = security.addSubForm( - "2FA Setup", - (_: any) => { - if (_.message) { - switch (_.code) { - case 60008: - form.error("code", "Invalid code"); - break; - case 400: - form.error("password", "Incorrect password"); - break; - } - } else { - genSecurity(); - this.mfa_enabled = true; - security.returnFromSub(); - } - }, - { - fetchURL: this.info.api + "/users/@me/mfa/totp/enable/", - headers: this.headers, - } - ); - form.addTitle( - "Copy this secret into your totp(time-based one time password) app" - ); - form.addText( - `Your secret is: ${secret} and it's 6 digits, with a 30 second token period` - ); - form.addTextInput("Account Password:", "password", { - required: true, - password: true, - }); - form.addTextInput("Code:", "code", { required: true }); - form.setValue("secret", secret); - }); - } - security.addButtonInput("", "Change discriminator", () => { - const form = security.addSubForm( - "Change Discriminator", - (_) => { - security.returnFromSub(); - }, - { - fetchURL: this.info.api + "/users/@me/", - headers: this.headers, - method: "PATCH", - } - ); - form.addTextInput("New discriminator:", "discriminator"); - }); - security.addButtonInput("", "Change email", () => { - const form = security.addSubForm( - "Change Email", - (_) => { - security.returnFromSub(); - }, - { - fetchURL: this.info.api + "/users/@me/", - headers: this.headers, - method: "PATCH", - } - ); - form.addTextInput("Password:", "password", { password: true }); - if (this.mfa_enabled) { - form.addTextInput("Code:", "code"); - } - form.addTextInput("New email:", "email"); - }); - security.addButtonInput("", "Change username", () => { - const form = security.addSubForm( - "Change Username", - (_) => { - security.returnFromSub(); - }, - { - fetchURL: this.info.api + "/users/@me/", - headers: this.headers, - method: "PATCH", - } - ); - form.addTextInput("Password:", "password", { password: true }); - if (this.mfa_enabled) { - form.addTextInput("Code:", "code"); - } - form.addTextInput("New username:", "username"); - }); - security.addButtonInput("", "Change password", () => { - const form = security.addSubForm( - "Change Password", - (_) => { - security.returnFromSub(); - }, - { - fetchURL: this.info.api + "/users/@me/", - headers: this.headers, - method: "PATCH", - } - ); - form.addTextInput("Old password:", "password", { password: true }); - if (this.mfa_enabled) { - form.addTextInput("Code:", "code"); - } - let in1 = ""; - let in2 = ""; - form.addTextInput("New password:", "").watchForChange((text) => { - in1 = text; - }); - const copy = form.addTextInput("New password again:", ""); - copy.watchForChange((text) => { - in2 = text; - }); - form.setValue("new_password", () => { - if (in1 === in2) { - return in1; - } else { - throw new FormError(copy, "Passwords don't match"); - } - }); - }); - }; - genSecurity(); - } - { - const connections = settings.addButton("Connections"); - const connectionContainer = document.createElement("div"); - connectionContainer.id = "connection-container"; + { + const userinfos = getBulkInfo(); + tas.addColorInput( + "Accent color:", + (_) => { + userinfos.accent_color = _; + localStorage.setItem("userinfos", JSON.stringify(userinfos)); + document.documentElement.style.setProperty( + "--accent-color", + userinfos.accent_color + ); + }, + { initColor: userinfos.accent_color } + ); + } + } + { + const security = settings.addButton("Account Settings"); + const genSecurity = () => { + security.removeAll(); + if (this.mfa_enabled) { + security.addButtonInput("", "Disable 2FA", () => { + const form = security.addSubForm( + "2FA Disable", + (_: any) => { + if (_.message) { + switch (_.code) { + case 60008: + form.error("code", "Invalid code"); + break; + } + } else { + this.mfa_enabled = false; + security.returnFromSub(); + genSecurity(); + } + }, + { + fetchURL: this.info.api + "/users/@me/mfa/totp/disable", + headers: this.headers, + } + ); + form.addTextInput("Code:", "code", { required: true }); + }); + } else { + security.addButtonInput("", "Enable 2FA", async () => { + let secret = ""; + for (let i = 0; i < 18; i++) { + secret += "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"[ + Math.floor(Math.random() * 32) + ]; + } + const form = security.addSubForm( + "2FA Setup", + (_: any) => { + if (_.message) { + switch (_.code) { + case 60008: + form.error("code", "Invalid code"); + break; + case 400: + form.error("password", "Incorrect password"); + break; + } + } else { + genSecurity(); + this.mfa_enabled = true; + security.returnFromSub(); + } + }, + { + fetchURL: this.info.api + "/users/@me/mfa/totp/enable/", + headers: this.headers, + } + ); + form.addTitle( + "Copy this secret into your totp(time-based one time password) app" + ); + form.addText( + `Your secret is: ${secret} and it's 6 digits, with a 30 second token period` + ); + form.addTextInput("Account Password:", "password", { + required: true, + password: true, + }); + form.addTextInput("Code:", "code", { required: true }); + form.setValue("secret", secret); + }); + } + security.addButtonInput("", "Change discriminator", () => { + const form = security.addSubForm( + "Change Discriminator", + (_) => { + security.returnFromSub(); + }, + { + fetchURL: this.info.api + "/users/@me/", + headers: this.headers, + method: "PATCH", + } + ); + form.addTextInput("New discriminator:", "discriminator"); + }); + security.addButtonInput("", "Change email", () => { + const form = security.addSubForm( + "Change Email", + (_) => { + security.returnFromSub(); + }, + { + fetchURL: this.info.api + "/users/@me/", + headers: this.headers, + method: "PATCH", + } + ); + form.addTextInput("Password:", "password", { password: true }); + if (this.mfa_enabled) { + form.addTextInput("Code:", "code"); + } + form.addTextInput("New email:", "email"); + }); + security.addButtonInput("", "Change username", () => { + const form = security.addSubForm( + "Change Username", + (_) => { + security.returnFromSub(); + }, + { + fetchURL: this.info.api + "/users/@me/", + headers: this.headers, + method: "PATCH", + } + ); + form.addTextInput("Password:", "password", { password: true }); + if (this.mfa_enabled) { + form.addTextInput("Code:", "code"); + } + form.addTextInput("New username:", "username"); + }); + security.addButtonInput("", "Change password", () => { + const form = security.addSubForm( + "Change Password", + (_) => { + security.returnFromSub(); + }, + { + fetchURL: this.info.api + "/users/@me/", + headers: this.headers, + method: "PATCH", + } + ); + form.addTextInput("Old password:", "password", { password: true }); + if (this.mfa_enabled) { + form.addTextInput("Code:", "code"); + } + let in1 = ""; + let in2 = ""; + form.addTextInput("New password:", "").watchForChange((text) => { + in1 = text; + }); + const copy = form.addTextInput("New password again:", ""); + copy.watchForChange((text) => { + in2 = text; + }); + form.setValue("new_password", () => { + if (in1 === in2) { + return in1; + } else { + throw new FormError(copy, "Passwords don't match"); + } + }); + }); + }; + genSecurity(); + } + { + const connections = settings.addButton("Connections"); + const connectionContainer = document.createElement("div"); + connectionContainer.id = "connection-container"; - fetch(this.info.api + "/connections", { - headers: this.headers, - }) - .then((r) => r.json()) - .then((json) => { - Object.keys(json) - .sort((key) => (json[key].enabled ? -1 : 1)) - .forEach((key) => { - const connection = json[key]; + fetch(this.info.api + "/connections", { + headers: this.headers, + }) + .then((r) => r.json()) + .then((json) => { + Object.keys(json) + .sort((key) => (json[key].enabled ? -1 : 1)) + .forEach((key) => { + const connection = json[key]; - const container = document.createElement("div"); - container.textContent = - key.charAt(0).toUpperCase() + key.slice(1); + const container = document.createElement("div"); + container.textContent = + key.charAt(0).toUpperCase() + key.slice(1); - if (connection.enabled) { - container.addEventListener("click", async () => { - const connectionRes = await fetch( - this.info.api + "/connections/" + key + "/authorize", - { - headers: this.headers, - } - ); - const connectionJSON = await connectionRes.json(); - window.open( - connectionJSON.url, - "_blank", - "noopener noreferrer" - ); - }); - } else { - container.classList.add("disabled"); - container.title = - "This connection has been disabled server-side."; - } + if (connection.enabled) { + container.addEventListener("click", async () => { + const connectionRes = await fetch( + this.info.api + "/connections/" + key + "/authorize", + { + headers: this.headers, + } + ); + const connectionJSON = await connectionRes.json(); + window.open( + connectionJSON.url, + "_blank", + "noopener noreferrer" + ); + }); + } else { + container.classList.add("disabled"); + container.title = + "This connection has been disabled server-side."; + } - connectionContainer.appendChild(container); - }); - }); - connections.addHTMLArea(connectionContainer); - } - { - const devPortal = settings.addButton("Developer Portal"); + connectionContainer.appendChild(container); + }); + }); + connections.addHTMLArea(connectionContainer); + } + { + const devPortal = settings.addButton("Developer Portal"); - const teamsRes = await fetch(this.info.api + "/teams", { - headers: this.headers, - }); - const teams = await teamsRes.json(); + const teamsRes = await fetch(this.info.api + "/teams", { + headers: this.headers, + }); + const teams = await teamsRes.json(); - devPortal.addButtonInput("", "Create application", () => { - const form = devPortal.addSubForm( - "Create application", - (json: any) => { - if (json.message) form.error("name", json.message); - else { - devPortal.returnFromSub(); - this.manageApplication(json.id); - } - }, - { - fetchURL: this.info.api + "/applications", - headers: this.headers, - method: "POST", - } - ); + devPortal.addButtonInput("", "Create application", () => { + const form = devPortal.addSubForm( + "Create application", + (json: any) => { + if (json.message) form.error("name", json.message); + else { + devPortal.returnFromSub(); + this.manageApplication(json.id); + } + }, + { + fetchURL: this.info.api + "/applications", + headers: this.headers, + method: "POST", + } + ); - form.addTextInput("Name", "name", { required: true }); - form.addSelect( - "Team", - "team_id", - ["Personal", ...teams.map((team: { name: string }) => team.name)], - { - defaultIndex: 0, - } - ); - }); + form.addTextInput("Name", "name", { required: true }); + form.addSelect( + "Team", + "team_id", + ["Personal", ...teams.map((team: { name: string }) => team.name)], + { + defaultIndex: 0, + } + ); + }); - const appListContainer = document.createElement("div"); - appListContainer.id = "app-list-container"; - fetch(this.info.api + "/applications", { - headers: this.headers, - }) - .then((r) => r.json()) - .then((json) => { - json.forEach( - (application: { - cover_image: any; - icon: any; - id: string | undefined; - name: string | number; - bot: any; - }) => { - const container = document.createElement("div"); + const appListContainer = document.createElement("div"); + appListContainer.id = "app-list-container"; + fetch(this.info.api + "/applications", { + headers: this.headers, + }) + .then((r) => r.json()) + .then((json) => { + json.forEach( + (application: { + cover_image: any; + icon: any; + id: string | undefined; + name: string | number; + bot: any; + }) => { + const container = document.createElement("div"); - if (application.cover_image || application.icon) { - const cover = document.createElement("img"); - cover.crossOrigin = "anonymous"; - cover.src = - this.info.cdn + - "/app-icons/" + - application.id + - "/" + - (application.cover_image || application.icon) + - ".png?size=256"; - cover.alt = ""; - cover.loading = "lazy"; - container.appendChild(cover); - } + if (application.cover_image || application.icon) { + const cover = document.createElement("img"); + cover.crossOrigin = "anonymous"; + cover.src = + this.info.cdn + + "/app-icons/" + + application.id + + "/" + + (application.cover_image || application.icon) + + ".png?size=256"; + cover.alt = ""; + cover.loading = "lazy"; + container.appendChild(cover); + } - const name = document.createElement("h2"); - name.textContent = - application.name + (application.bot ? " (Bot)" : ""); - container.appendChild(name); + const name = document.createElement("h2"); + name.textContent = + application.name + (application.bot ? " (Bot)" : ""); + container.appendChild(name); - container.addEventListener("click", async () => { - this.manageApplication(application.id); - }); - appListContainer.appendChild(container); - } - ); - }); - devPortal.addHTMLArea(appListContainer); - } - settings.show(); - } - async manageApplication(appId = "") { - const res = await fetch(this.info.api + "/applications/" + appId, { - headers: this.headers, - }); - const json = await res.json(); + container.addEventListener("click", async () => { + this.manageApplication(application.id); + }); + appListContainer.appendChild(container); + } + ); + }); + devPortal.addHTMLArea(appListContainer); + } + settings.show(); + } + async manageApplication(appId = "") { + const res = await fetch(this.info.api + "/applications/" + appId, { + headers: this.headers, + }); + const json = await res.json(); - const fields: any = {}; - const appDialog = new Dialog([ - "vdiv", - ["title", "Editing " + json.name], - [ - "vdiv", - [ - "textbox", - "Application name:", - json.name, - (event: Event) => { - const target = event.target as HTMLInputElement; - fields.name = target.value; - }, - ], - [ - "mdbox", - "Description:", - json.description, - (event: Event) => { - const target = event.target as HTMLInputElement; - fields.description = target.value; - }, - ], - [ - "vdiv", - json.icon - ? [ - "img", - this.info.cdn + - "/app-icons/" + - appId + - "/" + - json.icon + - ".png?size=128", - [128, 128], - ] - : ["text", "No icon"], - [ - "fileupload", - "Application icon:", - (event) => { - const reader = new FileReader(); - const files = (event.target as HTMLInputElement).files; - if (files) { - reader.readAsDataURL(files[0]); - reader.onload = () => { - fields.icon = reader.result; - }; - } - }, - ], - ], - ], - [ - "hdiv", - [ - "textbox", - "Privacy policy URL:", - json.privacy_policy_url || "", - (event: Event) => { - const target = event.target as HTMLInputElement; - fields.privacy_policy_url = target.value; - }, - ], - [ - "textbox", - "Terms of Service URL:", - json.terms_of_service_url || "", - (event: Event) => { - const target = event.target as HTMLInputElement; - fields.terms_of_service_url = target.value; - }, - ], - ], - [ - "hdiv", - [ - "checkbox", - "Make bot publicly inviteable?", - json.bot_public, - (event: Event) => { - const target = event.target as HTMLInputElement; - fields.bot_public = target.checked; - }, - ], - [ - "checkbox", - "Require code grant to invite the bot?", - json.bot_require_code_grant, - (event: Event) => { - const target = event.target as HTMLInputElement; - fields.bot_require_code_grant = target.checked; - }, - ], - ], - [ - "hdiv", - [ - "button", - "", - "Save changes", - async () => { - const updateRes = await fetch( - this.info.api + "/applications/" + appId, - { - method: "PATCH", - headers: this.headers, - body: JSON.stringify(fields), - } - ); - if (updateRes.ok) appDialog.hide(); - else { - const updateJSON = await updateRes.json(); - alert("An error occurred: " + updateJSON.message); - } - }, - ], - [ - "button", - "", - (json.bot ? "Manage" : "Add") + " bot", - async () => { - if (!json.bot) { - if ( - !confirm( - "Are you sure you want to add a bot to this application? There's no going back." - ) - ) - return; + const fields: any = {}; + const appDialog = new Dialog([ + "vdiv", + ["title", "Editing " + json.name], + [ + "vdiv", + [ + "textbox", + "Application name:", + json.name, + (event: Event) => { + const target = event.target as HTMLInputElement; + fields.name = target.value; + }, + ], + [ + "mdbox", + "Description:", + json.description, + (event: Event) => { + const target = event.target as HTMLInputElement; + fields.description = target.value; + }, + ], + [ + "vdiv", + json.icon + ? [ + "img", + this.info.cdn + + "/app-icons/" + + appId + + "/" + + json.icon + + ".png?size=128", + [128, 128], + ] + : ["text", "No icon"], + [ + "fileupload", + "Application icon:", + (event) => { + const reader = new FileReader(); + const files = (event.target as HTMLInputElement).files; + if (files) { + reader.readAsDataURL(files[0]); + reader.onload = () => { + fields.icon = reader.result; + }; + } + }, + ], + ], + ], + [ + "hdiv", + [ + "textbox", + "Privacy policy URL:", + json.privacy_policy_url || "", + (event: Event) => { + const target = event.target as HTMLInputElement; + fields.privacy_policy_url = target.value; + }, + ], + [ + "textbox", + "Terms of Service URL:", + json.terms_of_service_url || "", + (event: Event) => { + const target = event.target as HTMLInputElement; + fields.terms_of_service_url = target.value; + }, + ], + ], + [ + "hdiv", + [ + "checkbox", + "Make bot publicly inviteable?", + json.bot_public, + (event: Event) => { + const target = event.target as HTMLInputElement; + fields.bot_public = target.checked; + }, + ], + [ + "checkbox", + "Require code grant to invite the bot?", + json.bot_require_code_grant, + (event: Event) => { + const target = event.target as HTMLInputElement; + fields.bot_require_code_grant = target.checked; + }, + ], + ], + [ + "hdiv", + [ + "button", + "", + "Save changes", + async () => { + const updateRes = await fetch( + this.info.api + "/applications/" + appId, + { + method: "PATCH", + headers: this.headers, + body: JSON.stringify(fields), + } + ); + if (updateRes.ok) appDialog.hide(); + else { + const updateJSON = await updateRes.json(); + alert("An error occurred: " + updateJSON.message); + } + }, + ], + [ + "button", + "", + (json.bot ? "Manage" : "Add") + " bot", + async () => { + if (!json.bot) { + if ( + !confirm( + "Are you sure you want to add a bot to this application? There's no going back." + ) + ) + return; - const updateRes = await fetch( - this.info.api + "/applications/" + appId + "/bot", - { - method: "POST", - headers: this.headers, - } - ); - const updateJSON = await updateRes.json(); - alert("Bot token:\n" + updateJSON.token); - } + const updateRes = await fetch( + this.info.api + "/applications/" + appId + "/bot", + { + method: "POST", + headers: this.headers, + } + ); + const updateJSON = await updateRes.json(); + alert("Bot token:\n" + updateJSON.token); + } - appDialog.hide(); - this.manageBot(appId); - }, - ], - ], - ]); - appDialog.show(); - } - async manageBot(appId = "") { - const res = await fetch(this.info.api + "/applications/" + appId, { - headers: this.headers, - }); - const json = await res.json(); - if (!json.bot) - return alert( - "For some reason, this application doesn't have a bot (yet)." - ); + appDialog.hide(); + this.manageBot(appId); + }, + ], + ], + ]); + appDialog.show(); + } + async manageBot(appId = "") { + const res = await fetch(this.info.api + "/applications/" + appId, { + headers: this.headers, + }); + const json = await res.json(); + if (!json.bot) + return alert( + "For some reason, this application doesn't have a bot (yet)." + ); - const fields: any = { - username: json.bot.username, - avatar: json.bot.avatar - ? this.info.cdn + - "/app-icons/" + - appId + - "/" + - json.bot.avatar + - ".png?size=256" - : "", - }; - const botDialog = new Dialog([ - "vdiv", - ["title", "Editing bot: " + json.bot.username], - [ - "hdiv", - [ - "textbox", - "Bot username:", - json.bot.username, - (event: Event) => { - const target = event.target as HTMLInputElement; - fields.username = target.value; - }, - ], - [ - "vdiv", - fields.avatar - ? ["img", fields.avatar, [128, 128]] - : ["text", "No avatar"], - [ - "fileupload", - "Bot avatar:", - (event) => { - const reader = new FileReader(); - const files = (event.target as HTMLInputElement).files; - if (files) { - const file = files[0]; - reader.readAsDataURL(file); - reader.onload = () => { - fields.avatar = reader.result; - }; - } - }, - ], - ], - ], - [ - "hdiv", - [ - "button", - "", - "Save changes", - async () => { - const updateRes = await fetch( - this.info.api + "/applications/" + appId + "/bot", - { - method: "PATCH", - headers: this.headers, - body: JSON.stringify(fields), - } - ); - if (updateRes.ok) botDialog.hide(); - else { - const updateJSON = await updateRes.json(); - alert("An error occurred: " + updateJSON.message); - } - }, - ], - [ - "button", - "", - "Reset token", - async () => { - if ( - !confirm( - "Are you sure you want to reset the bot token? Your bot will stop working until you update it." - ) - ) - return; + const fields: any = { + username: json.bot.username, + avatar: json.bot.avatar + ? this.info.cdn + + "/app-icons/" + + appId + + "/" + + json.bot.avatar + + ".png?size=256" + : "", + }; + const botDialog = new Dialog([ + "vdiv", + ["title", "Editing bot: " + json.bot.username], + [ + "hdiv", + [ + "textbox", + "Bot username:", + json.bot.username, + (event: Event) => { + const target = event.target as HTMLInputElement; + fields.username = target.value; + }, + ], + [ + "vdiv", + fields.avatar + ? ["img", fields.avatar, [128, 128]] + : ["text", "No avatar"], + [ + "fileupload", + "Bot avatar:", + (event) => { + const reader = new FileReader(); + const files = (event.target as HTMLInputElement).files; + if (files) { + const file = files[0]; + reader.readAsDataURL(file); + reader.onload = () => { + fields.avatar = reader.result; + }; + } + }, + ], + ], + ], + [ + "hdiv", + [ + "button", + "", + "Save changes", + async () => { + const updateRes = await fetch( + this.info.api + "/applications/" + appId + "/bot", + { + method: "PATCH", + headers: this.headers, + body: JSON.stringify(fields), + } + ); + if (updateRes.ok) botDialog.hide(); + else { + const updateJSON = await updateRes.json(); + alert("An error occurred: " + updateJSON.message); + } + }, + ], + [ + "button", + "", + "Reset token", + async () => { + if ( + !confirm( + "Are you sure you want to reset the bot token? Your bot will stop working until you update it." + ) + ) + return; - const updateRes = await fetch( - this.info.api + "/applications/" + appId + "/bot/reset", - { - method: "POST", - headers: this.headers, - } - ); - const updateJSON = await updateRes.json(); - alert("New token:\n" + updateJSON.token); - botDialog.hide(); - }, - ], - ], - ]); - botDialog.show(); - } + const updateRes = await fetch( + this.info.api + "/applications/" + appId + "/bot/reset", + { + method: "POST", + headers: this.headers, + } + ); + const updateJSON = await updateRes.json(); + alert("New token:\n" + updateJSON.token); + botDialog.hide(); + }, + ], + ], + ]); + botDialog.show(); + } - //---------- resolving members code ----------- - readonly waitingmembers: Map< - string, - Map void> - > = new Map(); - readonly presences: Map = new Map(); - async resolvemember( - id: string, - guildid: string - ): Promise { - if (guildid === "@me") { - return undefined; - } - const guild = this.guildids.get(guildid); - const borked = true; - if (borked && guild && guild.member_count > 250) { - //sorry puyo, I need to fix member resolving while it's broken on large guilds - try { - const req = await fetch( - this.info.api + "/guilds/" + guild.id + "/members/" + id, - { - headers: this.headers, - } - ); - if (req.status !== 200) { - return undefined; - } - return await req.json(); - } catch { - return undefined; - } - } - let guildmap = this.waitingmembers.get(guildid); - if (!guildmap) { - guildmap = new Map(); - this.waitingmembers.set(guildid, guildmap); - } - const promise: Promise = new Promise((res) => { - guildmap.set(id, res); - this.getmembers(); - }); - return await promise; - } - fetchingmembers: Map = new Map(); - noncemap: Map void> = new Map(); - noncebuild: Map = new Map(); - async gotChunk(chunk: { - chunk_index: number; - chunk_count: number; - nonce: string; - not_found?: string[]; - members?: memberjson[]; - presences: presencejson[]; - }) { - for (const thing of chunk.presences) { - if (thing.user) { - this.presences.set(thing.user.id, thing); - } - } - chunk.members ??= []; - const arr = this.noncebuild.get(chunk.nonce); - if (!arr) return; - arr[0] = arr[0].concat(chunk.members); - if (chunk.not_found) { - arr[1] = chunk.not_found; - } - arr[2].push(chunk.chunk_index); - if (arr[2].length === chunk.chunk_count) { - this.noncebuild.delete(chunk.nonce); - const func = this.noncemap.get(chunk.nonce); - if (!func) return; - func([arr[0], arr[1]]); - this.noncemap.delete(chunk.nonce); - } - } - async getmembers() { - const promise = new Promise((res) => { - setTimeout(res, 10); - }); - await promise; //allow for more to be sent at once :P - if (this.ws) { - this.waitingmembers.forEach(async (value, guildid) => { - const keys = value.keys(); - if (this.fetchingmembers.has(guildid)) { - return; - } - const build: string[] = []; - for (const key of keys) { - build.push(key); - if (build.length === 100) { - break; - } - } - if (!build.length) { - this.waitingmembers.delete(guildid); - return; - } - const promise: Promise<[memberjson[], string[]]> = new Promise( - (res) => { - const nonce = "" + Math.floor(Math.random() * 100000000000); - this.noncemap.set(nonce, res); - this.noncebuild.set(nonce, [[], [], []]); - if (!this.ws) return; - this.ws.send( - JSON.stringify({ - op: 8, - d: { - user_ids: build, - guild_id: guildid, - limit: 100, - nonce, - presences: true, - }, - }) - ); - this.fetchingmembers.set(guildid, true); - } - ); - const prom = await promise; - const data = prom[0]; - for (const thing of data) { - if (value.has(thing.id)) { - const func = value.get(thing.id); - if (!func) { - value.delete(thing.id); - continue; - } - func(thing); - value.delete(thing.id); - } - } - for (const thing of prom[1]) { - if (value.has(thing)) { - const func = value.get(thing); - if (!func) { - value.delete(thing); - continue; - } - func(undefined); - value.delete(thing); - } - } - this.fetchingmembers.delete(guildid); - this.getmembers(); - }); - } - } - async pingEndpoint() { - const userInfo = getBulkInfo(); - if (!userInfo.instances) userInfo.instances = {}; - const wellknown = this.info.wellknown; - if (!userInfo.instances[wellknown]) { - const pingRes = await fetch(this.info.api + "/ping"); - const pingJSON = await pingRes.json(); - userInfo.instances[wellknown] = pingJSON; - localStorage.setItem("userinfos", JSON.stringify(userInfo)); - } - this.instancePing = userInfo.instances[wellknown].instance; + //---------- resolving members code ----------- + readonly waitingmembers: Map< + string, + Map void> + > = new Map(); + readonly presences: Map = new Map(); + async resolvemember( + id: string, + guildid: string + ): Promise { + if (guildid === "@me") { + return undefined; + } + const guild = this.guildids.get(guildid); + const borked = true; + if (borked && guild && guild.member_count > 250) { + //sorry puyo, I need to fix member resolving while it's broken on large guilds + try { + const req = await fetch( + this.info.api + "/guilds/" + guild.id + "/members/" + id, + { + headers: this.headers, + } + ); + if (req.status !== 200) { + return undefined; + } + return await req.json(); + } catch { + return undefined; + } + } + let guildmap = this.waitingmembers.get(guildid); + if (!guildmap) { + guildmap = new Map(); + this.waitingmembers.set(guildid, guildmap); + } + const promise: Promise = new Promise((res) => { + guildmap.set(id, res); + this.getmembers(); + }); + return await promise; + } + fetchingmembers: Map = new Map(); + noncemap: Map void> = new Map(); + noncebuild: Map = new Map(); + async gotChunk(chunk: { + chunk_index: number; + chunk_count: number; + nonce: string; + not_found?: string[]; + members?: memberjson[]; + presences: presencejson[]; + }) { + for (const thing of chunk.presences) { + if (thing.user) { + this.presences.set(thing.user.id, thing); + } + } + chunk.members ??= []; + const arr = this.noncebuild.get(chunk.nonce); + if (!arr) return; + arr[0] = arr[0].concat(chunk.members); + if (chunk.not_found) { + arr[1] = chunk.not_found; + } + arr[2].push(chunk.chunk_index); + if (arr[2].length === chunk.chunk_count) { + this.noncebuild.delete(chunk.nonce); + const func = this.noncemap.get(chunk.nonce); + if (!func) return; + func([arr[0], arr[1]]); + this.noncemap.delete(chunk.nonce); + } + } + async getmembers() { + const promise = new Promise((res) => { + setTimeout(res, 10); + }); + await promise; //allow for more to be sent at once :P + if (this.ws) { + this.waitingmembers.forEach(async (value, guildid) => { + const keys = value.keys(); + if (this.fetchingmembers.has(guildid)) { + return; + } + const build: string[] = []; + for (const key of keys) { + build.push(key); + if (build.length === 100) { + break; + } + } + if (!build.length) { + this.waitingmembers.delete(guildid); + return; + } + const promise: Promise<[memberjson[], string[]]> = new Promise( + (res) => { + const nonce = "" + Math.floor(Math.random() * 100000000000); + this.noncemap.set(nonce, res); + this.noncebuild.set(nonce, [[], [], []]); + if (!this.ws) return; + this.ws.send( + JSON.stringify({ + op: 8, + d: { + user_ids: build, + guild_id: guildid, + limit: 100, + nonce, + presences: true, + }, + }) + ); + this.fetchingmembers.set(guildid, true); + } + ); + const prom = await promise; + const data = prom[0]; + for (const thing of data) { + if (value.has(thing.id)) { + const func = value.get(thing.id); + if (!func) { + value.delete(thing.id); + continue; + } + func(thing); + value.delete(thing.id); + } + } + for (const thing of prom[1]) { + if (value.has(thing)) { + const func = value.get(thing); + if (!func) { + value.delete(thing); + continue; + } + func(undefined); + value.delete(thing); + } + } + this.fetchingmembers.delete(guildid); + this.getmembers(); + }); + } + } + async pingEndpoint() { + const userInfo = getBulkInfo(); + if (!userInfo.instances) userInfo.instances = {}; + const wellknown = this.info.wellknown; + if (!userInfo.instances[wellknown]) { + const pingRes = await fetch(this.info.api + "/ping"); + const pingJSON = await pingRes.json(); + userInfo.instances[wellknown] = pingJSON; + localStorage.setItem("userinfos", JSON.stringify(userInfo)); + } + this.instancePing = userInfo.instances[wellknown].instance; - this.pageTitle("Loading..."); - } - pageTitle(channelName = "", guildName = "") { - (document.getElementById("channelname") as HTMLSpanElement).textContent = - channelName; - ( - document.getElementsByTagName("title")[0] as HTMLTitleElement - ).textContent = - channelName + - (guildName ? " | " + guildName : "") + - " | " + - this.instancePing.name + - " | Jank Client"; - } - async instanceStats() { - const res = await fetch(this.info.api + "/policies/stats", { - headers: this.headers, - }); - const json = await res.json(); + this.pageTitle("Loading..."); + } + pageTitle(channelName = "", guildName = "") { + (document.getElementById("channelname") as HTMLSpanElement).textContent = + channelName; + ( + document.getElementsByTagName("title")[0] as HTMLTitleElement + ).textContent = + channelName + + (guildName ? " | " + guildName : "") + + " | " + + this.instancePing.name + + " | Jank Client"; + } + async instanceStats() { + const res = await fetch(this.info.api + "/policies/stats", { + headers: this.headers, + }); + const json = await res.json(); - const dialog = new Dialog([ - "vdiv", - ["title", "Instance stats: " + this.instancePing.name], - ["text", "Registered users: " + json.counts.user], - ["text", "Servers: " + json.counts.guild], - ["text", "Messages: " + json.counts.message], - ["text", "Members: " + json.counts.members], - ]); - dialog.show(); - } - } - export { Localuser }; + const dialog = new Dialog([ + "vdiv", + ["title", "Instance stats: " + this.instancePing.name], + ["text", "Registered users: " + json.counts.user], + ["text", "Servers: " + json.counts.guild], + ["text", "Messages: " + json.counts.message], + ["text", "Members: " + json.counts.members], + ]); + dialog.show(); + } +} +export { Localuser }; diff --git a/tsconfig.json b/tsconfig.json index 514583e..64d78e8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -28,6 +28,7 @@ "target": "ESNext", "useDefineForClassFields": true, "resolvePackageJsonImports": true, + "skipLibCheck": true, "outDir": "./dist", }, "include": [