summary refs log tree commit diff
diff options
context:
space:
mode:
authorMadeline <46743919+MaddyUnderStars@users.noreply.github.com>2023-01-20 18:10:47 +1100
committerGitHub <noreply@github.com>2023-01-20 18:10:47 +1100
commit084dc0be08555891cad4c2bb984822a62ec5ec9f (patch)
treeed2ca0fafefa2224ae32761f955f63935422a97d
parentfix: route file regex (#956) (diff)
downloadserver-084dc0be08555891cad4c2bb984822a62ec5ec9f.tar.xz
Add ESLint (#941)
* Add eslint, switch to lint-staged for precommit

* Fix all ESLint errors

* Update GH workflow to check prettier and eslint
-rw-r--r--.eslintignore7
-rw-r--r--.eslintrc11
-rw-r--r--.github/workflows/build.yml2
-rwxr-xr-x.husky/pre-commit2
-rw-r--r--.lintstagedrc3
-rw-r--r--package-lock.json1170
-rw-r--r--package.json6
-rw-r--r--scripts/util/getRouteDescriptions.js3
-rw-r--r--src/api/Server.ts17
-rw-r--r--src/api/middlewares/Authentication.ts10
-rw-r--r--src/api/middlewares/RateLimit.ts12
-rw-r--r--src/api/routes/applications/#id/bot/index.ts6
-rw-r--r--src/api/routes/applications/#id/index.ts2
-rw-r--r--src/api/routes/applications/#id/skus.ts1
-rw-r--r--src/api/routes/applications/index.ts2
-rw-r--r--src/api/routes/auth/generate-registration-tokens.ts2
-rw-r--r--src/api/routes/auth/login.ts2
-rw-r--r--src/api/routes/auth/mfa/totp.ts6
-rw-r--r--src/api/routes/auth/register.ts10
-rw-r--r--src/api/routes/channels/#channel_id/followers.ts2
-rw-r--r--src/api/routes/channels/#channel_id/index.ts2
-rw-r--r--src/api/routes/channels/#channel_id/invites.ts1
-rw-r--r--src/api/routes/channels/#channel_id/messages/#message_id/index.ts13
-rw-r--r--src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts7
-rw-r--r--src/api/routes/channels/#channel_id/messages/bulk-delete.ts2
-rw-r--r--src/api/routes/channels/#channel_id/messages/index.ts65
-rw-r--r--src/api/routes/channels/#channel_id/permissions.ts18
-rw-r--r--src/api/routes/channels/#channel_id/pins.ts8
-rw-r--r--src/api/routes/channels/#channel_id/purge.ts8
-rw-r--r--src/api/routes/channels/#channel_id/recipients.ts8
-rw-r--r--src/api/routes/channels/#channel_id/webhooks.ts4
-rw-r--r--src/api/routes/discoverable-guilds.ts4
-rw-r--r--src/api/routes/discovery.ts3
-rw-r--r--src/api/routes/download.ts (renamed from src/api/routes/download/index.ts)5
-rw-r--r--src/api/routes/gifs/search.ts2
-rw-r--r--src/api/routes/gifs/trending-gifs.ts2
-rw-r--r--src/api/routes/gifs/trending.ts61
-rw-r--r--src/api/routes/guild-recommendations.ts7
-rw-r--r--src/api/routes/guilds/#guild_id/bans.ts12
-rw-r--r--src/api/routes/guilds/#guild_id/channels.ts2
-rw-r--r--src/api/routes/guilds/#guild_id/delete.ts14
-rw-r--r--src/api/routes/guilds/#guild_id/discovery-requirements.ts2
-rw-r--r--src/api/routes/guilds/#guild_id/index.ts12
-rw-r--r--src/api/routes/guilds/#guild_id/invites.ts2
-rw-r--r--src/api/routes/guilds/#guild_id/members/#member_id/index.ts18
-rw-r--r--src/api/routes/guilds/#guild_id/members/#member_id/nick.ts12
-rw-r--r--src/api/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts2
-rw-r--r--src/api/routes/guilds/#guild_id/members/index.ts2
-rw-r--r--src/api/routes/guilds/#guild_id/messages/search.ts18
-rw-r--r--src/api/routes/guilds/#guild_id/profile/index.ts5
-rw-r--r--src/api/routes/guilds/#guild_id/prune.ts10
-rw-r--r--src/api/routes/guilds/#guild_id/regions.ts5
-rw-r--r--src/api/routes/guilds/#guild_id/roles/#role_id/index.ts3
-rw-r--r--src/api/routes/guilds/#guild_id/roles/index.ts3
-rw-r--r--src/api/routes/guilds/#guild_id/templates.ts6
-rw-r--r--src/api/routes/guilds/#guild_id/voice-states/#user_id/index.ts5
-rw-r--r--src/api/routes/guilds/#guild_id/widget.json.ts19
-rw-r--r--src/api/routes/guilds/#guild_id/widget.png.ts5
-rw-r--r--src/api/routes/guilds/index.ts2
-rw-r--r--src/api/routes/guilds/templates/index.ts6
-rw-r--r--src/api/routes/oauth2/authorize.ts12
-rw-r--r--src/api/routes/partners/#guild_id/requirements.ts2
-rw-r--r--src/api/routes/policies/instance/domains.ts1
-rw-r--r--src/api/routes/store/published-listings/applications.ts2
-rw-r--r--src/api/routes/store/published-listings/skus.ts2
-rw-r--r--src/api/routes/updates.ts3
-rw-r--r--src/api/routes/users/#id/delete.ts3
-rw-r--r--src/api/routes/users/#id/profile.ts9
-rw-r--r--src/api/routes/users/#id/relationships.ts4
-rw-r--r--src/api/routes/users/@me/delete.ts2
-rw-r--r--src/api/routes/users/@me/guilds/#guild_id/settings.ts2
-rw-r--r--src/api/routes/users/@me/index.ts7
-rw-r--r--src/api/routes/users/@me/mfa/codes-verification.ts10
-rw-r--r--src/api/routes/users/@me/mfa/codes.ts2
-rw-r--r--src/api/routes/users/@me/mfa/totp/disable.ts2
-rw-r--r--src/api/routes/users/@me/mfa/totp/enable.ts2
-rw-r--r--src/api/routes/users/@me/relationships.ts6
-rw-r--r--src/api/routes/users/@me/settings.ts2
-rw-r--r--src/api/start.ts7
-rw-r--r--src/api/util/handlers/Instance.ts17
-rw-r--r--src/api/util/handlers/Message.ts34
-rw-r--r--src/api/util/handlers/Voice.ts2
-rw-r--r--src/api/util/handlers/route.ts6
-rw-r--r--src/api/util/utility/EmbedHandlers.ts38
-rw-r--r--src/api/util/utility/RandomInviteID.ts8
-rw-r--r--src/api/util/utility/captcha.ts11
-rw-r--r--src/api/util/utility/ipAddress.ts11
-rw-r--r--src/api/util/utility/passwordStrength.ts8
-rw-r--r--src/bundle/Server.ts2
-rw-r--r--src/bundle/start.ts21
-rw-r--r--src/cdn/Server.ts2
-rw-r--r--src/cdn/routes/attachments.ts10
-rw-r--r--src/cdn/routes/avatars.ts9
-rw-r--r--src/cdn/routes/guild-profiles.ts8
-rw-r--r--src/cdn/routes/role-icons.ts8
-rw-r--r--src/cdn/util/FileStorage.ts8
-rw-r--r--src/cdn/util/Storage.ts1
-rw-r--r--src/gateway/Server.ts1
-rw-r--r--src/gateway/events/Close.ts2
-rw-r--r--src/gateway/events/Connection.ts7
-rw-r--r--src/gateway/events/Message.ts15
-rw-r--r--src/gateway/listener/listener.ts22
-rw-r--r--src/gateway/opcodes/Heartbeat.ts4
-rw-r--r--src/gateway/opcodes/Identify.ts46
-rw-r--r--src/gateway/opcodes/LazyRequest.ts67
-rw-r--r--src/gateway/opcodes/RequestGuildMembers.ts4
-rw-r--r--src/gateway/opcodes/Resume.ts4
-rw-r--r--src/gateway/opcodes/VoiceStateUpdate.ts1
-rw-r--r--src/gateway/opcodes/index.ts4
-rw-r--r--src/gateway/opcodes/instanceOf.ts2
-rw-r--r--src/gateway/start.ts2
-rw-r--r--src/gateway/util/Constants.ts1
-rw-r--r--src/gateway/util/Send.ts4
-rw-r--r--src/gateway/util/WebSocket.ts8
-rw-r--r--src/util/config/types/GifConfiguration.ts2
-rw-r--r--src/util/dtos/DmChannelDTO.ts8
-rw-r--r--src/util/dtos/ReadyGuildDTO.ts16
-rw-r--r--src/util/entities/Application.ts14
-rw-r--r--src/util/entities/AuditLog.ts4
-rw-r--r--src/util/entities/BackupCodes.ts4
-rw-r--r--src/util/entities/BaseClass.ts9
-rw-r--r--src/util/entities/Channel.ts14
-rw-r--r--src/util/entities/ConnectedAccount.ts6
-rw-r--r--src/util/entities/Emoji.ts1
-rw-r--r--src/util/entities/Encryption.ts26
-rw-r--r--src/util/entities/Guild.ts8
-rw-r--r--src/util/entities/Member.ts25
-rw-r--r--src/util/entities/ReadState.ts1
-rw-r--r--src/util/entities/StickerPack.ts1
-rw-r--r--src/util/entities/Team.ts1
-rw-r--r--src/util/entities/User.ts19
-rw-r--r--src/util/imports/OrmUtils.ts25
-rw-r--r--src/util/interfaces/Event.ts12
-rw-r--r--src/util/interfaces/Interaction.ts2
-rw-r--r--src/util/schemas/ChannelPermissionOverwriteSchema.ts3
-rw-r--r--src/util/schemas/IdentifySchema.ts12
-rw-r--r--src/util/schemas/LazyRequestSchema.ts8
-rw-r--r--src/util/schemas/MessageCreateSchema.ts9
-rw-r--r--src/util/schemas/UserSettingsSchema.ts2
-rw-r--r--src/util/schemas/Validator.ts10
-rw-r--r--src/util/util/Array.ts4
-rw-r--r--src/util/util/AutoUpdate.ts5
-rw-r--r--src/util/util/BitField.ts4
-rw-r--r--src/util/util/Config.ts10
-rw-r--r--src/util/util/Constants.ts2
-rw-r--r--src/util/util/Database.ts5
-rw-r--r--src/util/util/Email.ts30
-rw-r--r--src/util/util/Event.ts30
-rw-r--r--src/util/util/FieldError.ts2
-rw-r--r--src/util/util/Permissions.ts37
-rw-r--r--src/util/util/Rights.ts12
-rw-r--r--src/util/util/Sentry.ts6
-rw-r--r--src/util/util/Snowflake.ts9
-rw-r--r--src/util/util/String.ts3
-rw-r--r--src/util/util/Token.ts25
-rw-r--r--src/util/util/TraverseDirectory.ts2
-rw-r--r--src/util/util/cdn.ts4
157 files changed, 1904 insertions, 667 deletions
diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 00000000..15a75b0e
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,7 @@
+node_modules
+dist
+README.md
+COPYING
+src/webrtc
+scripts/
+assets
\ No newline at end of file
diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 00000000..00ce9892
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,11 @@
+{
+	"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
+	"parser": "@typescript-eslint/parser",
+	"plugins": ["@typescript-eslint"],
+	"root": true,
+	"rules": {
+		"no-mixed-spaces-and-tabs": "off",
+		"@typescript-eslint/no-inferrable-types": "off", // Required by typeorm
+		"@typescript-eslint/no-var-requires": "off" // Sometimes requred by typeorm to resolve circular deps
+	}
+}
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index e3bcc81f..5b27fddf 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -24,5 +24,7 @@ jobs:
         node-version: ${{ matrix.node-version }}
         cache: 'npm'
     - run: npm ci
+    - run: npx eslint .
+    - run: npx prettier --check .
     - run: npm run build --if-present
     - run: npm run test --if-present
\ No newline at end of file
diff --git a/.husky/pre-commit b/.husky/pre-commit
index 0da96d6b..1bc5a8c6 100755
--- a/.husky/pre-commit
+++ b/.husky/pre-commit
@@ -1,4 +1,4 @@
 #!/usr/bin/env sh
 . "$(dirname -- "$0")/_/husky.sh"
 
-npx pretty-quick --staged
+npx -y lint-staged
\ No newline at end of file
diff --git a/.lintstagedrc b/.lintstagedrc
new file mode 100644
index 00000000..4c3506ec
--- /dev/null
+++ b/.lintstagedrc
@@ -0,0 +1,3 @@
+{
+	"*.ts": ["eslint", "prettier --write"]
+}
diff --git a/package-lock.json b/package-lock.json
index 74115e92..d6a90f43 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -68,11 +68,14 @@
 				"@types/probe-image-size": "^7.2.0",
 				"@types/sharp": "^0.31.0",
 				"@types/ws": "^8.5.3",
+				"@typescript-eslint/eslint-plugin": "^5.48.2",
+				"@typescript-eslint/parser": "^5.48.2",
+				"eslint": "^8.32.0",
 				"express": "^4.18.1",
 				"husky": "^8.0.0",
 				"prettier": "^2.7.1",
 				"pretty-quick": "^3.1.3",
-				"typescript": "^4.8.3"
+				"typescript": "^4.9.4"
 			},
 			"optionalDependencies": {
 				"@yukikaze-bot/erlpack": "^1.0.1"
@@ -1417,12 +1420,108 @@
 				"node": ">=12"
 			}
 		},
+		"node_modules/@eslint/eslintrc": {
+			"version": "1.4.1",
+			"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
+			"integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==",
+			"dev": true,
+			"dependencies": {
+				"ajv": "^6.12.4",
+				"debug": "^4.3.2",
+				"espree": "^9.4.0",
+				"globals": "^13.19.0",
+				"ignore": "^5.2.0",
+				"import-fresh": "^3.2.1",
+				"js-yaml": "^4.1.0",
+				"minimatch": "^3.1.2",
+				"strip-json-comments": "^3.1.1"
+			},
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://opencollective.com/eslint"
+			}
+		},
+		"node_modules/@eslint/eslintrc/node_modules/ajv": {
+			"version": "6.12.6",
+			"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+			"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+			"dev": true,
+			"dependencies": {
+				"fast-deep-equal": "^3.1.1",
+				"fast-json-stable-stringify": "^2.0.0",
+				"json-schema-traverse": "^0.4.1",
+				"uri-js": "^4.2.2"
+			},
+			"funding": {
+				"type": "github",
+				"url": "https://github.com/sponsors/epoberezkin"
+			}
+		},
+		"node_modules/@eslint/eslintrc/node_modules/argparse": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+			"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+			"dev": true
+		},
+		"node_modules/@eslint/eslintrc/node_modules/js-yaml": {
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+			"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+			"dev": true,
+			"dependencies": {
+				"argparse": "^2.0.1"
+			},
+			"bin": {
+				"js-yaml": "bin/js-yaml.js"
+			}
+		},
+		"node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": {
+			"version": "0.4.1",
+			"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+			"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+			"dev": true
+		},
 		"node_modules/@gar/promisify": {
 			"version": "1.1.3",
 			"resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz",
 			"integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==",
 			"optional": true
 		},
+		"node_modules/@humanwhocodes/config-array": {
+			"version": "0.11.8",
+			"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
+			"integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
+			"dev": true,
+			"dependencies": {
+				"@humanwhocodes/object-schema": "^1.2.1",
+				"debug": "^4.1.1",
+				"minimatch": "^3.0.5"
+			},
+			"engines": {
+				"node": ">=10.10.0"
+			}
+		},
+		"node_modules/@humanwhocodes/module-importer": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+			"integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+			"dev": true,
+			"engines": {
+				"node": ">=12.22"
+			},
+			"funding": {
+				"type": "github",
+				"url": "https://github.com/sponsors/nzakas"
+			}
+		},
+		"node_modules/@humanwhocodes/object-schema": {
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
+			"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+			"dev": true
+		},
 		"node_modules/@jridgewell/resolve-uri": {
 			"version": "3.1.0",
 			"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
@@ -1464,6 +1563,41 @@
 				"node-pre-gyp": "bin/node-pre-gyp"
 			}
 		},
+		"node_modules/@nodelib/fs.scandir": {
+			"version": "2.1.5",
+			"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+			"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+			"dev": true,
+			"dependencies": {
+				"@nodelib/fs.stat": "2.0.5",
+				"run-parallel": "^1.1.9"
+			},
+			"engines": {
+				"node": ">= 8"
+			}
+		},
+		"node_modules/@nodelib/fs.stat": {
+			"version": "2.0.5",
+			"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+			"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+			"dev": true,
+			"engines": {
+				"node": ">= 8"
+			}
+		},
+		"node_modules/@nodelib/fs.walk": {
+			"version": "1.2.8",
+			"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+			"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+			"dev": true,
+			"dependencies": {
+				"@nodelib/fs.scandir": "2.1.5",
+				"fastq": "^1.6.0"
+			},
+			"engines": {
+				"node": ">= 8"
+			}
+		},
 		"node_modules/@npmcli/fs": {
 			"version": "1.1.1",
 			"resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz",
@@ -1850,6 +1984,12 @@
 			"integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==",
 			"dev": true
 		},
+		"node_modules/@types/semver": {
+			"version": "7.3.13",
+			"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
+			"integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
+			"dev": true
+		},
 		"node_modules/@types/serve-static": {
 			"version": "1.15.0",
 			"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz",
@@ -1886,6 +2026,193 @@
 				"@types/node": "*"
 			}
 		},
+		"node_modules/@typescript-eslint/eslint-plugin": {
+			"version": "5.48.2",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.2.tgz",
+			"integrity": "sha512-sR0Gja9Ky1teIq4qJOl0nC+Tk64/uYdX+mi+5iB//MH8gwyx8e3SOyhEzeLZEFEEfCaLf8KJq+Bd/6je1t+CAg==",
+			"dev": true,
+			"dependencies": {
+				"@typescript-eslint/scope-manager": "5.48.2",
+				"@typescript-eslint/type-utils": "5.48.2",
+				"@typescript-eslint/utils": "5.48.2",
+				"debug": "^4.3.4",
+				"ignore": "^5.2.0",
+				"natural-compare-lite": "^1.4.0",
+				"regexpp": "^3.2.0",
+				"semver": "^7.3.7",
+				"tsutils": "^3.21.0"
+			},
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			},
+			"peerDependencies": {
+				"@typescript-eslint/parser": "^5.0.0",
+				"eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+			},
+			"peerDependenciesMeta": {
+				"typescript": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@typescript-eslint/parser": {
+			"version": "5.48.2",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.2.tgz",
+			"integrity": "sha512-38zMsKsG2sIuM5Oi/olurGwYJXzmtdsHhn5mI/pQogP+BjYVkK5iRazCQ8RGS0V+YLk282uWElN70zAAUmaYHw==",
+			"dev": true,
+			"dependencies": {
+				"@typescript-eslint/scope-manager": "5.48.2",
+				"@typescript-eslint/types": "5.48.2",
+				"@typescript-eslint/typescript-estree": "5.48.2",
+				"debug": "^4.3.4"
+			},
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			},
+			"peerDependencies": {
+				"eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+			},
+			"peerDependenciesMeta": {
+				"typescript": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@typescript-eslint/scope-manager": {
+			"version": "5.48.2",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.2.tgz",
+			"integrity": "sha512-zEUFfonQid5KRDKoI3O+uP1GnrFd4tIHlvs+sTJXiWuypUWMuDaottkJuR612wQfOkjYbsaskSIURV9xo4f+Fw==",
+			"dev": true,
+			"dependencies": {
+				"@typescript-eslint/types": "5.48.2",
+				"@typescript-eslint/visitor-keys": "5.48.2"
+			},
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			}
+		},
+		"node_modules/@typescript-eslint/type-utils": {
+			"version": "5.48.2",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.2.tgz",
+			"integrity": "sha512-QVWx7J5sPMRiOMJp5dYshPxABRoZV1xbRirqSk8yuIIsu0nvMTZesKErEA3Oix1k+uvsk8Cs8TGJ6kQ0ndAcew==",
+			"dev": true,
+			"dependencies": {
+				"@typescript-eslint/typescript-estree": "5.48.2",
+				"@typescript-eslint/utils": "5.48.2",
+				"debug": "^4.3.4",
+				"tsutils": "^3.21.0"
+			},
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			},
+			"peerDependencies": {
+				"eslint": "*"
+			},
+			"peerDependenciesMeta": {
+				"typescript": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@typescript-eslint/types": {
+			"version": "5.48.2",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.2.tgz",
+			"integrity": "sha512-hE7dA77xxu7ByBc6KCzikgfRyBCTst6dZQpwaTy25iMYOnbNljDT4hjhrGEJJ0QoMjrfqrx+j1l1B9/LtKeuqA==",
+			"dev": true,
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			}
+		},
+		"node_modules/@typescript-eslint/typescript-estree": {
+			"version": "5.48.2",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.2.tgz",
+			"integrity": "sha512-bibvD3z6ilnoVxUBFEgkO0k0aFvUc4Cttt0dAreEr+nrAHhWzkO83PEVVuieK3DqcgL6VAK5dkzK8XUVja5Zcg==",
+			"dev": true,
+			"dependencies": {
+				"@typescript-eslint/types": "5.48.2",
+				"@typescript-eslint/visitor-keys": "5.48.2",
+				"debug": "^4.3.4",
+				"globby": "^11.1.0",
+				"is-glob": "^4.0.3",
+				"semver": "^7.3.7",
+				"tsutils": "^3.21.0"
+			},
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			},
+			"peerDependenciesMeta": {
+				"typescript": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@typescript-eslint/utils": {
+			"version": "5.48.2",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.2.tgz",
+			"integrity": "sha512-2h18c0d7jgkw6tdKTlNaM7wyopbLRBiit8oAxoP89YnuBOzCZ8g8aBCaCqq7h208qUTroL7Whgzam7UY3HVLow==",
+			"dev": true,
+			"dependencies": {
+				"@types/json-schema": "^7.0.9",
+				"@types/semver": "^7.3.12",
+				"@typescript-eslint/scope-manager": "5.48.2",
+				"@typescript-eslint/types": "5.48.2",
+				"@typescript-eslint/typescript-estree": "5.48.2",
+				"eslint-scope": "^5.1.1",
+				"eslint-utils": "^3.0.0",
+				"semver": "^7.3.7"
+			},
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			},
+			"peerDependencies": {
+				"eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+			}
+		},
+		"node_modules/@typescript-eslint/visitor-keys": {
+			"version": "5.48.2",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.2.tgz",
+			"integrity": "sha512-z9njZLSkwmjFWUelGEwEbdf4NwKvfHxvGC0OcGN1Hp/XNDIcJ7D5DpPNPv6x6/mFvc1tQHsaWmpD/a4gOvvCJQ==",
+			"dev": true,
+			"dependencies": {
+				"@typescript-eslint/types": "5.48.2",
+				"eslint-visitor-keys": "^3.3.0"
+			},
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			}
+		},
 		"node_modules/@yukikaze-bot/erlpack": {
 			"version": "1.0.1",
 			"resolved": "https://registry.npmjs.org/@yukikaze-bot/erlpack/-/erlpack-1.0.1.tgz",
@@ -1925,6 +2252,15 @@
 				"node": ">=0.4.0"
 			}
 		},
+		"node_modules/acorn-jsx": {
+			"version": "5.3.2",
+			"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+			"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+			"dev": true,
+			"peerDependencies": {
+				"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+			}
+		},
 		"node_modules/acorn-walk": {
 			"version": "8.2.0",
 			"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
@@ -2299,6 +2635,18 @@
 				"concat-map": "0.0.1"
 			}
 		},
+		"node_modules/braces": {
+			"version": "3.0.2",
+			"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+			"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+			"dev": true,
+			"dependencies": {
+				"fill-range": "^7.0.1"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
 		"node_modules/buffer": {
 			"version": "6.0.3",
 			"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
@@ -2427,6 +2775,15 @@
 				"url": "https://github.com/sponsors/ljharb"
 			}
 		},
+		"node_modules/callsites": {
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+			"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+			"dev": true,
+			"engines": {
+				"node": ">=6"
+			}
+		},
 		"node_modules/chalk": {
 			"version": "4.1.2",
 			"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -2889,6 +3246,30 @@
 				"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",
+			"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+			"dev": true,
+			"dependencies": {
+				"path-type": "^4.0.0"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/doctrine": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+			"integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+			"dev": true,
+			"dependencies": {
+				"esutils": "^2.0.2"
+			},
+			"engines": {
+				"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",
@@ -3043,6 +3424,18 @@
 			"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
 			"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
 		},
+		"node_modules/escape-string-regexp": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+			"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+			"dev": true,
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
 		"node_modules/escodegen": {
 			"version": "1.14.3",
 			"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz",
@@ -3064,6 +3457,302 @@
 				"source-map": "~0.6.1"
 			}
 		},
+		"node_modules/eslint": {
+			"version": "8.32.0",
+			"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.32.0.tgz",
+			"integrity": "sha512-nETVXpnthqKPFyuY2FNjz/bEd6nbosRgKbkgS/y1C7LJop96gYHWpiguLecMHQ2XCPxn77DS0P+68WzG6vkZSQ==",
+			"dev": true,
+			"dependencies": {
+				"@eslint/eslintrc": "^1.4.1",
+				"@humanwhocodes/config-array": "^0.11.8",
+				"@humanwhocodes/module-importer": "^1.0.1",
+				"@nodelib/fs.walk": "^1.2.8",
+				"ajv": "^6.10.0",
+				"chalk": "^4.0.0",
+				"cross-spawn": "^7.0.2",
+				"debug": "^4.3.2",
+				"doctrine": "^3.0.0",
+				"escape-string-regexp": "^4.0.0",
+				"eslint-scope": "^7.1.1",
+				"eslint-utils": "^3.0.0",
+				"eslint-visitor-keys": "^3.3.0",
+				"espree": "^9.4.0",
+				"esquery": "^1.4.0",
+				"esutils": "^2.0.2",
+				"fast-deep-equal": "^3.1.3",
+				"file-entry-cache": "^6.0.1",
+				"find-up": "^5.0.0",
+				"glob-parent": "^6.0.2",
+				"globals": "^13.19.0",
+				"grapheme-splitter": "^1.0.4",
+				"ignore": "^5.2.0",
+				"import-fresh": "^3.0.0",
+				"imurmurhash": "^0.1.4",
+				"is-glob": "^4.0.0",
+				"is-path-inside": "^3.0.3",
+				"js-sdsl": "^4.1.4",
+				"js-yaml": "^4.1.0",
+				"json-stable-stringify-without-jsonify": "^1.0.1",
+				"levn": "^0.4.1",
+				"lodash.merge": "^4.6.2",
+				"minimatch": "^3.1.2",
+				"natural-compare": "^1.4.0",
+				"optionator": "^0.9.1",
+				"regexpp": "^3.2.0",
+				"strip-ansi": "^6.0.1",
+				"strip-json-comments": "^3.1.0",
+				"text-table": "^0.2.0"
+			},
+			"bin": {
+				"eslint": "bin/eslint.js"
+			},
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://opencollective.com/eslint"
+			}
+		},
+		"node_modules/eslint-scope": {
+			"version": "5.1.1",
+			"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+			"integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+			"dev": true,
+			"dependencies": {
+				"esrecurse": "^4.3.0",
+				"estraverse": "^4.1.1"
+			},
+			"engines": {
+				"node": ">=8.0.0"
+			}
+		},
+		"node_modules/eslint-utils": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
+			"integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
+			"dev": true,
+			"dependencies": {
+				"eslint-visitor-keys": "^2.0.0"
+			},
+			"engines": {
+				"node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/mysticatea"
+			},
+			"peerDependencies": {
+				"eslint": ">=5"
+			}
+		},
+		"node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
+			"version": "2.1.0",
+			"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
+			"integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
+			"dev": true,
+			"engines": {
+				"node": ">=10"
+			}
+		},
+		"node_modules/eslint-visitor-keys": {
+			"version": "3.3.0",
+			"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
+			"integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
+			"dev": true,
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			}
+		},
+		"node_modules/eslint/node_modules/ajv": {
+			"version": "6.12.6",
+			"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+			"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+			"dev": true,
+			"dependencies": {
+				"fast-deep-equal": "^3.1.1",
+				"fast-json-stable-stringify": "^2.0.0",
+				"json-schema-traverse": "^0.4.1",
+				"uri-js": "^4.2.2"
+			},
+			"funding": {
+				"type": "github",
+				"url": "https://github.com/sponsors/epoberezkin"
+			}
+		},
+		"node_modules/eslint/node_modules/argparse": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+			"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+			"dev": true
+		},
+		"node_modules/eslint/node_modules/eslint-scope": {
+			"version": "7.1.1",
+			"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
+			"integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
+			"dev": true,
+			"dependencies": {
+				"esrecurse": "^4.3.0",
+				"estraverse": "^5.2.0"
+			},
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			}
+		},
+		"node_modules/eslint/node_modules/estraverse": {
+			"version": "5.3.0",
+			"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+			"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+			"dev": true,
+			"engines": {
+				"node": ">=4.0"
+			}
+		},
+		"node_modules/eslint/node_modules/find-up": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+			"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+			"dev": true,
+			"dependencies": {
+				"locate-path": "^6.0.0",
+				"path-exists": "^4.0.0"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/eslint/node_modules/js-yaml": {
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+			"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+			"dev": true,
+			"dependencies": {
+				"argparse": "^2.0.1"
+			},
+			"bin": {
+				"js-yaml": "bin/js-yaml.js"
+			}
+		},
+		"node_modules/eslint/node_modules/json-schema-traverse": {
+			"version": "0.4.1",
+			"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+			"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+			"dev": true
+		},
+		"node_modules/eslint/node_modules/levn": {
+			"version": "0.4.1",
+			"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+			"integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+			"dev": true,
+			"dependencies": {
+				"prelude-ls": "^1.2.1",
+				"type-check": "~0.4.0"
+			},
+			"engines": {
+				"node": ">= 0.8.0"
+			}
+		},
+		"node_modules/eslint/node_modules/locate-path": {
+			"version": "6.0.0",
+			"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+			"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+			"dev": true,
+			"dependencies": {
+				"p-locate": "^5.0.0"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/eslint/node_modules/optionator": {
+			"version": "0.9.1",
+			"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
+			"integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+			"dev": true,
+			"dependencies": {
+				"deep-is": "^0.1.3",
+				"fast-levenshtein": "^2.0.6",
+				"levn": "^0.4.1",
+				"prelude-ls": "^1.2.1",
+				"type-check": "^0.4.0",
+				"word-wrap": "^1.2.3"
+			},
+			"engines": {
+				"node": ">= 0.8.0"
+			}
+		},
+		"node_modules/eslint/node_modules/p-limit": {
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+			"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+			"dev": true,
+			"dependencies": {
+				"yocto-queue": "^0.1.0"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/eslint/node_modules/p-locate": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+			"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+			"dev": true,
+			"dependencies": {
+				"p-limit": "^3.0.2"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/eslint/node_modules/prelude-ls": {
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+			"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+			"dev": true,
+			"engines": {
+				"node": ">= 0.8.0"
+			}
+		},
+		"node_modules/eslint/node_modules/type-check": {
+			"version": "0.4.0",
+			"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+			"integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+			"dev": true,
+			"dependencies": {
+				"prelude-ls": "^1.2.1"
+			},
+			"engines": {
+				"node": ">= 0.8.0"
+			}
+		},
+		"node_modules/espree": {
+			"version": "9.4.1",
+			"resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz",
+			"integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==",
+			"dev": true,
+			"dependencies": {
+				"acorn": "^8.8.0",
+				"acorn-jsx": "^5.3.2",
+				"eslint-visitor-keys": "^3.3.0"
+			},
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://opencollective.com/eslint"
+			}
+		},
 		"node_modules/esprima": {
 			"version": "4.0.1",
 			"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
@@ -3076,6 +3765,48 @@
 				"node": ">=4"
 			}
 		},
+		"node_modules/esquery": {
+			"version": "1.4.0",
+			"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
+			"integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
+			"dev": true,
+			"dependencies": {
+				"estraverse": "^5.1.0"
+			},
+			"engines": {
+				"node": ">=0.10"
+			}
+		},
+		"node_modules/esquery/node_modules/estraverse": {
+			"version": "5.3.0",
+			"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+			"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+			"dev": true,
+			"engines": {
+				"node": ">=4.0"
+			}
+		},
+		"node_modules/esrecurse": {
+			"version": "4.3.0",
+			"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+			"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+			"dev": true,
+			"dependencies": {
+				"estraverse": "^5.2.0"
+			},
+			"engines": {
+				"node": ">=4.0"
+			}
+		},
+		"node_modules/esrecurse/node_modules/estraverse": {
+			"version": "5.3.0",
+			"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+			"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+			"dev": true,
+			"engines": {
+				"node": ">=4.0"
+			}
+		},
 		"node_modules/estraverse": {
 			"version": "4.3.0",
 			"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
@@ -3228,6 +3959,40 @@
 			"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
 			"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
 		},
+		"node_modules/fast-glob": {
+			"version": "3.2.12",
+			"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
+			"integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
+			"dev": true,
+			"dependencies": {
+				"@nodelib/fs.stat": "^2.0.2",
+				"@nodelib/fs.walk": "^1.2.3",
+				"glob-parent": "^5.1.2",
+				"merge2": "^1.3.0",
+				"micromatch": "^4.0.4"
+			},
+			"engines": {
+				"node": ">=8.6.0"
+			}
+		},
+		"node_modules/fast-glob/node_modules/glob-parent": {
+			"version": "5.1.2",
+			"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+			"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+			"dev": true,
+			"dependencies": {
+				"is-glob": "^4.0.1"
+			},
+			"engines": {
+				"node": ">= 6"
+			}
+		},
+		"node_modules/fast-json-stable-stringify": {
+			"version": "2.1.0",
+			"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+			"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+			"dev": true
+		},
 		"node_modules/fast-levenshtein": {
 			"version": "2.0.6",
 			"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
@@ -3257,6 +4022,27 @@
 				"url": "https://patreon.com/timotejroiko"
 			}
 		},
+		"node_modules/fastq": {
+			"version": "1.15.0",
+			"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
+			"integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
+			"dev": true,
+			"dependencies": {
+				"reusify": "^1.0.4"
+			}
+		},
+		"node_modules/file-entry-cache": {
+			"version": "6.0.1",
+			"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+			"integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+			"dev": true,
+			"dependencies": {
+				"flat-cache": "^3.0.4"
+			},
+			"engines": {
+				"node": "^10.12.0 || >=12.0.0"
+			}
+		},
 		"node_modules/file-type": {
 			"version": "16.5.4",
 			"resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz",
@@ -3281,6 +4067,18 @@
 				"node": ">= 6"
 			}
 		},
+		"node_modules/fill-range": {
+			"version": "7.0.1",
+			"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+			"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+			"dev": true,
+			"dependencies": {
+				"to-regex-range": "^5.0.1"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
 		"node_modules/finalhandler": {
 			"version": "1.2.0",
 			"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
@@ -3324,6 +4122,25 @@
 				"node": ">=8"
 			}
 		},
+		"node_modules/flat-cache": {
+			"version": "3.0.4",
+			"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
+			"integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+			"dev": true,
+			"dependencies": {
+				"flatted": "^3.1.0",
+				"rimraf": "^3.0.2"
+			},
+			"engines": {
+				"node": "^10.12.0 || >=12.0.0"
+			}
+		},
+		"node_modules/flatted": {
+			"version": "3.2.7",
+			"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
+			"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
+			"dev": true
+		},
 		"node_modules/form-data": {
 			"version": "4.0.0",
 			"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
@@ -3489,11 +4306,64 @@
 				"url": "https://github.com/sponsors/isaacs"
 			}
 		},
+		"node_modules/glob-parent": {
+			"version": "6.0.2",
+			"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+			"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+			"dev": true,
+			"dependencies": {
+				"is-glob": "^4.0.3"
+			},
+			"engines": {
+				"node": ">=10.13.0"
+			}
+		},
+		"node_modules/globals": {
+			"version": "13.19.0",
+			"resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz",
+			"integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==",
+			"dev": true,
+			"dependencies": {
+				"type-fest": "^0.20.2"
+			},
+			"engines": {
+				"node": ">=8"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/globby": {
+			"version": "11.1.0",
+			"resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+			"integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+			"dev": true,
+			"dependencies": {
+				"array-union": "^2.1.0",
+				"dir-glob": "^3.0.1",
+				"fast-glob": "^3.2.9",
+				"ignore": "^5.2.0",
+				"merge2": "^1.4.1",
+				"slash": "^3.0.0"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
 		"node_modules/graceful-fs": {
 			"version": "4.2.10",
 			"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
 			"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="
 		},
+		"node_modules/grapheme-splitter": {
+			"version": "1.0.4",
+			"resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
+			"integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
+			"dev": true
+		},
 		"node_modules/has": {
 			"version": "1.0.3",
 			"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
@@ -3737,11 +4607,27 @@
 			"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
 			"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
 		},
+		"node_modules/import-fresh": {
+			"version": "3.3.0",
+			"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+			"integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+			"dev": true,
+			"dependencies": {
+				"parent-module": "^1.0.0",
+				"resolve-from": "^4.0.0"
+			},
+			"engines": {
+				"node": ">=6"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
 		"node_modules/imurmurhash": {
 			"version": "0.1.4",
 			"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
 			"integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
-			"optional": true,
+			"devOptional": true,
 			"engines": {
 				"node": ">=0.8.19"
 			}
@@ -3788,6 +4674,15 @@
 				"node": ">= 0.10"
 			}
 		},
+		"node_modules/is-extglob": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+			"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+			"dev": true,
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
 		"node_modules/is-fullwidth-code-point": {
 			"version": "3.0.0",
 			"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
@@ -3796,12 +4691,42 @@
 				"node": ">=8"
 			}
 		},
+		"node_modules/is-glob": {
+			"version": "4.0.3",
+			"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+			"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+			"dev": true,
+			"dependencies": {
+				"is-extglob": "^2.1.1"
+			},
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
 		"node_modules/is-lambda": {
 			"version": "1.0.1",
 			"resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz",
 			"integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==",
 			"optional": true
 		},
+		"node_modules/is-number": {
+			"version": "7.0.0",
+			"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+			"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+			"dev": true,
+			"engines": {
+				"node": ">=0.12.0"
+			}
+		},
+		"node_modules/is-path-inside": {
+			"version": "3.0.3",
+			"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+			"integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+			"dev": true,
+			"engines": {
+				"node": ">=8"
+			}
+		},
 		"node_modules/is-stream": {
 			"version": "2.0.1",
 			"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
@@ -3825,6 +4750,16 @@
 			"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
 			"devOptional": true
 		},
+		"node_modules/js-sdsl": {
+			"version": "4.2.0",
+			"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz",
+			"integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==",
+			"dev": true,
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/js-sdsl"
+			}
+		},
 		"node_modules/js-yaml": {
 			"version": "3.13.1",
 			"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
@@ -3861,6 +4796,12 @@
 				"url": "https://github.com/sponsors/ljharb"
 			}
 		},
+		"node_modules/json-stable-stringify-without-jsonify": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+			"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+			"dev": true
+		},
 		"node_modules/json5": {
 			"version": "2.0.0",
 			"resolved": "https://registry.npmjs.org/json5/-/json5-2.0.0.tgz",
@@ -4150,6 +5091,15 @@
 			"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
 			"dev": true
 		},
+		"node_modules/merge2": {
+			"version": "1.4.1",
+			"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+			"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+			"dev": true,
+			"engines": {
+				"node": ">= 8"
+			}
+		},
 		"node_modules/methods": {
 			"version": "1.1.2",
 			"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
@@ -4158,6 +5108,19 @@
 				"node": ">= 0.6"
 			}
 		},
+		"node_modules/micromatch": {
+			"version": "4.0.5",
+			"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+			"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+			"dev": true,
+			"dependencies": {
+				"braces": "^3.0.2",
+				"picomatch": "^2.3.1"
+			},
+			"engines": {
+				"node": ">=8.6"
+			}
+		},
 		"node_modules/mime": {
 			"version": "1.6.0",
 			"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
@@ -4431,6 +5394,18 @@
 				"thenify-all": "^1.0.0"
 			}
 		},
+		"node_modules/natural-compare": {
+			"version": "1.4.0",
+			"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+			"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+			"dev": true
+		},
+		"node_modules/natural-compare-lite": {
+			"version": "1.4.0",
+			"resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
+			"integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
+			"dev": true
+		},
 		"node_modules/needle": {
 			"version": "2.9.1",
 			"resolved": "https://registry.npmjs.org/needle/-/needle-2.9.1.tgz",
@@ -4838,6 +5813,18 @@
 				"node": ">= 8"
 			}
 		},
+		"node_modules/parent-module": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+			"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+			"dev": true,
+			"dependencies": {
+				"callsites": "^3.0.0"
+			},
+			"engines": {
+				"node": ">=6"
+			}
+		},
 		"node_modules/parse5": {
 			"version": "7.1.2",
 			"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
@@ -4900,6 +5887,15 @@
 			"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
 			"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
 		},
+		"node_modules/path-type": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+			"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+			"dev": true,
+			"engines": {
+				"node": ">=8"
+			}
+		},
 		"node_modules/peek-readable": {
 			"version": "4.1.0",
 			"resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz",
@@ -4917,6 +5913,18 @@
 			"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
 			"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
 		},
+		"node_modules/picomatch": {
+			"version": "2.3.1",
+			"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+			"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+			"dev": true,
+			"engines": {
+				"node": ">=8.6"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/jonschlinkert"
+			}
+		},
 		"node_modules/prelude-ls": {
 			"version": "1.1.2",
 			"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
@@ -5090,6 +6098,26 @@
 				"inherits": "~2.0.3"
 			}
 		},
+		"node_modules/queue-microtask": {
+			"version": "1.2.3",
+			"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+			"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+			"dev": true,
+			"funding": [
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/feross"
+				},
+				{
+					"type": "patreon",
+					"url": "https://www.patreon.com/feross"
+				},
+				{
+					"type": "consulting",
+					"url": "https://feross.org/support"
+				}
+			]
+		},
 		"node_modules/range-parser": {
 			"version": "1.2.1",
 			"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@@ -5188,6 +6216,18 @@
 			"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
 			"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
 		},
+		"node_modules/regexpp": {
+			"version": "3.2.0",
+			"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
+			"integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
+			"dev": true,
+			"engines": {
+				"node": ">=8"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/mysticatea"
+			}
+		},
 		"node_modules/require-directory": {
 			"version": "2.1.1",
 			"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@@ -5209,6 +6249,15 @@
 			"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
 			"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="
 		},
+		"node_modules/resolve-from": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+			"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+			"dev": true,
+			"engines": {
+				"node": ">=4"
+			}
+		},
 		"node_modules/retry": {
 			"version": "0.12.0",
 			"resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
@@ -5218,6 +6267,16 @@
 				"node": ">= 4"
 			}
 		},
+		"node_modules/reusify": {
+			"version": "1.0.4",
+			"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+			"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+			"dev": true,
+			"engines": {
+				"iojs": ">=1.0.0",
+				"node": ">=0.10.0"
+			}
+		},
 		"node_modules/rimraf": {
 			"version": "3.0.2",
 			"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@@ -5232,6 +6291,29 @@
 				"url": "https://github.com/sponsors/isaacs"
 			}
 		},
+		"node_modules/run-parallel": {
+			"version": "1.2.0",
+			"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+			"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+			"dev": true,
+			"funding": [
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/feross"
+				},
+				{
+					"type": "patreon",
+					"url": "https://www.patreon.com/feross"
+				},
+				{
+					"type": "consulting",
+					"url": "https://feross.org/support"
+				}
+			],
+			"dependencies": {
+				"queue-microtask": "^1.2.2"
+			}
+		},
 		"node_modules/safe-buffer": {
 			"version": "5.1.2",
 			"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@@ -5393,6 +6475,15 @@
 			"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
 			"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
 		},
+		"node_modules/slash": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+			"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+			"dev": true,
+			"engines": {
+				"node": ">=8"
+			}
+		},
 		"node_modules/smart-buffer": {
 			"version": "4.2.0",
 			"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
@@ -5564,6 +6655,18 @@
 				"node": ">=6"
 			}
 		},
+		"node_modules/strip-json-comments": {
+			"version": "3.1.1",
+			"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+			"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+			"dev": true,
+			"engines": {
+				"node": ">=8"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
 		"node_modules/strnum": {
 			"version": "1.0.5",
 			"resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz",
@@ -5639,6 +6742,12 @@
 			"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
 			"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
 		},
+		"node_modules/text-table": {
+			"version": "0.2.0",
+			"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+			"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+			"dev": true
+		},
 		"node_modules/thenify": {
 			"version": "3.3.1",
 			"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
@@ -5666,6 +6775,18 @@
 				"node": ">=0.2.6"
 			}
 		},
+		"node_modules/to-regex-range": {
+			"version": "5.0.1",
+			"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+			"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+			"dev": true,
+			"dependencies": {
+				"is-number": "^7.0.0"
+			},
+			"engines": {
+				"node": ">=8.0"
+			}
+		},
 		"node_modules/toidentifier": {
 			"version": "1.0.1",
 			"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
@@ -5742,6 +6863,27 @@
 			"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
 			"integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA=="
 		},
+		"node_modules/tsutils": {
+			"version": "3.21.0",
+			"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+			"integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+			"dev": true,
+			"dependencies": {
+				"tslib": "^1.8.1"
+			},
+			"engines": {
+				"node": ">= 6"
+			},
+			"peerDependencies": {
+				"typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
+			}
+		},
+		"node_modules/tsutils/node_modules/tslib": {
+			"version": "1.14.1",
+			"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+			"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+			"dev": true
+		},
 		"node_modules/type-check": {
 			"version": "0.3.2",
 			"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
@@ -5753,6 +6895,18 @@
 				"node": ">= 0.8.0"
 			}
 		},
+		"node_modules/type-fest": {
+			"version": "0.20.2",
+			"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+			"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+			"dev": true,
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
 		"node_modules/type-is": {
 			"version": "1.6.18",
 			"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
@@ -6277,6 +7431,18 @@
 			"engines": {
 				"node": ">=6"
 			}
+		},
+		"node_modules/yocto-queue": {
+			"version": "0.1.0",
+			"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+			"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+			"dev": true,
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
 		}
 	}
 }
diff --git a/package.json b/package.json
index 61791697..8f08068e 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,7 @@
 		"start:cdn": "node dist/cdn/start.js",
 		"start:gateway": "node dist/gateway/start.js",
 		"build": "tsc -p .",
+		"lint": "eslint .",
 		"setup": "npm run build && npm run generate:schema",
 		"sync:db": "npm run build && node scripts/syncronise.js",
 		"generate:rights": "node scripts/rights.js",
@@ -53,11 +54,14 @@
 		"@types/probe-image-size": "^7.2.0",
 		"@types/sharp": "^0.31.0",
 		"@types/ws": "^8.5.3",
+		"@typescript-eslint/eslint-plugin": "^5.48.2",
+		"@typescript-eslint/parser": "^5.48.2",
+		"eslint": "^8.32.0",
 		"express": "^4.18.1",
 		"husky": "^8.0.0",
 		"prettier": "^2.7.1",
 		"pretty-quick": "^3.1.3",
-		"typescript": "^4.8.3"
+		"typescript": "^4.9.4"
 	},
 	"dependencies": {
 		"@aws-sdk/client-s3": "^3.178.0",
diff --git a/scripts/util/getRouteDescriptions.js b/scripts/util/getRouteDescriptions.js
index 274c0d14..649cafaf 100644
--- a/scripts/util/getRouteDescriptions.js
+++ b/scripts/util/getRouteDescriptions.js
@@ -32,7 +32,7 @@ function registerPath(file, method, prefix, path, ...args) {
 	const sourceFile = file.replace("/dist/", "/src/").replace(".js", ".ts");
 	const opts = args.find((x) => typeof x === "object");
 	if (opts) {
-		routes.set(urlPath + "|" + method, opts); // @ts-ignore
+		routes.set(urlPath + "|" + method, opts);
 		opts.file = sourceFile;
 		// console.log(method, urlPath, opts);
 	} else {
@@ -46,7 +46,6 @@ function routeOptions(opts) {
 	return opts;
 }
 
-// @ts-ignore
 RouteUtility.route = routeOptions;
 
 express.Router = (opts) => {
diff --git a/src/api/Server.ts b/src/api/Server.ts
index 4660e6b1..0177be40 100644
--- a/src/api/Server.ts
+++ b/src/api/Server.ts
@@ -22,7 +22,7 @@ import { Authentication, CORS } from "./middlewares/";
 import { Config, initDatabase, initEvent, Sentry } from "@fosscord/util";
 import { ErrorHandler } from "./middlewares/ErrorHandler";
 import { BodyParser } from "./middlewares/BodyParser";
-import { Router, Request, Response, NextFunction } from "express";
+import { Router, Request, Response } from "express";
 import path from "path";
 import { initRateLimits } from "./middlewares/RateLimit";
 import TestClient from "./middlewares/TestClient";
@@ -32,12 +32,12 @@ import { initInstance } from "./util/handlers/Instance";
 import { registerRoutes } from "@fosscord/util";
 import { red } from "picocolors";
 
-export interface FosscordServerOptions extends ServerOptions {}
+export type FosscordServerOptions = ServerOptions;
 
 declare global {
+	// eslint-disable-next-line @typescript-eslint/no-namespace
 	namespace Express {
 		interface Request {
-			// @ts-ignore
 			server: FosscordServer;
 		}
 	}
@@ -47,6 +47,7 @@ export class FosscordServer extends Server {
 	public declare options: FosscordServerOptions;
 
 	constructor(opts?: Partial<FosscordServerOptions>) {
+		// eslint-disable-next-line @typescript-eslint/ban-ts-comment
 		// @ts-ignore
 		super({ ...opts, errorHandler: false, jsonBody: false });
 	}
@@ -58,12 +59,12 @@ export class FosscordServer extends Server {
 		await initInstance();
 		await Sentry.init(this.app);
 
-		let logRequests = process.env["LOG_REQUESTS"] != undefined;
+		const logRequests = process.env["LOG_REQUESTS"] != undefined;
 		if (logRequests) {
 			this.app.use(
 				morgan("combined", {
 					skip: (req, res) => {
-						var skip = !(
+						let skip = !(
 							process.env["LOG_REQUESTS"]?.includes(
 								res.statusCode.toString(),
 							) ?? false
@@ -80,7 +81,9 @@ export class FosscordServer extends Server {
 		this.app.use(BodyParser({ inflate: true, limit: "10mb" }));
 
 		const app = this.app;
-		const api = Router(); // @ts-ignore
+		const api = Router();
+		// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+		// @ts-ignore
 		this.app = api;
 
 		api.use(Authentication);
@@ -95,7 +98,7 @@ export class FosscordServer extends Server {
 		// 404 is not an error in express, so this should not be an error middleware
 		// this is a fine place to put the 404 handler because its after we register the routes
 		// and since its not an error middleware, our error handler below still works.
-		api.use("*", (req: Request, res: Response, next: NextFunction) => {
+		api.use("*", (req: Request, res: Response) => {
 			res.status(404).json({
 				message: "404 endpoint not found",
 				code: 0,
diff --git a/src/api/middlewares/Authentication.ts b/src/api/middlewares/Authentication.ts
index 208c54d6..8e0dcc7c 100644
--- a/src/api/middlewares/Authentication.ts
+++ b/src/api/middlewares/Authentication.ts
@@ -54,11 +54,12 @@ export const API_PREFIX = /^\/api(\/v\d+)?/;
 export const API_PREFIX_TRAILING_SLASH = /^\/api(\/v\d+)?\//;
 
 declare global {
+	// eslint-disable-next-line @typescript-eslint/no-namespace
 	namespace Express {
 		interface Request {
 			user_id: string;
 			user_bot: boolean;
-			token: string;
+			token: { id: string; iat: number };
 			rights: Rights;
 		}
 	}
@@ -87,7 +88,7 @@ export async function Authentication(
 	try {
 		const { jwtSecret } = Config.get().security;
 
-		const { decoded, user }: any = await checkToken(
+		const { decoded, user } = await checkToken(
 			req.headers.authorization,
 			jwtSecret,
 		);
@@ -97,7 +98,8 @@ export async function Authentication(
 		req.user_bot = user.bot;
 		req.rights = new Rights(Number(user.rights));
 		return next();
-	} catch (error: any) {
-		return next(new HTTPError(error?.toString(), 400));
+	} catch (error) {
+		// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+		return next(new HTTPError(error!.toString(), 400));
 	}
 }
diff --git a/src/api/middlewares/RateLimit.ts b/src/api/middlewares/RateLimit.ts
index ae102c94..1a28f356 100644
--- a/src/api/middlewares/RateLimit.ts
+++ b/src/api/middlewares/RateLimit.ts
@@ -42,7 +42,7 @@ type RateLimit = {
 	expires_at: Date;
 };
 
-let Cache = new Map<string, RateLimit>();
+const Cache = new Map<string, RateLimit>();
 const EventRateLimit = "RATELIMIT";
 
 export default function rateLimit(opts: {
@@ -57,12 +57,8 @@ export default function rateLimit(opts: {
 	error?: boolean;
 	success?: boolean;
 	onlyIp?: boolean;
-}): any {
-	return async (
-		req: Request,
-		res: Response,
-		next: NextFunction,
-	): Promise<any> => {
+}) {
+	return async (req: Request, res: Response, next: NextFunction) => {
 		// exempt user? if so, immediately short circuit
 		if (req.user_id) {
 			const rights = await getRights(req.user_id);
@@ -85,7 +81,7 @@ export default function rateLimit(opts: {
 		)
 			max_hits = opts.MODIFY;
 
-		let offender = Cache.get(executor_id + bucket_id);
+		const offender = Cache.get(executor_id + bucket_id);
 
 		if (offender) {
 			let reset = offender.expires_at.getTime();
diff --git a/src/api/routes/applications/#id/bot/index.ts b/src/api/routes/applications/#id/bot/index.ts
index 7d0a637e..9bc3c571 100644
--- a/src/api/routes/applications/#id/bot/index.ts
+++ b/src/api/routes/applications/#id/bot/index.ts
@@ -64,8 +64,8 @@ router.post("/", route({}), async (req: Request, res: Response) => {
 });
 
 router.post("/reset", route({}), async (req: Request, res: Response) => {
-	let bot = await User.findOneOrFail({ where: { id: req.params.id } });
-	let owner = await User.findOneOrFail({ where: { id: req.user_id } });
+	const bot = await User.findOneOrFail({ where: { id: req.params.id } });
+	const owner = await User.findOneOrFail({ where: { id: req.user_id } });
 
 	if (owner.id != req.user_id)
 		throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION;
@@ -80,7 +80,7 @@ router.post("/reset", route({}), async (req: Request, res: Response) => {
 
 	await bot.save();
 
-	let token = await generateToken(bot.id);
+	const token = await generateToken(bot.id);
 
 	res.json({ token }).status(200);
 });
diff --git a/src/api/routes/applications/#id/index.ts b/src/api/routes/applications/#id/index.ts
index 2b283880..59e90168 100644
--- a/src/api/routes/applications/#id/index.ts
+++ b/src/api/routes/applications/#id/index.ts
@@ -20,10 +20,8 @@ import { Request, Response, Router } from "express";
 import { route } from "@fosscord/api";
 import {
 	Application,
-	OrmUtils,
 	DiscordApiErrors,
 	ApplicationModifySchema,
-	User,
 } from "@fosscord/util";
 import { verifyToken } from "node-2fa";
 import { HTTPError } from "lambert-server";
diff --git a/src/api/routes/applications/#id/skus.ts b/src/api/routes/applications/#id/skus.ts
index 23e6eb6b..5a3a479f 100644
--- a/src/api/routes/applications/#id/skus.ts
+++ b/src/api/routes/applications/#id/skus.ts
@@ -18,7 +18,6 @@
 
 import { Request, Response, Router } from "express";
 import { route } from "@fosscord/api";
-import { Application, OrmUtils, Team, trimSpecial, User } from "@fosscord/util";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/applications/index.ts b/src/api/routes/applications/index.ts
index 6ea24870..859ee145 100644
--- a/src/api/routes/applications/index.ts
+++ b/src/api/routes/applications/index.ts
@@ -28,7 +28,7 @@ import {
 const router: Router = Router();
 
 router.get("/", route({}), async (req: Request, res: Response) => {
-	let results = await Application.find({
+	const results = await Application.find({
 		where: { owner: { id: req.user_id } },
 		relations: ["owner", "bot"],
 	});
diff --git a/src/api/routes/auth/generate-registration-tokens.ts b/src/api/routes/auth/generate-registration-tokens.ts
index 64e3b0a6..c79d2a59 100644
--- a/src/api/routes/auth/generate-registration-tokens.ts
+++ b/src/api/routes/auth/generate-registration-tokens.ts
@@ -32,7 +32,7 @@ router.get(
 			? parseInt(req.query.length as string)
 			: 255;
 
-		let tokens: ValidRegistrationToken[] = [];
+		const tokens: ValidRegistrationToken[] = [];
 
 		for (let i = 0; i < count; i++) {
 			const token = ValidRegistrationToken.create({
diff --git a/src/api/routes/auth/login.ts b/src/api/routes/auth/login.ts
index 5f1b7a14..4d367546 100644
--- a/src/api/routes/auth/login.ts
+++ b/src/api/routes/auth/login.ts
@@ -74,7 +74,7 @@ router.post(
 				"totp_secret",
 				"mfa_enabled",
 			],
-		}).catch((e) => {
+		}).catch(() => {
 			throw FieldErrors({
 				login: {
 					message: req.t("auth:login.INVALID_LOGIN"),
diff --git a/src/api/routes/auth/mfa/totp.ts b/src/api/routes/auth/mfa/totp.ts
index 42485535..65cdd397 100644
--- a/src/api/routes/auth/mfa/totp.ts
+++ b/src/api/routes/auth/mfa/totp.ts
@@ -27,8 +27,8 @@ router.post(
 	"/",
 	route({ body: "TotpSchema" }),
 	async (req: Request, res: Response) => {
-		const { code, ticket, gift_code_sku_id, login_source } =
-			req.body as TotpSchema;
+		// const { code, ticket, gift_code_sku_id, login_source } =
+		const { code, ticket } = req.body as TotpSchema;
 
 		const user = await User.findOneOrFail({
 			where: {
@@ -47,7 +47,7 @@ router.post(
 		});
 
 		if (!backup) {
-			const ret = verifyToken(user.totp_secret!, code);
+			const ret = verifyToken(user.totp_secret || "", code);
 			if (!ret || ret.delta != 0)
 				throw new HTTPError(
 					req.t("auth:login.INVALID_TOTP_CODE"),
diff --git a/src/api/routes/auth/register.ts b/src/api/routes/auth/register.ts
index b98f17c5..0bf8efae 100644
--- a/src/api/routes/auth/register.ts
+++ b/src/api/routes/auth/register.ts
@@ -36,7 +36,7 @@ import {
 } from "@fosscord/api";
 import bcrypt from "bcrypt";
 import { HTTPError } from "lambert-server";
-import { LessThan, MoreThan } from "typeorm";
+import { MoreThan } from "typeorm";
 
 const router: Router = Router();
 
@@ -53,12 +53,12 @@ router.post(
 		let regTokenUsed = false;
 		if (req.get("Referrer") && req.get("Referrer")?.includes("token=")) {
 			// eg theyre on https://staging.fosscord.com/register?token=whatever
-			const token = req.get("Referrer")!.split("token=")[1].split("&")[0];
+			const token = req.get("Referrer")?.split("token=")[1].split("&")[0];
 			if (token) {
-				const regToken = await ValidRegistrationToken.findOne({
+				const regToken = await ValidRegistrationToken.findOneOrFail({
 					where: { token, expires_at: MoreThan(new Date()) },
 				});
-				await ValidRegistrationToken.delete({ token });
+				await regToken.remove();
 				regTokenUsed = true;
 				console.log(
 					`[REGISTER] Registration token ${token} used for registration!`,
@@ -71,7 +71,7 @@ router.post(
 		}
 
 		// email will be slightly modified version of the user supplied email -> e.g. protection against GMail Trick
-		let email = adjustEmail(body.email);
+		const email = adjustEmail(body.email);
 
 		// check if registration is allowed
 		if (!regTokenUsed && !register.allowNewRegistration) {
diff --git a/src/api/routes/channels/#channel_id/followers.ts b/src/api/routes/channels/#channel_id/followers.ts
index 0ff784df..a9d5d4ee 100644
--- a/src/api/routes/channels/#channel_id/followers.ts
+++ b/src/api/routes/channels/#channel_id/followers.ts
@@ -16,7 +16,7 @@
 	along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-import { Router, Response, Request } from "express";
+import { Router } from "express";
 const router: Router = Router();
 // TODO:
 
diff --git a/src/api/routes/channels/#channel_id/index.ts b/src/api/routes/channels/#channel_id/index.ts
index 5bcd3a84..4a2023d2 100644
--- a/src/api/routes/channels/#channel_id/index.ts
+++ b/src/api/routes/channels/#channel_id/index.ts
@@ -92,7 +92,7 @@ router.patch(
 	"/",
 	route({ body: "ChannelModifySchema", permission: "MANAGE_CHANNELS" }),
 	async (req: Request, res: Response) => {
-		var payload = req.body as ChannelModifySchema;
+		const payload = req.body as ChannelModifySchema;
 		const { channel_id } = req.params;
 		if (payload.icon)
 			payload.icon = await handleFile(
diff --git a/src/api/routes/channels/#channel_id/invites.ts b/src/api/routes/channels/#channel_id/invites.ts
index b9105bea..49620aaf 100644
--- a/src/api/routes/channels/#channel_id/invites.ts
+++ b/src/api/routes/channels/#channel_id/invites.ts
@@ -86,7 +86,6 @@ router.get(
 	"/",
 	route({ permission: "MANAGE_CHANNELS" }),
 	async (req: Request, res: Response) => {
-		const { user_id } = req;
 		const { channel_id } = req.params;
 		const channel = await Channel.findOneOrFail({
 			where: { id: channel_id },
diff --git a/src/api/routes/channels/#channel_id/messages/#message_id/index.ts b/src/api/routes/channels/#channel_id/messages/#message_id/index.ts
index 3d9a69be..9ea33340 100644
--- a/src/api/routes/channels/#channel_id/messages/#message_id/index.ts
+++ b/src/api/routes/channels/#channel_id/messages/#message_id/index.ts
@@ -30,7 +30,6 @@ import {
 	Snowflake,
 	uploadFile,
 	MessageCreateSchema,
-	DiscordApiErrors,
 } from "@fosscord/util";
 import { Router, Response, Request } from "express";
 import multer from "multer";
@@ -59,7 +58,7 @@ router.patch(
 	}),
 	async (req: Request, res: Response) => {
 		const { message_id, channel_id } = req.params;
-		var body = req.body as MessageCreateSchema;
+		let body = req.body as MessageCreateSchema;
 
 		const message = await Message.findOneOrFail({
 			where: { id: message_id, channel_id },
@@ -85,6 +84,7 @@ router.patch(
 		const new_message = await handleMessage({
 			...message,
 			// TODO: should message_reference be overridable?
+			// eslint-disable-next-line @typescript-eslint/ban-ts-comment
 			// @ts-ignore
 			message_reference: message.message_reference,
 			...body,
@@ -127,7 +127,7 @@ router.put(
 	}),
 	async (req: Request, res: Response) => {
 		const { channel_id, message_id } = req.params;
-		var body = req.body as MessageCreateSchema;
+		const body = req.body as MessageCreateSchema;
 		const attachments: Attachment[] = [];
 
 		const rights = await getRights(req.user_id);
@@ -171,7 +171,7 @@ router.put(
 
 		const embeds = body.embeds || [];
 		if (body.embed) embeds.push(body.embed);
-		let message = await handleMessage({
+		const message = await handleMessage({
 			...body,
 			type: 0,
 			pinned: false,
@@ -197,7 +197,10 @@ router.put(
 			channel.save(),
 		]);
 
-		postHandleMessage(message).catch((e) => {}); // no await as it shouldnt block the message send function and silently catch error
+		// no await as it shouldnt block the message send function and silently catch error
+		postHandleMessage(message).catch((e) =>
+			console.error("[Message] post-message handler failed", e),
+		);
 
 		return res.json(message);
 	},
diff --git a/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts b/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts
index bf6d43e5..c3598b24 100644
--- a/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts
+++ b/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts
@@ -165,13 +165,13 @@ router.put(
 				x.emoji.name === emoji.name,
 		);
 
-		if (!already_added) req.permission!.hasThrow("ADD_REACTIONS");
+		if (!already_added) req.permission?.hasThrow("ADD_REACTIONS");
 
 		if (emoji.id) {
 			const external_emoji = await Emoji.findOneOrFail({
 				where: { id: emoji.id },
 			});
-			if (!already_added) req.permission!.hasThrow("USE_EXTERNAL_EMOJIS");
+			if (!already_added) req.permission?.hasThrow("USE_EXTERNAL_EMOJIS");
 			emoji.animated = external_emoji.animated;
 			emoji.name = external_emoji.name;
 		}
@@ -214,7 +214,8 @@ router.delete(
 	"/:emoji/:user_id",
 	route({}),
 	async (req: Request, res: Response) => {
-		var { message_id, channel_id, user_id } = req.params;
+		let { user_id } = req.params;
+		const { message_id, channel_id } = req.params;
 
 		const emoji = getEmoji(req.params.emoji);
 
diff --git a/src/api/routes/channels/#channel_id/messages/bulk-delete.ts b/src/api/routes/channels/#channel_id/messages/bulk-delete.ts
index ad5d24c8..ee039d3e 100644
--- a/src/api/routes/channels/#channel_id/messages/bulk-delete.ts
+++ b/src/api/routes/channels/#channel_id/messages/bulk-delete.ts
@@ -50,7 +50,7 @@ router.post(
 		const rights = await getRights(req.user_id);
 		rights.hasThrow("SELF_DELETE_MESSAGES");
 
-		let superuser = rights.has("MANAGE_MESSAGES");
+		const superuser = rights.has("MANAGE_MESSAGES");
 		const permission = await getPermission(
 			req.user_id,
 			channel?.guild_id,
diff --git a/src/api/routes/channels/#channel_id/messages/index.ts b/src/api/routes/channels/#channel_id/messages/index.ts
index 6e4f06a2..76f6a0dc 100644
--- a/src/api/routes/channels/#channel_id/messages/index.ts
+++ b/src/api/routes/channels/#channel_id/messages/index.ts
@@ -31,23 +31,16 @@ import {
 	Snowflake,
 	uploadFile,
 	Member,
-	Role,
 	MessageCreateSchema,
 	ReadState,
-	DiscordApiErrors,
-	getRights,
 	Rights,
+	Reaction,
+	User,
 } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
-import {
-	handleMessage,
-	postHandleMessage,
-	route,
-	getIpAdress,
-} from "@fosscord/api";
+import { handleMessage, postHandleMessage, route } from "@fosscord/api";
 import multer from "multer";
-import { yellow } from "picocolors";
-import { FindManyOptions, LessThan, MoreThan } from "typeorm";
+import { FindManyOptions, FindOperator, LessThan, MoreThan } from "typeorm";
 import { URL } from "url";
 
 const router: Router = Router();
@@ -93,7 +86,7 @@ router.get("/", async (req: Request, res: Response) => {
 	if (limit < 1 || limit > 100)
 		throw new HTTPError("limit must be between 1 and 100", 422);
 
-	var halfLimit = Math.floor(limit / 2);
+	const halfLimit = Math.floor(limit / 2);
 
 	const permissions = await getPermission(
 		req.user_id,
@@ -103,7 +96,9 @@ router.get("/", async (req: Request, res: Response) => {
 	permissions.hasThrow("VIEW_CHANNEL");
 	if (!permissions.has("READ_MESSAGE_HISTORY")) return res.json([]);
 
-	var query: FindManyOptions<Message> & { where: { id?: any } } = {
+	const query: FindManyOptions<Message> & {
+		where: { id?: FindOperator<string> | FindOperator<string>[] };
+	} = {
 		order: { timestamp: "DESC" },
 		take: limit,
 		where: { channel_id },
@@ -140,23 +135,21 @@ router.get("/", async (req: Request, res: Response) => {
 	const endpoint = Config.get().cdn.endpointPublic;
 
 	return res.json(
-		messages.map((x: any) => {
-			(x.reactions || []).forEach((x: any) => {
-				// @ts-ignore
-				if ((x.user_ids || []).includes(req.user_id)) x.me = true;
-				// @ts-ignore
-				delete x.user_ids;
+		messages.map((x: Partial<Message>) => {
+			(x.reactions || []).forEach((y: Partial<Reaction>) => {
+				// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+				//@ts-ignore
+				if ((y.user_ids || []).includes(req.user_id)) y.me = true;
+				delete y.user_ids;
 			});
-			// @ts-ignore
 			if (!x.author)
-				x.author = {
+				x.author = User.create({
 					id: "4",
 					discriminator: "0000",
 					username: "Fosscord Ghost",
-					public_flags: "0",
-					avatar: null,
-				};
-			x.attachments?.forEach((y: any) => {
+					public_flags: 0,
+				});
+			x.attachments?.forEach((y: Attachment) => {
 				// dynamically set attachment proxy_url in case the endpoint changed
 				const uri = y.proxy_url.startsWith("http")
 					? y.proxy_url
@@ -168,7 +161,7 @@ router.get("/", async (req: Request, res: Response) => {
 
 			/**
 			Some clients ( discord.js ) only check if a property exists within the response,
-			which causes erorrs when, say, the `application` property is `null`.
+			which causes errors when, say, the `application` property is `null`.
 			**/
 
 			// for (var curr in x) {
@@ -216,7 +209,7 @@ router.post(
 	}),
 	async (req: Request, res: Response) => {
 		const { channel_id } = req.params;
-		var body = req.body as MessageCreateSchema;
+		const body = req.body as MessageCreateSchema;
 		const attachments: Attachment[] = [];
 
 		const channel = await Channel.findOneOrFail({
@@ -244,7 +237,7 @@ router.post(
 		}
 
 		if (!req.rights.has(Rights.FLAGS.BYPASS_RATE_LIMITS)) {
-			var limits = Config.get().limits;
+			const limits = Config.get().limits;
 			if (limits.absoluteRate.register.enabled) {
 				const count = await Message.count({
 					where: {
@@ -269,7 +262,7 @@ router.post(
 		}
 
 		const files = (req.files as Express.Multer.File[]) ?? [];
-		for (var currFile of files) {
+		for (const currFile of files) {
 			try {
 				const file = await uploadFile(
 					`/attachments/${channel.id}`,
@@ -279,13 +272,13 @@ router.post(
 					Attachment.create({ ...file, proxy_url: file.url }),
 				);
 			} catch (error) {
-				return res.status(400).json({ message: error!.toString() });
+				return res.status(400).json({ message: error?.toString() });
 			}
 		}
 
 		const embeds = body.embeds || [];
 		if (body.embed) embeds.push(body.embed);
-		let message = await handleMessage({
+		const message = await handleMessage({
 			...body,
 			type: 0,
 			pinned: false,
@@ -304,7 +297,7 @@ router.post(
 
 			// Only one recipients should be closed here, since in group DMs the recipient is deleted not closed
 			await Promise.all(
-				channel.recipients!.map((recipient) => {
+				channel.recipients?.map((recipient) => {
 					if (recipient.closed) {
 						recipient.closed = false;
 						return Promise.all([
@@ -318,7 +311,7 @@ router.post(
 							}),
 						]);
 					}
-				}),
+				}) || [],
 			);
 		}
 
@@ -332,6 +325,7 @@ router.post(
 				});
 			}
 
+			// eslint-disable-next-line @typescript-eslint/ban-ts-comment
 			//@ts-ignore
 			message.member.roles = message.member.roles
 				.filter((x) => x.id != x.guild_id)
@@ -362,7 +356,10 @@ router.post(
 			channel.save(),
 		]);
 
-		postHandleMessage(message).catch((e) => {}); // no await as it shouldnt block the message send function and silently catch error
+		// no await as it shouldnt block the message send function and silently catch error
+		postHandleMessage(message).catch((e) =>
+			console.error("[Message] post-message handler failed", e),
+		);
 
 		return res.json(message);
 	},
diff --git a/src/api/routes/channels/#channel_id/permissions.ts b/src/api/routes/channels/#channel_id/permissions.ts
index 7aa29700..da448678 100644
--- a/src/api/routes/channels/#channel_id/permissions.ts
+++ b/src/api/routes/channels/#channel_id/permissions.ts
@@ -43,7 +43,7 @@ router.put(
 		const { channel_id, overwrite_id } = req.params;
 		const body = req.body as ChannelPermissionOverwriteSchema;
 
-		var channel = await Channel.findOneOrFail({
+		const channel = await Channel.findOneOrFail({
 			where: { id: channel_id },
 		});
 		if (!channel.guild_id) throw new HTTPError("Channel not found", 404);
@@ -56,22 +56,24 @@ router.put(
 				throw new HTTPError("user not found", 404);
 		} else throw new HTTPError("type not supported", 501);
 
-		//@ts-ignore
-		var overwrite: ChannelPermissionOverwrite =
+		let overwrite: ChannelPermissionOverwrite | undefined =
 			channel.permission_overwrites?.find((x) => x.id === overwrite_id);
 		if (!overwrite) {
-			// @ts-ignore
 			overwrite = {
 				id: overwrite_id,
 				type: body.type,
+				allow: "0",
+				deny: "0",
 			};
-			channel.permission_overwrites!.push(overwrite);
+			channel.permission_overwrites?.push(overwrite);
 		}
 		overwrite.allow = String(
-			req.permission!.bitfield & (BigInt(body.allow) || BigInt("0")),
+			(req.permission?.bitfield || 0n) &
+				(BigInt(body.allow) || BigInt("0")),
 		);
 		overwrite.deny = String(
-			req.permission!.bitfield & (BigInt(body.deny) || BigInt("0")),
+			(req.permission?.bitfield || 0n) &
+				(BigInt(body.deny) || BigInt("0")),
 		);
 
 		await Promise.all([
@@ -99,7 +101,7 @@ router.delete(
 		});
 		if (!channel.guild_id) throw new HTTPError("Channel not found", 404);
 
-		channel.permission_overwrites = channel.permission_overwrites!.filter(
+		channel.permission_overwrites = channel.permission_overwrites?.filter(
 			(x) => x.id === overwrite_id,
 		);
 
diff --git a/src/api/routes/channels/#channel_id/pins.ts b/src/api/routes/channels/#channel_id/pins.ts
index f48e0ff5..28419383 100644
--- a/src/api/routes/channels/#channel_id/pins.ts
+++ b/src/api/routes/channels/#channel_id/pins.ts
@@ -21,13 +21,11 @@ import {
 	ChannelPinsUpdateEvent,
 	Config,
 	emitEvent,
-	getPermission,
 	Message,
 	MessageUpdateEvent,
 	DiscordApiErrors,
 } from "@fosscord/util";
 import { Router, Request, Response } from "express";
-import { HTTPError } from "lambert-server";
 import { route } from "@fosscord/api";
 
 const router: Router = Router();
@@ -43,7 +41,7 @@ router.put(
 		});
 
 		// * in dm channels anyone can pin messages -> only check for guilds
-		if (message.guild_id) req.permission!.hasThrow("MANAGE_MESSAGES");
+		if (message.guild_id) req.permission?.hasThrow("MANAGE_MESSAGES");
 
 		const pinned_count = await Message.count({
 			where: { channel: { id: channel_id }, pinned: true },
@@ -83,7 +81,7 @@ router.delete(
 		const channel = await Channel.findOneOrFail({
 			where: { id: channel_id },
 		});
-		if (channel.guild_id) req.permission!.hasThrow("MANAGE_MESSAGES");
+		if (channel.guild_id) req.permission?.hasThrow("MANAGE_MESSAGES");
 
 		const message = await Message.findOneOrFail({
 			where: { id: message_id },
@@ -120,7 +118,7 @@ router.get(
 	async (req: Request, res: Response) => {
 		const { channel_id } = req.params;
 
-		let pins = await Message.find({
+		const pins = await Message.find({
 			where: { channel_id: channel_id, pinned: true },
 		});
 
diff --git a/src/api/routes/channels/#channel_id/purge.ts b/src/api/routes/channels/#channel_id/purge.ts
index 05660acf..04d8cfa2 100644
--- a/src/api/routes/channels/#channel_id/purge.ts
+++ b/src/api/routes/channels/#channel_id/purge.ts
@@ -19,10 +19,9 @@
 import { HTTPError } from "lambert-server";
 import { route } from "@fosscord/api";
 import { isTextChannel } from "./messages";
-import { FindManyOptions, Between, Not } from "typeorm";
+import { FindManyOptions, Between, Not, FindOperator } from "typeorm";
 import {
 	Channel,
-	Config,
 	emitEvent,
 	getPermission,
 	getRights,
@@ -69,7 +68,9 @@ router.post(
 
 		// TODO: send the deletion event bite-by-bite to prevent client stress
 
-		var query: FindManyOptions<Message> & { where: { id?: any } } = {
+		const query: FindManyOptions<Message> & {
+			where: { id?: FindOperator<string> };
+		} = {
 			order: { id: "ASC" },
 			// take: limit,
 			where: {
@@ -93,7 +94,6 @@ router.post(
 		};
 
 		const messages = await Message.find(query);
-		const endpoint = Config.get().cdn.endpointPublic;
 
 		if (messages.length == 0) {
 			res.sendStatus(304);
diff --git a/src/api/routes/channels/#channel_id/recipients.ts b/src/api/routes/channels/#channel_id/recipients.ts
index 6928dd34..252a8ef0 100644
--- a/src/api/routes/channels/#channel_id/recipients.ts
+++ b/src/api/routes/channels/#channel_id/recipients.ts
@@ -41,7 +41,7 @@ router.put("/:user_id", route({}), async (req: Request, res: Response) => {
 
 	if (channel.type !== ChannelType.GROUP_DM) {
 		const recipients = [
-			...channel.recipients!.map((r) => r.user_id),
+			...(channel.recipients?.map((r) => r.user_id) || []),
 			user_id,
 		].unique();
 
@@ -51,11 +51,11 @@ router.put("/:user_id", route({}), async (req: Request, res: Response) => {
 		);
 		return res.status(201).json(new_channel);
 	} else {
-		if (channel.recipients!.map((r) => r.user_id).includes(user_id)) {
+		if (channel.recipients?.map((r) => r.user_id).includes(user_id)) {
 			throw DiscordApiErrors.INVALID_RECIPIENT; //TODO is this the right error?
 		}
 
-		channel.recipients!.push(
+		channel.recipients?.push(
 			Recipient.create({ channel_id: channel_id, user_id: user_id }),
 		);
 		await channel.save();
@@ -95,7 +95,7 @@ router.delete("/:user_id", route({}), async (req: Request, res: Response) => {
 	)
 		throw DiscordApiErrors.MISSING_PERMISSIONS;
 
-	if (!channel.recipients!.map((r) => r.user_id).includes(user_id)) {
+	if (!channel.recipients?.map((r) => r.user_id).includes(user_id)) {
 		throw DiscordApiErrors.INVALID_RECIPIENT; //TODO is this the right error?
 	}
 
diff --git a/src/api/routes/channels/#channel_id/webhooks.ts b/src/api/routes/channels/#channel_id/webhooks.ts
index 511933c3..31cae747 100644
--- a/src/api/routes/channels/#channel_id/webhooks.ts
+++ b/src/api/routes/channels/#channel_id/webhooks.ts
@@ -55,10 +55,10 @@ router.post(
 
 		const webhook_count = await Webhook.count({ where: { channel_id } });
 		const { maxWebhooks } = Config.get().limits.channel;
-		if (webhook_count > maxWebhooks)
+		if (maxWebhooks && webhook_count > maxWebhooks)
 			throw DiscordApiErrors.MAXIMUM_WEBHOOKS.withParams(maxWebhooks);
 
-		var { avatar, name } = req.body as WebhookCreateSchema;
+		let { avatar, name } = req.body as WebhookCreateSchema;
 		name = trimSpecial(name);
 
 		// TODO: move this
diff --git a/src/api/routes/discoverable-guilds.ts b/src/api/routes/discoverable-guilds.ts
index 522861eb..8f90d73c 100644
--- a/src/api/routes/discoverable-guilds.ts
+++ b/src/api/routes/discoverable-guilds.ts
@@ -26,8 +26,8 @@ const router = Router();
 
 router.get("/", route({}), async (req: Request, res: Response) => {
 	const { offset, limit, categories } = req.query;
-	var showAllGuilds = Config.get().guild.discovery.showAllGuilds;
-	var configLimit = Config.get().guild.discovery.limit;
+	const showAllGuilds = Config.get().guild.discovery.showAllGuilds;
+	const configLimit = Config.get().guild.discovery.limit;
 	let guilds;
 	if (categories == undefined) {
 		guilds = showAllGuilds
diff --git a/src/api/routes/discovery.ts b/src/api/routes/discovery.ts
index 411c3bc5..1414a617 100644
--- a/src/api/routes/discovery.ts
+++ b/src/api/routes/discovery.ts
@@ -26,7 +26,8 @@ router.get("/categories", route({}), async (req: Request, res: Response) => {
 	// TODO:
 	// Get locale instead
 
-	const { locale, primary_only } = req.query;
+	// const { locale, primary_only } = req.query;
+	const { primary_only } = req.query;
 
 	const out = primary_only
 		? await Categories.find()
diff --git a/src/api/routes/download/index.ts b/src/api/routes/download.ts
index 246c8834..b6c03a48 100644
--- a/src/api/routes/download/index.ts
+++ b/src/api/routes/download.ts
@@ -22,11 +22,6 @@ import { FieldErrors, Release } from "@fosscord/util";
 
 const router = Router();
 
-/*
-	TODO: Putting the download route in /routes/download.ts doesn't register the route, for some reason
-	But putting it here *does*
-*/
-
 router.get("/", route({}), async (req: Request, res: Response) => {
 	const { platform } = req.query;
 
diff --git a/src/api/routes/gifs/search.ts b/src/api/routes/gifs/search.ts
index 02022004..ae63d643 100644
--- a/src/api/routes/gifs/search.ts
+++ b/src/api/routes/gifs/search.ts
@@ -41,7 +41,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 		},
 	);
 
-	const { results } = (await response.json()) as any; // TODO: types
+	const { results } = await response.json();
 
 	res.json(results.map(parseGifResult)).status(200);
 });
diff --git a/src/api/routes/gifs/trending-gifs.ts b/src/api/routes/gifs/trending-gifs.ts
index d3fdb00a..d0698fa0 100644
--- a/src/api/routes/gifs/trending-gifs.ts
+++ b/src/api/routes/gifs/trending-gifs.ts
@@ -41,7 +41,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 		},
 	);
 
-	const { results } = (await response.json()) as any; // TODO: types
+	const { results } = await response.json();
 
 	res.json(results.map(parseGifResult)).status(200);
 });
diff --git a/src/api/routes/gifs/trending.ts b/src/api/routes/gifs/trending.ts
index 5dc43e85..5c872df8 100644
--- a/src/api/routes/gifs/trending.ts
+++ b/src/api/routes/gifs/trending.ts
@@ -25,7 +25,57 @@ import { HTTPError } from "lambert-server";
 
 const router = Router();
 
-export function parseGifResult(result: any) {
+// TODO: Move somewhere else
+enum TENOR_GIF_TYPES {
+	gif,
+	mediumgif,
+	tinygif,
+	nanogif,
+	mp4,
+	loopedmp4,
+	tinymp4,
+	nanomp4,
+	webm,
+	tinywebm,
+	nanowebm,
+}
+
+type TENOR_MEDIA = {
+	preview: string;
+	url: string;
+	dims: number[];
+	size: number;
+};
+
+type TENOR_GIF = {
+	created: number;
+	hasaudio: boolean;
+	id: string;
+	media: { [type in keyof typeof TENOR_GIF_TYPES]: TENOR_MEDIA }[];
+	tags: string[];
+	title: string;
+	itemurl: string;
+	hascaption: boolean;
+	url: string;
+};
+
+type TENOR_CATEGORY = {
+	searchterm: string;
+	path: string;
+	image: string;
+	name: string;
+};
+
+type TENOR_CATEGORIES_RESULTS = {
+	tags: TENOR_CATEGORY[];
+};
+
+type TENOR_TRENDING_RESULTS = {
+	next: string;
+	results: TENOR_GIF[];
+};
+
+export function parseGifResult(result: TENOR_GIF) {
 	return {
 		id: result.id,
 		title: result.title,
@@ -50,7 +100,8 @@ export function getGifApiKey() {
 router.get("/", route({}), async (req: Request, res: Response) => {
 	// TODO: Custom providers
 	// TODO: return gifs as mp4
-	const { media_format, locale } = req.query;
+	// const { media_format, locale } = req.query;
+	const { locale } = req.query;
 
 	const apiKey = getGifApiKey();
 
@@ -75,11 +126,11 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 		),
 	]);
 
-	const { tags } = (await responseSource.json()) as any; // TODO: types
-	const { results } = (await trendGifSource.json()) as any; //TODO: types;
+	const { tags } = (await responseSource.json()) as TENOR_CATEGORIES_RESULTS;
+	const { results } = (await trendGifSource.json()) as TENOR_TRENDING_RESULTS;
 
 	res.json({
-		categories: tags.map((x: any) => ({
+		categories: tags.map((x) => ({
 			name: x.searchterm,
 			src: x.image,
 		})),
diff --git a/src/api/routes/guild-recommendations.ts b/src/api/routes/guild-recommendations.ts
index 13c08734..ac2ad9e7 100644
--- a/src/api/routes/guild-recommendations.ts
+++ b/src/api/routes/guild-recommendations.ts
@@ -25,10 +25,11 @@ import { Like } from "typeorm";
 const router = Router();
 
 router.get("/", route({}), async (req: Request, res: Response) => {
-	const { limit, personalization_disabled } = req.query;
-	var showAllGuilds = Config.get().guild.discovery.showAllGuilds;
+	// const { limit, personalization_disabled } = req.query;
+	const { limit } = req.query;
+	const showAllGuilds = Config.get().guild.discovery.showAllGuilds;
 
-	const genLoadId = (size: Number) =>
+	const genLoadId = (size: number) =>
 		[...Array(size)]
 			.map(() => Math.floor(Math.random() * 16).toString(16))
 			.join("");
diff --git a/src/api/routes/guilds/#guild_id/bans.ts b/src/api/routes/guilds/#guild_id/bans.ts
index efb06fa0..b044689f 100644
--- a/src/api/routes/guilds/#guild_id/bans.ts
+++ b/src/api/routes/guilds/#guild_id/bans.ts
@@ -41,8 +41,8 @@ router.get(
 	async (req: Request, res: Response) => {
 		const { guild_id } = req.params;
 
-		let bans = await Ban.find({ where: { guild_id: guild_id } });
-		let promisesToAwait: object[] = [];
+		const bans = await Ban.find({ where: { guild_id: guild_id } });
+		const promisesToAwait: object[] = [];
 		const bansObj: object[] = [];
 
 		bans.filter((ban) => ban.user_id !== ban.executor_id); // pretend self-bans don't exist to prevent victim chasing
@@ -104,14 +104,14 @@ router.put(
 
 		if (
 			req.user_id === banned_user_id &&
-			banned_user_id === req.permission!.cache.guild?.owner_id
+			banned_user_id === req.permission?.cache.guild?.owner_id
 		)
 			throw new HTTPError(
 				"You are the guild owner, hence can't ban yourself",
 				403,
 			);
 
-		if (req.permission!.cache.guild?.owner_id === banned_user_id)
+		if (req.permission?.cache.guild?.owner_id === banned_user_id)
 			throw new HTTPError("You can't ban the owner", 400);
 
 		const banned_user = await User.getPublicUser(banned_user_id);
@@ -149,7 +149,7 @@ router.put(
 
 		const banned_user = await User.getPublicUser(req.params.user_id);
 
-		if (req.permission!.cache.guild?.owner_id === req.params.user_id)
+		if (req.permission?.cache.guild?.owner_id === req.params.user_id)
 			throw new HTTPError(
 				"You are the guild owner, hence can't ban yourself",
 				403,
@@ -186,7 +186,7 @@ router.delete(
 	async (req: Request, res: Response) => {
 		const { guild_id, user_id } = req.params;
 
-		let ban = await Ban.findOneOrFail({
+		const ban = await Ban.findOneOrFail({
 			where: { guild_id: guild_id, user_id: user_id },
 		});
 
diff --git a/src/api/routes/guilds/#guild_id/channels.ts b/src/api/routes/guilds/#guild_id/channels.ts
index b72f5ddb..acdb5f19 100644
--- a/src/api/routes/guilds/#guild_id/channels.ts
+++ b/src/api/routes/guilds/#guild_id/channels.ts
@@ -68,7 +68,7 @@ router.patch(
 						400,
 					);
 
-				const opts: any = {};
+				const opts: Partial<Channel> = {};
 				if (x.position != null) opts.position = x.position;
 
 				if (x.parent_id) {
diff --git a/src/api/routes/guilds/#guild_id/delete.ts b/src/api/routes/guilds/#guild_id/delete.ts
index 551c6829..9a13c9b4 100644
--- a/src/api/routes/guilds/#guild_id/delete.ts
+++ b/src/api/routes/guilds/#guild_id/delete.ts
@@ -16,17 +16,7 @@
 	along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-import {
-	Channel,
-	emitEvent,
-	GuildDeleteEvent,
-	Guild,
-	Member,
-	Message,
-	Role,
-	Invite,
-	Emoji,
-} from "@fosscord/util";
+import { emitEvent, GuildDeleteEvent, Guild } from "@fosscord/util";
 import { Router, Request, Response } from "express";
 import { HTTPError } from "lambert-server";
 import { route } from "@fosscord/api";
@@ -36,7 +26,7 @@ const router = Router();
 // discord prefixes this route with /delete instead of using the delete method
 // docs are wrong https://discord.com/developers/docs/resources/guild#delete-guild
 router.post("/", route({}), async (req: Request, res: Response) => {
-	var { guild_id } = req.params;
+	const { guild_id } = req.params;
 
 	const guild = await Guild.findOneOrFail({
 		where: { id: guild_id },
diff --git a/src/api/routes/guilds/#guild_id/discovery-requirements.ts b/src/api/routes/guilds/#guild_id/discovery-requirements.ts
index 11dcc33e..de2da6ee 100644
--- a/src/api/routes/guilds/#guild_id/discovery-requirements.ts
+++ b/src/api/routes/guilds/#guild_id/discovery-requirements.ts
@@ -16,8 +16,6 @@
 	along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-import { Guild, Config } from "@fosscord/util";
-
 import { Router, Request, Response } from "express";
 import { route } from "@fosscord/api";
 
diff --git a/src/api/routes/guilds/#guild_id/index.ts b/src/api/routes/guilds/#guild_id/index.ts
index 0df90f56..c262a088 100644
--- a/src/api/routes/guilds/#guild_id/index.ts
+++ b/src/api/routes/guilds/#guild_id/index.ts
@@ -47,10 +47,10 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 			401,
 		);
 
-	// @ts-ignore
-	guild.joined_at = member?.joined_at;
-
-	return res.send(guild);
+	return res.send({
+		...guild,
+		joined_at: member?.joined_at,
+	});
 });
 
 router.patch(
@@ -68,7 +68,7 @@ router.patch(
 				"MANAGE_GUILDS",
 			);
 
-		var guild = await Guild.findOneOrFail({
+		const guild = await Guild.findOneOrFail({
 			where: { id: guild_id },
 			relations: ["emojis", "roles", "stickers"],
 		});
@@ -110,7 +110,7 @@ router.patch(
 				"DISCOVERABLE",
 			];
 
-			for (var feature of diff) {
+			for (const feature of diff) {
 				if (MUTABLE_FEATURES.includes(feature)) continue;
 
 				throw FosscordApiErrors.FEATURE_IS_IMMUTABLE.withParams(
diff --git a/src/api/routes/guilds/#guild_id/invites.ts b/src/api/routes/guilds/#guild_id/invites.ts
index 6e9cc3e6..dd099992 100644
--- a/src/api/routes/guilds/#guild_id/invites.ts
+++ b/src/api/routes/guilds/#guild_id/invites.ts
@@ -16,7 +16,7 @@
 	along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-import { getPermission, Invite, PublicInviteRelation } from "@fosscord/util";
+import { Invite, PublicInviteRelation } from "@fosscord/util";
 import { route } from "@fosscord/api";
 import { Request, Response, Router } from "express";
 
diff --git a/src/api/routes/guilds/#guild_id/members/#member_id/index.ts b/src/api/routes/guilds/#guild_id/members/#member_id/index.ts
index 2cf7c08b..2daa7d9b 100644
--- a/src/api/routes/guilds/#guild_id/members/#member_id/index.ts
+++ b/src/api/routes/guilds/#guild_id/members/#member_id/index.ts
@@ -49,11 +49,12 @@ router.patch(
 	"/",
 	route({ body: "MemberChangeSchema" }),
 	async (req: Request, res: Response) => {
-		let { guild_id, member_id } = req.params;
-		if (member_id === "@me") member_id = req.user_id;
+		const { guild_id } = req.params;
+		const member_id =
+			req.params.member_id === "@me" ? req.user_id : req.params.member_id;
 		const body = req.body as MemberChangeSchema;
 
-		let member = await Member.findOneOrFail({
+		const member = await Member.findOneOrFail({
 			where: { id: member_id, guild_id },
 			relations: ["roles", "user"],
 		});
@@ -101,7 +102,8 @@ router.put("/", route({}), async (req: Request, res: Response) => {
 
 	const rights = await getRights(req.user_id);
 
-	let { guild_id, member_id } = req.params;
+	const { guild_id } = req.params;
+	let { member_id } = req.params;
 	if (member_id === "@me") {
 		member_id = req.user_id;
 		rights.hasThrow("JOIN_GUILDS");
@@ -109,19 +111,19 @@ router.put("/", route({}), async (req: Request, res: Response) => {
 		// TODO: join others by controller
 	}
 
-	var guild = await Guild.findOneOrFail({
+	const guild = await Guild.findOneOrFail({
 		where: { id: guild_id },
 	});
 
-	var emoji = await Emoji.find({
+	const emoji = await Emoji.find({
 		where: { guild_id: guild_id },
 	});
 
-	var roles = await Role.find({
+	const roles = await Role.find({
 		where: { guild_id: guild_id },
 	});
 
-	var stickers = await Sticker.find({
+	const stickers = await Sticker.find({
 		where: { guild_id: guild_id },
 	});
 
diff --git a/src/api/routes/guilds/#guild_id/members/#member_id/nick.ts b/src/api/routes/guilds/#guild_id/members/#member_id/nick.ts
index 619b66f7..c93eab08 100644
--- a/src/api/routes/guilds/#guild_id/members/#member_id/nick.ts
+++ b/src/api/routes/guilds/#guild_id/members/#member_id/nick.ts
@@ -26,12 +26,12 @@ router.patch(
 	"/",
 	route({ body: "MemberNickChangeSchema" }),
 	async (req: Request, res: Response) => {
-		var { guild_id, member_id } = req.params;
-		var permissionString: PermissionResolvable = "MANAGE_NICKNAMES";
-		if (member_id === "@me") {
-			member_id = req.user_id;
-			permissionString = "CHANGE_NICKNAME";
-		}
+		const { guild_id } = req.params;
+		let permissionString: PermissionResolvable = "MANAGE_NICKNAMES";
+		const member_id =
+			req.params.member_id === "@me"
+				? ((permissionString = "CHANGE_NICKNAME"), req.user_id)
+				: req.params.member_id;
 
 		const perms = await getPermission(req.user_id, guild_id);
 		perms.hasThrow(permissionString);
diff --git a/src/api/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts b/src/api/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts
index e64893b7..16c5e789 100644
--- a/src/api/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts
+++ b/src/api/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts
@@ -16,7 +16,7 @@
 	along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-import { getPermission, Member } from "@fosscord/util";
+import { Member } from "@fosscord/util";
 import { route } from "@fosscord/api";
 import { Request, Response, Router } from "express";
 
diff --git a/src/api/routes/guilds/#guild_id/members/index.ts b/src/api/routes/guilds/#guild_id/members/index.ts
index b96210f3..51e9eb1f 100644
--- a/src/api/routes/guilds/#guild_id/members/index.ts
+++ b/src/api/routes/guilds/#guild_id/members/index.ts
@@ -17,7 +17,7 @@
 */
 
 import { Request, Response, Router } from "express";
-import { Guild, Member, PublicMemberProjection } from "@fosscord/util";
+import { Member, PublicMemberProjection } from "@fosscord/util";
 import { route } from "@fosscord/api";
 import { MoreThan } from "typeorm";
 import { HTTPError } from "lambert-server";
diff --git a/src/api/routes/guilds/#guild_id/messages/search.ts b/src/api/routes/guilds/#guild_id/messages/search.ts
index 7061b5f0..601167ee 100644
--- a/src/api/routes/guilds/#guild_id/messages/search.ts
+++ b/src/api/routes/guilds/#guild_id/messages/search.ts
@@ -16,6 +16,8 @@
 	along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 
+/* eslint-disable @typescript-eslint/ban-ts-comment */
+
 import { Request, Response, Router } from "express";
 import { route } from "@fosscord/api";
 import { getPermission, FieldErrors, Message, Channel } from "@fosscord/util";
@@ -28,10 +30,10 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	const {
 		channel_id,
 		content,
-		include_nsfw, // TODO
+		// include_nsfw, // TODO
 		offset,
 		sort_order,
-		sort_by, // TODO: Handle 'relevance'
+		// sort_by, // TODO: Handle 'relevance'
 		limit,
 		author_id,
 	} = req.query;
@@ -62,7 +64,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	if (!permissions.has("READ_MESSAGE_HISTORY"))
 		return res.json({ messages: [], total_results: 0 });
 
-	var query: FindManyOptions<Message> = {
+	const query: FindManyOptions<Message> = {
 		order: {
 			timestamp: sort_order
 				? (sort_order.toUpperCase() as "ASC" | "DESC")
@@ -87,7 +89,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 		skip: offset ? Number(offset) : 0,
 	};
 	//@ts-ignore
-	if (channel_id) query.where!.channel = { id: channel_id };
+	if (channel_id) query.where.channel = { id: channel_id };
 	else {
 		// get all channel IDs that this user can access
 		const channels = await Channel.find({
@@ -96,7 +98,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 		});
 		const ids = [];
 
-		for (var channel of channels) {
+		for (const channel of channels) {
 			const perm = await getPermission(
 				req.user_id,
 				req.params.guild_id,
@@ -108,12 +110,12 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 		}
 
 		//@ts-ignore
-		query.where!.channel = { id: In(ids) };
+		query.where.channel = { id: In(ids) };
 	}
 	//@ts-ignore
-	if (author_id) query.where!.author = { id: author_id };
+	if (author_id) query.where.author = { id: author_id };
 	//@ts-ignore
-	if (content) query.where!.content = Like(`%${content}%`);
+	if (content) query.where.content = Like(`%${content}%`);
 
 	const messages: Message[] = await Message.find(query);
 
diff --git a/src/api/routes/guilds/#guild_id/profile/index.ts b/src/api/routes/guilds/#guild_id/profile/index.ts
index 5771fbf1..cbf0ff6a 100644
--- a/src/api/routes/guilds/#guild_id/profile/index.ts
+++ b/src/api/routes/guilds/#guild_id/profile/index.ts
@@ -33,8 +33,9 @@ router.patch(
 	"/:member_id",
 	route({ body: "MemberChangeProfileSchema" }),
 	async (req: Request, res: Response) => {
-		let { guild_id, member_id } = req.params;
-		if (member_id === "@me") member_id = req.user_id;
+		const { guild_id } = req.params;
+		// const member_id =
+		// 	req.params.member_id === "@me" ? req.user_id : req.params.member_id;
 		const body = req.body as MemberChangeProfileSchema;
 
 		let member = await Member.findOneOrFail({
diff --git a/src/api/routes/guilds/#guild_id/prune.ts b/src/api/routes/guilds/#guild_id/prune.ts
index 1199df54..37b70f63 100644
--- a/src/api/routes/guilds/#guild_id/prune.ts
+++ b/src/api/routes/guilds/#guild_id/prune.ts
@@ -29,16 +29,16 @@ export const inactiveMembers = async (
 	days: number,
 	roles: string[] = [],
 ) => {
-	var date = new Date();
+	const date = new Date();
 	date.setDate(date.getDate() - days);
 	//Snowflake should have `generateFromTime` method? Or similar?
-	var minId = BigInt(date.valueOf() - Snowflake.EPOCH) << BigInt(22);
+	const minId = BigInt(date.valueOf() - Snowflake.EPOCH) << BigInt(22);
 
 	/**
 	idea: ability to customise the cutoff variable
 	possible candidates: public read receipt, last presence, last VC leave
 	**/
-	var members = await Member.find({
+	let members = await Member.find({
 		where: [
 			{
 				guild_id,
@@ -83,7 +83,7 @@ export const inactiveMembers = async (
 router.get("/", route({}), async (req: Request, res: Response) => {
 	const days = parseInt(req.query.days as string);
 
-	var roles = req.query.include_roles;
+	let roles = req.query.include_roles;
 	if (typeof roles === "string") roles = [roles]; //express will return array otherwise
 
 	const members = await inactiveMembers(
@@ -102,7 +102,7 @@ router.post(
 	async (req: Request, res: Response) => {
 		const days = parseInt(req.body.days);
 
-		var roles = req.query.include_roles;
+		let roles = req.query.include_roles;
 		if (typeof roles === "string") roles = [roles];
 
 		const { guild_id } = req.params;
diff --git a/src/api/routes/guilds/#guild_id/regions.ts b/src/api/routes/guilds/#guild_id/regions.ts
index a9c04a39..61ba00bf 100644
--- a/src/api/routes/guilds/#guild_id/regions.ts
+++ b/src/api/routes/guilds/#guild_id/regions.ts
@@ -16,10 +16,9 @@
 	along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-import { Config, Guild, Member } from "@fosscord/util";
+import { Guild } from "@fosscord/util";
 import { Request, Response, Router } from "express";
-import { getVoiceRegions, route } from "@fosscord/api";
-import { getIpAdress } from "@fosscord/api";
+import { getVoiceRegions, route, getIpAdress } from "@fosscord/api";
 
 const router = Router();
 
diff --git a/src/api/routes/guilds/#guild_id/roles/#role_id/index.ts b/src/api/routes/guilds/#guild_id/roles/#role_id/index.ts
index 22eb439a..48e77897 100644
--- a/src/api/routes/guilds/#guild_id/roles/#role_id/index.ts
+++ b/src/api/routes/guilds/#guild_id/roles/#role_id/index.ts
@@ -87,7 +87,8 @@ router.patch(
 		role.assign({
 			...body,
 			permissions: String(
-				req.permission!.bitfield & BigInt(body.permissions || "0"),
+				(req.permission?.bitfield || 0n) &
+					BigInt(body.permissions || "0"),
 			),
 		});
 
diff --git a/src/api/routes/guilds/#guild_id/roles/index.ts b/src/api/routes/guilds/#guild_id/roles/index.ts
index feab84ef..54d4b12c 100644
--- a/src/api/routes/guilds/#guild_id/roles/index.ts
+++ b/src/api/routes/guilds/#guild_id/roles/index.ts
@@ -68,7 +68,8 @@ router.post(
 			guild_id: guild_id,
 			managed: false,
 			permissions: String(
-				req.permission!.bitfield & BigInt(body.permissions || "0"),
+				(req.permission?.bitfield || 0n) &
+					BigInt(body.permissions || "0"),
 			),
 			tags: undefined,
 			icon: undefined,
diff --git a/src/api/routes/guilds/#guild_id/templates.ts b/src/api/routes/guilds/#guild_id/templates.ts
index f5244313..284bbccf 100644
--- a/src/api/routes/guilds/#guild_id/templates.ts
+++ b/src/api/routes/guilds/#guild_id/templates.ts
@@ -44,7 +44,7 @@ const TemplateGuildProjection: (keyof Guild)[] = [
 router.get("/", route({}), async (req: Request, res: Response) => {
 	const { guild_id } = req.params;
 
-	var templates = await Template.find({
+	const templates = await Template.find({
 		where: { source_guild_id: guild_id },
 	});
 
@@ -60,9 +60,9 @@ router.post(
 			where: { id: guild_id },
 			select: TemplateGuildProjection,
 		});
-		const exists = await Template.findOneOrFail({
+		const exists = await Template.findOne({
 			where: { id: guild_id },
-		}).catch((e) => {});
+		});
 		if (exists) throw new HTTPError("Template already exists", 400);
 
 		const template = await Template.create({
diff --git a/src/api/routes/guilds/#guild_id/voice-states/#user_id/index.ts b/src/api/routes/guilds/#guild_id/voice-states/#user_id/index.ts
index 9883ef0d..3577df17 100644
--- a/src/api/routes/guilds/#guild_id/voice-states/#user_id/index.ts
+++ b/src/api/routes/guilds/#guild_id/voice-states/#user_id/index.ts
@@ -37,8 +37,9 @@ router.patch(
 	route({ body: "VoiceStateUpdateSchema" }),
 	async (req: Request, res: Response) => {
 		const body = req.body as VoiceStateUpdateSchema;
-		var { guild_id, user_id } = req.params;
-		if (user_id === "@me") user_id = req.user_id;
+		const { guild_id } = req.params;
+		const user_id =
+			req.params.user_id === "@me" ? req.user_id : req.params.user_id;
 
 		const perms = await getPermission(
 			req.user_id,
diff --git a/src/api/routes/guilds/#guild_id/widget.json.ts b/src/api/routes/guilds/#guild_id/widget.json.ts
index 46b8aa8b..9319d058 100644
--- a/src/api/routes/guilds/#guild_id/widget.json.ts
+++ b/src/api/routes/guilds/#guild_id/widget.json.ts
@@ -17,14 +17,7 @@
 */
 
 import { Request, Response, Router } from "express";
-import {
-	Config,
-	Permissions,
-	Guild,
-	Invite,
-	Channel,
-	Member,
-} from "@fosscord/util";
+import { Permissions, Guild, Invite, Channel, Member } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { random, route } from "@fosscord/api";
 
@@ -46,7 +39,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	if (!guild.widget_enabled) throw new HTTPError("Widget Disabled", 404);
 
 	// Fetch existing widget invite for widget channel
-	var invite = await Invite.findOne({
+	let invite = await Invite.findOne({
 		where: { channel_id: guild.widget_channel_id },
 	});
 
@@ -70,7 +63,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	}
 
 	// Fetch voice channels, and the @everyone permissions object
-	const channels = [] as any[];
+	const channels: { id: string; name: string; position: number }[] = [];
 
 	(
 		await Channel.find({
@@ -88,15 +81,15 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 		) {
 			channels.push({
 				id: doc.id,
-				name: doc.name,
-				position: doc.position,
+				name: doc.name ?? "Unknown channel",
+				position: doc.position ?? 0,
 			});
 		}
 	});
 
 	// Fetch members
 	// TODO: Understand how Discord's max 100 random member sample works, and apply to here (see top of this file)
-	let members = await Member.find({ where: { guild_id: guild_id } });
+	const members = await Member.find({ where: { guild_id: guild_id } });
 
 	// Construct object to respond with
 	const data = {
diff --git a/src/api/routes/guilds/#guild_id/widget.png.ts b/src/api/routes/guilds/#guild_id/widget.png.ts
index 1c6a62ac..65de8978 100644
--- a/src/api/routes/guilds/#guild_id/widget.png.ts
+++ b/src/api/routes/guilds/#guild_id/widget.png.ts
@@ -16,6 +16,8 @@
 	along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 
+/* eslint-disable @typescript-eslint/no-explicit-any */
+
 import { Request, Response, Router } from "express";
 import { Guild } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
@@ -161,8 +163,7 @@ async function drawIcon(
 	scale: number,
 	icon: string,
 ) {
-	// @ts-ignore
-	const img = new require("canvas").Image();
+	const img = new (require("canvas").Image)();
 	img.src = icon;
 
 	// Do some canvas clipping magic!
diff --git a/src/api/routes/guilds/index.ts b/src/api/routes/guilds/index.ts
index 125d25b0..64af4bd1 100644
--- a/src/api/routes/guilds/index.ts
+++ b/src/api/routes/guilds/index.ts
@@ -18,7 +18,6 @@
 
 import { Router, Request, Response } from "express";
 import {
-	Role,
 	Guild,
 	Config,
 	getRights,
@@ -52,6 +51,7 @@ router.post(
 
 		const { autoJoin } = Config.get().guild;
 		if (autoJoin.enabled && !autoJoin.guilds?.length) {
+			// eslint-disable-next-line @typescript-eslint/ban-ts-comment
 			// @ts-ignore
 			await Config.set({ guild: { autoJoin: { guilds: [guild.id] } } });
 		}
diff --git a/src/api/routes/guilds/templates/index.ts b/src/api/routes/guilds/templates/index.ts
index f3bb3ef1..a43337d8 100644
--- a/src/api/routes/guilds/templates/index.ts
+++ b/src/api/routes/guilds/templates/index.ts
@@ -86,8 +86,8 @@ router.post(
 		const {
 			enabled,
 			allowTemplateCreation,
-			allowDiscordTemplates,
-			allowRaws,
+			// allowDiscordTemplates,
+			// allowRaws,
 		} = Config.get().templates;
 		if (!enabled)
 			return res
@@ -121,7 +121,7 @@ router.post(
 
 		const guild_id = Snowflake.generate();
 
-		const [guild, role] = await Promise.all([
+		const [guild] = await Promise.all([
 			Guild.create({
 				...body,
 				...template.serialized_source_guild,
diff --git a/src/api/routes/oauth2/authorize.ts b/src/api/routes/oauth2/authorize.ts
index be9b39b4..e238b72f 100644
--- a/src/api/routes/oauth2/authorize.ts
+++ b/src/api/routes/oauth2/authorize.ts
@@ -27,16 +27,14 @@ import {
 	Member,
 	Permissions,
 	User,
-	getRights,
-	Rights,
-	MemberPrivateProjection,
 } from "@fosscord/util";
 const router = Router();
 
 // TODO: scopes, other oauth types
 
 router.get("/", route({}), async (req: Request, res: Response) => {
-	const { client_id, scope, response_type, redirect_url } = req.query;
+	// const { client_id, scope, response_type, redirect_url } = req.query;
+	const { client_id } = req.query;
 
 	const app = await Application.findOne({
 		where: {
@@ -68,6 +66,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 			},
 		},
 		relations: ["guild", "roles"],
+		// eslint-disable-next-line @typescript-eslint/ban-ts-comment
 		//@ts-ignore
 		// prettier-ignore
 		select: ["guild.id", "guild.name", "guild.icon", "guild.mfa_level", "guild.owner_id", "roles.id"],
@@ -139,7 +138,8 @@ router.post(
 	route({ body: "ApplicationAuthorizeSchema" }),
 	async (req: Request, res: Response) => {
 		const body = req.body as ApplicationAuthorizeSchema;
-		const { client_id, scope, response_type, redirect_url } = req.query;
+		// const { client_id, scope, response_type, redirect_url } = req.query;
+		const { client_id } = req.query;
 
 		// TODO: captcha verification
 		// TODO: MFA verification
@@ -153,7 +153,7 @@ router.post(
 		// getPermission cache won't exist if we're owner
 		if (
 			Object.keys(perms.cache || {}).length > 0 &&
-			perms.cache.member!.user.bot
+			perms.cache.member?.user.bot
 		)
 			throw DiscordApiErrors.UNAUTHORIZED;
 		perms.hasThrow("MANAGE_GUILD");
diff --git a/src/api/routes/partners/#guild_id/requirements.ts b/src/api/routes/partners/#guild_id/requirements.ts
index 11dcc33e..de2da6ee 100644
--- a/src/api/routes/partners/#guild_id/requirements.ts
+++ b/src/api/routes/partners/#guild_id/requirements.ts
@@ -16,8 +16,6 @@
 	along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-import { Guild, Config } from "@fosscord/util";
-
 import { Router, Request, Response } from "express";
 import { route } from "@fosscord/api";
 
diff --git a/src/api/routes/policies/instance/domains.ts b/src/api/routes/policies/instance/domains.ts
index 929cf65c..33c06765 100644
--- a/src/api/routes/policies/instance/domains.ts
+++ b/src/api/routes/policies/instance/domains.ts
@@ -19,7 +19,6 @@
 import { Router, Request, Response } from "express";
 import { route } from "@fosscord/api";
 import { Config } from "@fosscord/util";
-import { config } from "dotenv";
 const router = Router();
 
 router.get("/", route({}), async (req: Request, res: Response) => {
diff --git a/src/api/routes/store/published-listings/applications.ts b/src/api/routes/store/published-listings/applications.ts
index 16604960..ec9168b1 100644
--- a/src/api/routes/store/published-listings/applications.ts
+++ b/src/api/routes/store/published-listings/applications.ts
@@ -23,7 +23,7 @@ const router: Router = Router();
 
 router.get("/:id", route({}), async (req: Request, res: Response) => {
 	//TODO
-	const id = req.params.id;
+	// const id = req.params.id;
 	res.json({
 		id: "",
 		summary: "",
diff --git a/src/api/routes/store/published-listings/skus.ts b/src/api/routes/store/published-listings/skus.ts
index 16604960..ec9168b1 100644
--- a/src/api/routes/store/published-listings/skus.ts
+++ b/src/api/routes/store/published-listings/skus.ts
@@ -23,7 +23,7 @@ const router: Router = Router();
 
 router.get("/:id", route({}), async (req: Request, res: Response) => {
 	//TODO
-	const id = req.params.id;
+	// const id = req.params.id;
 	res.json({
 		id: "",
 		summary: "",
diff --git a/src/api/routes/updates.ts b/src/api/routes/updates.ts
index 5555fcda..5c237465 100644
--- a/src/api/routes/updates.ts
+++ b/src/api/routes/updates.ts
@@ -18,12 +18,11 @@
 
 import { Router, Response, Request } from "express";
 import { route } from "@fosscord/api";
-import { Config, FieldErrors, Release } from "@fosscord/util";
+import { FieldErrors, Release } from "@fosscord/util";
 
 const router = Router();
 
 router.get("/", route({}), async (req: Request, res: Response) => {
-	const { client } = Config.get();
 	const platform = req.query.platform;
 
 	if (!platform)
diff --git a/src/api/routes/users/#id/delete.ts b/src/api/routes/users/#id/delete.ts
index e7caeb05..9bc3f9f8 100644
--- a/src/api/routes/users/#id/delete.ts
+++ b/src/api/routes/users/#id/delete.ts
@@ -23,7 +23,6 @@ import {
 	PrivateUserProjection,
 	User,
 	UserDeleteEvent,
-	UserDeleteSchema,
 } from "@fosscord/util";
 import { Request, Response, Router } from "express";
 
@@ -33,7 +32,7 @@ router.post(
 	"/",
 	route({ right: "MANAGE_USERS" }),
 	async (req: Request, res: Response) => {
-		let user = await User.findOneOrFail({
+		await User.findOneOrFail({
 			where: { id: req.params.id },
 			select: [...PrivateUserProjection, "data"],
 		});
diff --git a/src/api/routes/users/#id/profile.ts b/src/api/routes/users/#id/profile.ts
index 1103bb48..dbf95a52 100644
--- a/src/api/routes/users/#id/profile.ts
+++ b/src/api/routes/users/#id/profile.ts
@@ -19,11 +19,9 @@
 import { Router, Request, Response } from "express";
 import {
 	PublicConnectedAccount,
-	PublicUser,
 	User,
 	UserPublic,
 	Member,
-	Guild,
 	UserProfileModifySchema,
 	handleFile,
 	PrivateUserProjection,
@@ -53,8 +51,8 @@ router.get(
 			relations: ["connected_accounts"],
 		});
 
-		var mutual_guilds: object[] = [];
-		var premium_guild_since;
+		const mutual_guilds: object[] = [];
+		let premium_guild_since;
 
 		if (with_mutual_guilds == "true") {
 			const requested_member = await Member.find({
@@ -169,7 +167,7 @@ router.patch(
 				`/banners/${req.user_id}`,
 				body.banner as string,
 			);
-		let user = await User.findOneOrFail({
+		const user = await User.findOneOrFail({
 			where: { id: req.user_id },
 			select: [...PrivateUserProjection, "data"],
 		});
@@ -177,6 +175,7 @@ router.patch(
 		user.assign(body);
 		await user.save();
 
+		// eslint-disable-next-line @typescript-eslint/ban-ts-comment
 		// @ts-ignore
 		delete user.data;
 
diff --git a/src/api/routes/users/#id/relationships.ts b/src/api/routes/users/#id/relationships.ts
index aa36967a..e915e3ff 100644
--- a/src/api/routes/users/#id/relationships.ts
+++ b/src/api/routes/users/#id/relationships.ts
@@ -36,7 +36,7 @@ router.get(
 	"/",
 	route({ test: { response: { body: "UserRelationsResponse" } } }),
 	async (req: Request, res: Response) => {
-		var mutual_relations: object[] = [];
+		const mutual_relations: object[] = [];
 		const requested_relations = await User.findOneOrFail({
 			where: { id: req.params.id },
 			relations: ["relationships"],
@@ -53,7 +53,7 @@ router.get(
 					rmem.type === 1 &&
 					rmem.to_id !== req.user_id
 				) {
-					var relation_user = await User.getPublicUser(rmem.to_id);
+					const relation_user = await User.getPublicUser(rmem.to_id);
 
 					mutual_relations.push({
 						id: relation_user.id,
diff --git a/src/api/routes/users/@me/delete.ts b/src/api/routes/users/@me/delete.ts
index a6ae2d13..8043eae3 100644
--- a/src/api/routes/users/@me/delete.ts
+++ b/src/api/routes/users/@me/delete.ts
@@ -17,7 +17,7 @@
 */
 
 import { Router, Request, Response } from "express";
-import { Guild, Member, User } from "@fosscord/util";
+import { Member, User } from "@fosscord/util";
 import { route } from "@fosscord/api";
 import bcrypt from "bcrypt";
 import { HTTPError } from "lambert-server";
diff --git a/src/api/routes/users/@me/guilds/#guild_id/settings.ts b/src/api/routes/users/@me/guilds/#guild_id/settings.ts
index 0525bea2..72c95d6b 100644
--- a/src/api/routes/users/@me/guilds/#guild_id/settings.ts
+++ b/src/api/routes/users/@me/guilds/#guild_id/settings.ts
@@ -43,7 +43,7 @@ router.patch(
 		const body = req.body as UserGuildSettingsSchema;
 
 		if (body.channel_overrides) {
-			for (var channel in body.channel_overrides) {
+			for (const channel in body.channel_overrides) {
 				Channel.findOneOrFail({ where: { id: channel } });
 			}
 		}
diff --git a/src/api/routes/users/@me/index.ts b/src/api/routes/users/@me/index.ts
index 596e2575..0d3c3135 100644
--- a/src/api/routes/users/@me/index.ts
+++ b/src/api/routes/users/@me/index.ts
@@ -55,7 +55,7 @@ router.patch(
 		});
 
 		// Populated on password change
-		var newToken: string | undefined;
+		let newToken: string | undefined;
 
 		if (body.avatar)
 			body.avatar = await handleFile(
@@ -120,7 +120,7 @@ router.patch(
 		}
 
 		if (body.username) {
-			var check_username = body?.username?.replace(/\s/g, "");
+			const check_username = body?.username?.replace(/\s/g, "");
 			if (!check_username) {
 				throw FieldErrors({
 					username: {
@@ -153,7 +153,8 @@ router.patch(
 		user.validate();
 		await user.save();
 
-		// @ts-ignore
+		// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+		//@ts-ignore
 		delete user.data;
 
 		// TODO: send update member list event in gateway
diff --git a/src/api/routes/users/@me/mfa/codes-verification.ts b/src/api/routes/users/@me/mfa/codes-verification.ts
index ac16f7e7..24f018c9 100644
--- a/src/api/routes/users/@me/mfa/codes-verification.ts
+++ b/src/api/routes/users/@me/mfa/codes-verification.ts
@@ -23,6 +23,7 @@ import {
 	generateMfaBackupCodes,
 	User,
 	CodesVerificationSchema,
+	DiscordApiErrors,
 } from "@fosscord/util";
 
 const router = Router();
@@ -31,14 +32,17 @@ router.post(
 	"/",
 	route({ body: "CodesVerificationSchema" }),
 	async (req: Request, res: Response) => {
-		const { key, nonce, regenerate } = req.body as CodesVerificationSchema;
+		// const { key, nonce, regenerate } = req.body as CodesVerificationSchema;
+		const { regenerate } = req.body as CodesVerificationSchema;
 
 		// TODO: We don't have email/etc etc, so can't send a verification code.
 		// Once that's done, this route can verify `key`
 
-		const user = await User.findOneOrFail({ where: { id: req.user_id } });
+		// const user = await User.findOneOrFail({ where: { id: req.user_id } });
+		if ((await User.count({ where: { id: req.user_id } })) === 0)
+			throw DiscordApiErrors.UNKNOWN_USER;
 
-		var codes: BackupCode[];
+		let codes: BackupCode[];
 		if (regenerate) {
 			await BackupCode.update(
 				{ user: { id: req.user_id } },
diff --git a/src/api/routes/users/@me/mfa/codes.ts b/src/api/routes/users/@me/mfa/codes.ts
index 09b9b329..e2600400 100644
--- a/src/api/routes/users/@me/mfa/codes.ts
+++ b/src/api/routes/users/@me/mfa/codes.ts
@@ -51,7 +51,7 @@ router.post(
 			});
 		}
 
-		var codes: BackupCode[];
+		let codes: BackupCode[];
 		if (regenerate) {
 			await BackupCode.update(
 				{ user: { id: req.user_id } },
diff --git a/src/api/routes/users/@me/mfa/totp/disable.ts b/src/api/routes/users/@me/mfa/totp/disable.ts
index c399ba33..e35691ae 100644
--- a/src/api/routes/users/@me/mfa/totp/disable.ts
+++ b/src/api/routes/users/@me/mfa/totp/disable.ts
@@ -42,7 +42,7 @@ router.post(
 
 		const backup = await BackupCode.findOne({ where: { code: body.code } });
 		if (!backup) {
-			const ret = verifyToken(user.totp_secret!, body.code);
+			const ret = verifyToken(user.totp_secret || "", body.code);
 			if (!ret || ret.delta != 0)
 				throw new HTTPError(
 					req.t("auth:login.INVALID_TOTP_CODE"),
diff --git a/src/api/routes/users/@me/mfa/totp/enable.ts b/src/api/routes/users/@me/mfa/totp/enable.ts
index a59983ac..f6519ad0 100644
--- a/src/api/routes/users/@me/mfa/totp/enable.ts
+++ b/src/api/routes/users/@me/mfa/totp/enable.ts
@@ -57,7 +57,7 @@ router.post(
 		if (verifyToken(body.secret, body.code)?.delta != 0)
 			throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
 
-		let backup_codes = generateMfaBackupCodes(req.user_id);
+		const backup_codes = generateMfaBackupCodes(req.user_id);
 		await Promise.all(backup_codes.map((x) => x.save()));
 		await User.update(
 			{ id: req.user_id },
diff --git a/src/api/routes/users/@me/relationships.ts b/src/api/routes/users/@me/relationships.ts
index de684a34..4dfb4c33 100644
--- a/src/api/routes/users/@me/relationships.ts
+++ b/src/api/routes/users/@me/relationships.ts
@@ -175,7 +175,7 @@ async function updateRelationship(
 		select: userProjection,
 	});
 
-	var relationship = user.relationships.find((x) => x.to_id === id);
+	let relationship = user.relationships.find((x) => x.to_id === id);
 	const friendRequest = friend.relationships.find(
 		(x) => x.to_id === req.user_id,
 	);
@@ -219,13 +219,13 @@ async function updateRelationship(
 	if (user.relationships.length >= maxFriends)
 		throw DiscordApiErrors.MAXIMUM_FRIENDS.withParams(maxFriends);
 
-	var incoming_relationship = Relationship.create({
+	let incoming_relationship = Relationship.create({
 		nickname: undefined,
 		type: RelationshipType.incoming,
 		to: user,
 		from: friend,
 	});
-	var outgoing_relationship = Relationship.create({
+	let outgoing_relationship = Relationship.create({
 		nickname: undefined,
 		type: RelationshipType.outgoing,
 		to: friend,
diff --git a/src/api/routes/users/@me/settings.ts b/src/api/routes/users/@me/settings.ts
index ad922084..c883bb30 100644
--- a/src/api/routes/users/@me/settings.ts
+++ b/src/api/routes/users/@me/settings.ts
@@ -17,7 +17,7 @@
 */
 
 import { Router, Response, Request } from "express";
-import { OrmUtils, User, UserSettingsSchema } from "@fosscord/util";
+import { User, UserSettingsSchema } from "@fosscord/util";
 import { route } from "@fosscord/api";
 
 const router = Router();
diff --git a/src/api/start.ts b/src/api/start.ts
index e80a7d4a..7975d085 100644
--- a/src/api/start.ts
+++ b/src/api/start.ts
@@ -26,7 +26,7 @@ config();
 import { FosscordServer } from "./Server";
 import cluster from "cluster";
 import os from "os";
-var cores = 1;
+let cores = 1;
 try {
 	cores = Number(process.env.THREADS) || os.cpus().length;
 } catch {
@@ -41,16 +41,17 @@ if (cluster.isPrimary && process.env.NODE_ENV == "production") {
 		cluster.fork();
 	}
 
-	cluster.on("exit", (worker, code, signal) => {
+	cluster.on("exit", (worker) => {
 		console.log(`worker ${worker.process.pid} died, restart worker`);
 		cluster.fork();
 	});
 } else {
-	var port = Number(process.env.PORT) || 3001;
+	const port = Number(process.env.PORT) || 3001;
 
 	const server = new FosscordServer({ port });
 	server.start().catch(console.error);
 
+	// eslint-disable-next-line @typescript-eslint/ban-ts-comment
 	// @ts-ignore
 	global.server = server;
 }
diff --git a/src/api/util/handlers/Instance.ts b/src/api/util/handlers/Instance.ts
index acac1fb8..08157208 100644
--- a/src/api/util/handlers/Instance.ts
+++ b/src/api/util/handlers/Instance.ts
@@ -16,7 +16,7 @@
 	along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-import { Config, Guild, Session } from "@fosscord/util";
+import { Session } from "@fosscord/util";
 
 export async function initInstance() {
 	// TODO: clean up database and delete tombstone data
@@ -24,15 +24,14 @@ export async function initInstance() {
 
 	// create default guild and add it to auto join
 	// TODO: check if any current user is not part of autoJoinGuilds
-	const { autoJoin } = Config.get().guild;
+	// const { autoJoin } = Config.get().guild;
 
-	if (autoJoin.enabled && !autoJoin.guilds?.length) {
-		let guild = await Guild.findOne({ where: {}, select: ["id"] });
-		if (guild) {
-			// @ts-ignore
-			await Config.set({ guild: { autoJoin: { guilds: [guild.id] } } });
-		}
-	}
+	// if (autoJoin.enabled && !autoJoin.guilds?.length) {
+	// 	const guild = await Guild.findOne({ where: {}, select: ["id"] });
+	// 	if (guild) {
+	// 		await Config.set({ guild: { autoJoin: { guilds: [guild.id] } } });
+	// 	}
+	// }
 
 	// TODO: do no clear sessions for instance cluster
 	await Session.delete({});
diff --git a/src/api/util/handlers/Message.ts b/src/api/util/handlers/Message.ts
index 2371358f..42325681 100644
--- a/src/api/util/handlers/Message.ts
+++ b/src/api/util/handlers/Message.ts
@@ -51,7 +51,7 @@ const allow_empty = false;
 // TODO: embed gifs/videos/images
 
 const LINK_REGEX =
-	/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/g;
+	/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/g;
 
 export async function handleMessage(opts: MessageOptions): Promise<Message> {
 	const channel = await Channel.findOneOrFail({
@@ -129,7 +129,6 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> {
 		}
 		/** Q: should be checked if the referenced message exists? ANSWER: NO
 		 otherwise backfilling won't work **/
-		// @ts-ignore
 		message.type = MessageType.REPLY;
 	}
 
@@ -144,29 +143,29 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> {
 		throw new HTTPError("Empty messages are not allowed", 50006);
 	}
 
-	var content = opts.content;
-	var mention_channel_ids = [] as string[];
-	var mention_role_ids = [] as string[];
-	var mention_user_ids = [] as string[];
-	var mention_everyone = false;
+	let content = opts.content;
+	const mention_channel_ids = [] as string[];
+	const mention_role_ids = [] as string[];
+	const mention_user_ids = [] as string[];
+	let mention_everyone = false;
 
 	if (content) {
 		// TODO: explicit-only mentions
 		message.content = content.trim();
-		content = content.replace(/ *\`[^)]*\` */g, ""); // remove codeblocks
-		for (const [_, mention] of content.matchAll(CHANNEL_MENTION)) {
+		content = content.replace(/ *`[^)]*` */g, ""); // remove codeblocks
+		for (const [, mention] of content.matchAll(CHANNEL_MENTION)) {
 			if (!mention_channel_ids.includes(mention))
 				mention_channel_ids.push(mention);
 		}
 
-		for (const [_, mention] of content.matchAll(USER_MENTION)) {
+		for (const [, mention] of content.matchAll(USER_MENTION)) {
 			if (!mention_user_ids.includes(mention))
 				mention_user_ids.push(mention);
 		}
 
 		await Promise.all(
 			Array.from(content.matchAll(ROLE_MENTION)).map(
-				async ([_, mention]) => {
+				async ([, mention]) => {
 					const role = await Role.findOneOrFail({
 						where: { id: mention, guild_id: channel.guild_id },
 					});
@@ -198,8 +197,8 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> {
 
 // TODO: cache link result in db
 export async function postHandleMessage(message: Message) {
-	const content = message.content?.replace(/ *\`[^)]*\` */g, ""); // remove markdown
-	var links = content?.match(LINK_REGEX);
+	const content = message.content?.replace(/ *`[^)]*` */g, ""); // remove markdown
+	let links = content?.match(LINK_REGEX);
 	if (!links) return;
 
 	const data = { ...message };
@@ -232,8 +231,8 @@ export async function postHandleMessage(message: Message) {
 			// tried to use shorthand but types didn't like me L
 			if (!Array.isArray(res)) res = [res];
 
-			for (var embed of res) {
-				var cache = EmbedCache.create({
+			for (const embed of res) {
+				const cache = EmbedCache.create({
 					url: link,
 					embed: embed,
 				});
@@ -279,7 +278,10 @@ export async function sendMessage(opts: MessageOptions) {
 		} as MessageCreateEvent),
 	]);
 
-	postHandleMessage(message).catch((e) => {}); // no await as it should catch error non-blockingly
+	// no await as it should catch error non-blockingly
+	postHandleMessage(message).catch((e) =>
+		console.error("[Message] post-message handler failed", e),
+	);
 
 	return message;
 }
diff --git a/src/api/util/handlers/Voice.ts b/src/api/util/handlers/Voice.ts
index d8d5c279..24bfa7b3 100644
--- a/src/api/util/handlers/Voice.ts
+++ b/src/api/util/handlers/Voice.ts
@@ -31,7 +31,7 @@ export async function getVoiceRegions(ipAddress: string, vip: boolean) {
 
 		let min = Number.POSITIVE_INFINITY;
 
-		for (let ar of availableRegions) {
+		for (const ar of availableRegions) {
 			//TODO the endpoint location should be saved in the database if not already present to prevent IPAnalysis call
 			const dist = distanceBetweenLocations(
 				clientIpAnalysis,
diff --git a/src/api/util/handlers/route.ts b/src/api/util/handlers/route.ts
index 6fcc6c73..cb160637 100644
--- a/src/api/util/handlers/route.ts
+++ b/src/api/util/handlers/route.ts
@@ -34,6 +34,8 @@ import { NextFunction, Request, Response } from "express";
 import { AnyValidateFunction } from "ajv/dist/core";
 
 declare global {
+	// TODO: fix this
+	// eslint-disable-next-line @typescript-eslint/no-namespace
 	namespace Express {
 		interface Request {
 			permission?: Permissions;
@@ -53,7 +55,7 @@ export interface RouteOptions {
 	body?: `${string}Schema`; // typescript interface name
 	test?: {
 		response?: RouteResponse;
-		body?: any;
+		body?: unknown;
 		path?: string;
 		event?: EVENT | EVENT[];
 		headers?: Record<string, string>;
@@ -61,7 +63,7 @@ export interface RouteOptions {
 }
 
 export function route(opts: RouteOptions) {
-	var validate: AnyValidateFunction<any> | undefined;
+	let validate: AnyValidateFunction | undefined;
 	if (opts.body) {
 		validate = ajv.getSchema(opts.body);
 		if (!validate) throw new Error(`Body schema ${opts.body} not found`);
diff --git a/src/api/util/utility/EmbedHandlers.ts b/src/api/util/utility/EmbedHandlers.ts
index 522ff82b..8466a374 100644
--- a/src/api/util/utility/EmbedHandlers.ts
+++ b/src/api/util/utility/EmbedHandlers.ts
@@ -17,13 +17,13 @@
 */
 
 import { Config, Embed, EmbedType } from "@fosscord/util";
-import fetch, { Response } from "node-fetch";
+import fetch, { RequestInit } from "node-fetch";
 import * as cheerio from "cheerio";
 import probe from "probe-image-size";
 import crypto from "crypto";
 import { yellow } from "picocolors";
 
-export const DEFAULT_FETCH_OPTIONS: any = {
+export const DEFAULT_FETCH_OPTIONS: RequestInit = {
 	redirect: "follow",
 	follow: 1,
 	headers: {
@@ -50,7 +50,7 @@ export const getProxyUrl = (
 
 	// Imagor
 	if (imagorServerUrl) {
-		let path = `${width}x${height}/${url.host}${url.pathname}`;
+		const path = `${width}x${height}/${url.host}${url.pathname}`;
 
 		const hash = crypto
 			.createHmac("sha1", secret)
@@ -92,8 +92,8 @@ export const getMetaDescriptions = (text: string) => {
 		image: getMeta($, "og:image") || getMeta($, "twitter:image"),
 		image_fallback: $(`image`).attr("src"),
 		video_fallback: $(`video`).attr("src"),
-		width: parseInt(getMeta($, "og:image:width")!) || 0,
-		height: parseInt(getMeta($, "og:image:height")!) || 0,
+		width: parseInt(getMeta($, "og:image:width") || "0"),
+		height: parseInt(getMeta($, "og:image:height") || "0"),
 		url: getMeta($, "og:url"),
 		youtube_embed: getMeta($, "og:video:secure_url"),
 	};
@@ -192,8 +192,8 @@ export const EmbedHandlers: {
 				proxy_url: metas.image
 					? getProxyUrl(
 							new URL(metas.image),
-							metas.width!,
-							metas.height!,
+							metas.width,
+							metas.height,
 					  )
 					: undefined,
 			},
@@ -239,9 +239,9 @@ export const EmbedHandlers: {
 		const text = json.data.text;
 		const created_at = new Date(json.data.created_at);
 		const metrics = json.data.public_metrics;
-		let media = json.includes.media?.filter(
-			(x: any) => x.type == "photo",
-		) as any[]; // TODO: video
+		const media = json.includes.media?.filter(
+			(x: { type: string }) => x.type == "photo",
+		);
 
 		const embed: Embed = {
 			type: EmbedType.rich,
@@ -334,7 +334,7 @@ export const EmbedHandlers: {
 				width: 640,
 				height: 640,
 				proxy_url: metas.image
-					? getProxyUrl(new URL(metas.image!), 640, 640)
+					? getProxyUrl(new URL(metas.image), 640, 640)
 					: undefined,
 				url: metas.image,
 			},
@@ -365,9 +365,9 @@ export const EmbedHandlers: {
 				url: url.href,
 				proxy_url: metas.image
 					? getProxyUrl(
-							new URL(metas.image!),
-							metas.width!,
-							metas.height!,
+							new URL(metas.image),
+							metas.width,
+							metas.height,
 					  )
 					: undefined,
 			},
@@ -395,7 +395,7 @@ export const EmbedHandlers: {
 				height: 215,
 				url: metas.image,
 				proxy_url: metas.image
-					? getProxyUrl(new URL(metas.image!), 460, 215)
+					? getProxyUrl(new URL(metas.image), 460, 215)
 					: undefined,
 			},
 			provider: {
@@ -436,7 +436,7 @@ export const EmbedHandlers: {
 				// TODO: does this adjust with aspect ratio?
 				width: metas.width,
 				height: metas.height,
-				url: metas.youtube_embed!,
+				url: metas.youtube_embed,
 			},
 			url: url.href,
 			type: EmbedType.video,
@@ -447,9 +447,9 @@ export const EmbedHandlers: {
 				url: metas.image,
 				proxy_url: metas.image
 					? getProxyUrl(
-							new URL(metas.image!),
-							metas.width!,
-							metas.height!,
+							new URL(metas.image),
+							metas.width,
+							metas.height,
 					  )
 					: undefined,
 			},
diff --git a/src/api/util/utility/RandomInviteID.ts b/src/api/util/utility/RandomInviteID.ts
index e95b4d1d..7ce54ad2 100644
--- a/src/api/util/utility/RandomInviteID.ts
+++ b/src/api/util/utility/RandomInviteID.ts
@@ -24,7 +24,7 @@ import crypto from "crypto";
 
 export function random(length = 6) {
 	// Declare all characters
-	let chars =
+	const chars =
 		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
 
 	// Pick characers randomly
@@ -38,14 +38,14 @@ export function random(length = 6) {
 
 export function snowflakeBasedInvite() {
 	// Declare all characters
-	let chars =
+	const chars =
 		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
-	let base = BigInt(chars.length);
+	const base = BigInt(chars.length);
 	let snowflake = Snowflake.generateWorkerProcess();
 
 	// snowflakes hold ~10.75 characters worth of entropy;
 	// safe to generate a 8-char invite out of them
-	let str = "";
+	const str = "";
 	for (let i = 0; i < 10; i++) {
 		str.concat(chars.charAt(Number(snowflake % base)));
 		snowflake = snowflake / base;
diff --git a/src/api/util/utility/captcha.ts b/src/api/util/utility/captcha.ts
index 2d31f891..bd05582f 100644
--- a/src/api/util/utility/captcha.ts
+++ b/src/api/util/utility/captcha.ts
@@ -47,7 +47,10 @@ export async function verifyCaptcha(response: string, ip?: string) {
 	const { security } = Config.get();
 	const { service, secret, sitekey } = security.captcha;
 
-	if (!service) throw new Error("Cannot verify captcha without service");
+	if (!service || !secret || !sitekey)
+		throw new Error(
+			"CAPTCHA is not configured correctly. https://docs.fosscord.com/setup/server/security/captcha/",
+		);
 
 	const res = await fetch(verifyEndpoints[service], {
 		method: "POST",
@@ -56,9 +59,9 @@ export async function verifyCaptcha(response: string, ip?: string) {
 		},
 		body:
 			`response=${encodeURIComponent(response)}` +
-			`&secret=${encodeURIComponent(secret!)}` +
-			`&sitekey=${encodeURIComponent(sitekey!)}` +
-			(ip ? `&remoteip=${encodeURIComponent(ip!)}` : ""),
+			`&secret=${encodeURIComponent(secret)}` +
+			`&sitekey=${encodeURIComponent(sitekey)}` +
+			(ip ? `&remoteip=${encodeURIComponent(ip)}` : ""),
 	});
 
 	return (await res.json()) as hcaptchaResponse | recaptchaResponse;
diff --git a/src/api/util/utility/ipAddress.ts b/src/api/util/utility/ipAddress.ts
index 785844ce..71a48682 100644
--- a/src/api/util/utility/ipAddress.ts
+++ b/src/api/util/utility/ipAddress.ts
@@ -85,7 +85,7 @@ export async function IPAnalysis(ip: string): Promise<typeof exampleData> {
 
 	return (
 		await fetch(`https://api.ipdata.co/${ip}?api-key=${ipdataApiKey}`)
-	).json() as any; // TODO: types
+	).json();
 }
 
 export function isProxy(data: typeof exampleData) {
@@ -97,14 +97,21 @@ export function isProxy(data: typeof exampleData) {
 }
 
 export function getIpAdress(req: Request): string {
+	// TODO: express can do this (trustProxies: true)?
+
 	return (
+		// eslint-disable-next-line @typescript-eslint/ban-ts-comment
 		// @ts-ignore
 		req.headers[Config.get().security.forwadedFor] ||
 		req.socket.remoteAddress
 	);
 }
 
-export function distanceBetweenLocations(loc1: any, loc2: any): number {
+type Location = { latitude: number; longitude: number };
+export function distanceBetweenLocations(
+	loc1: Location,
+	loc2: Location,
+): number {
 	return distanceBetweenCoords(
 		loc1.latitude,
 		loc1.longitude,
diff --git a/src/api/util/utility/passwordStrength.ts b/src/api/util/utility/passwordStrength.ts
index c4dcd509..b293b856 100644
--- a/src/api/util/utility/passwordStrength.ts
+++ b/src/api/util/utility/passwordStrength.ts
@@ -23,7 +23,7 @@ const reNUMBER = /[0-9]/g;
 const reUPPERCASELETTER = /[A-Z]/g;
 const reSYMBOLS = /[A-Z,a-z,0-9]/g;
 
-const blocklist: string[] = []; // TODO: update ones passwordblocklist is stored in db
+// const blocklist: string[] = []; // TODO: update ones passwordblocklist is stored in db
 /*
  * https://en.wikipedia.org/wiki/Password_policy
  * password must meet following criteria, to be perfect:
@@ -38,7 +38,7 @@ const blocklist: string[] = []; // TODO: update ones passwordblocklist is stored
 export function checkPassword(password: string): number {
 	const { minLength, minNumbers, minUpperCase, minSymbols } =
 		Config.get().register.password;
-	var strength = 0;
+	let strength = 0;
 
 	// checks for total password len
 	if (password.length >= minLength - 1) {
@@ -68,13 +68,13 @@ export function checkPassword(password: string): number {
 		strength = 0;
 	}
 
-	let entropyMap: { [key: string]: number } = {};
+	const entropyMap: { [key: string]: number } = {};
 	for (let i = 0; i < password.length; i++) {
 		if (entropyMap[password[i]]) entropyMap[password[i]]++;
 		else entropyMap[password[i]] = 1;
 	}
 
-	let entropies = Object.values(entropyMap);
+	const entropies = Object.values(entropyMap);
 
 	entropies.map((x) => x / entropyMap.length);
 	strength +=
diff --git a/src/bundle/Server.ts b/src/bundle/Server.ts
index a5f96c3a..96f6a149 100644
--- a/src/bundle/Server.ts
+++ b/src/bundle/Server.ts
@@ -24,7 +24,7 @@ import * as Api from "@fosscord/api";
 import * as Gateway from "@fosscord/gateway";
 import { CDNServer } from "@fosscord/cdn";
 import express from "express";
-import { green, bold, yellow } from "picocolors";
+import { green, bold } from "picocolors";
 import { Config, initDatabase, Sentry } from "@fosscord/util";
 
 const app = express();
diff --git a/src/bundle/start.ts b/src/bundle/start.ts
index 10fb7c36..8da3cc20 100644
--- a/src/bundle/start.ts
+++ b/src/bundle/start.ts
@@ -29,14 +29,15 @@ import { execSync } from "child_process";
 
 const cores = process.env.THREADS ? parseInt(process.env.THREADS) : 1;
 
-if (cluster.isPrimary) {
-	function getCommitOrFail() {
-		try {
-			return execSync("git rev-parse HEAD").toString().trim();
-		} catch (e) {
-			return null;
-		}
+function getCommitOrFail() {
+	try {
+		return execSync("git rev-parse HEAD").toString().trim();
+	} catch (e) {
+		return null;
 	}
+}
+
+if (cluster.isPrimary) {
 	const commit = getCommitOrFail();
 
 	console.log(
@@ -81,14 +82,14 @@ Cores: ${cyan(os.cpus().length)} (Using ${cores} thread(s).)
 		// Fork workers.
 		for (let i = 0; i < cores; i++) {
 			// Delay each worker start if using sqlite database to prevent locking it
-			let delay = process.env.DATABASE?.includes("://") ? 0 : i * 1000;
+			const delay = process.env.DATABASE?.includes("://") ? 0 : i * 1000;
 			setTimeout(() => {
 				cluster.fork();
 				console.log(`[Process] worker ${cyan(i)} started.`);
 			}, delay);
 		}
 
-		cluster.on("message", (sender: Worker, message: any) => {
+		cluster.on("message", (sender: Worker, message) => {
 			for (const id in cluster.workers) {
 				const worker = cluster.workers[id];
 				if (worker === sender || !worker) continue;
@@ -96,7 +97,7 @@ Cores: ${cyan(os.cpus().length)} (Using ${cores} thread(s).)
 			}
 		});
 
-		cluster.on("exit", (worker: any, code: any, signal: any) => {
+		cluster.on("exit", (worker) => {
 			console.log(
 				`[Worker] ${red(
 					`died with PID: ${worker.process.pid} , restarting ...`,
diff --git a/src/cdn/Server.ts b/src/cdn/Server.ts
index bb7c9edf..37317bff 100644
--- a/src/cdn/Server.ts
+++ b/src/cdn/Server.ts
@@ -24,7 +24,7 @@ import guildProfilesRoute from "./routes/guild-profiles";
 import iconsRoute from "./routes/role-icons";
 import bodyParser from "body-parser";
 
-export interface CDNServerOptions extends ServerOptions {}
+export type CDNServerOptions = ServerOptions;
 
 export class CDNServer extends Server {
 	public declare options: CDNServerOptions;
diff --git a/src/cdn/routes/attachments.ts b/src/cdn/routes/attachments.ts
index 76824925..d7764bd7 100644
--- a/src/cdn/routes/attachments.ts
+++ b/src/cdn/routes/attachments.ts
@@ -41,7 +41,7 @@ router.post(
 			throw new HTTPError("Invalid request signature");
 		if (!req.file) throw new HTTPError("file missing");
 
-		const { buffer, mimetype, size, originalname, fieldname } = req.file;
+		const { buffer, mimetype, size, originalname } = req.file;
 		const { channel_id } = req.params;
 		const filename = originalname
 			.replaceAll(" ", "_")
@@ -53,8 +53,8 @@ router.post(
 			Config.get()?.cdn.endpointPublic || "http://localhost:3003";
 
 		await storage.set(path, buffer);
-		var width;
-		var height;
+		let width;
+		let height;
 		if (mimetype.includes("image")) {
 			const dimensions = imageSize(buffer);
 			if (dimensions) {
@@ -81,10 +81,10 @@ router.get(
 	"/:channel_id/:id/:filename",
 	async (req: Request, res: Response) => {
 		const { channel_id, id, filename } = req.params;
-		const { format } = req.query;
+		// const { format } = req.query;
 
 		const path = `attachments/${channel_id}/${id}/${filename}`;
-		let file = await storage.get(path);
+		const file = await storage.get(path);
 		if (!file) throw new HTTPError("File not found");
 		const type = await FileType.fromBuffer(file);
 		let content_type = type?.mime || "application/octet-stream";
diff --git a/src/cdn/routes/avatars.ts b/src/cdn/routes/avatars.ts
index e2d80d11..2c078c29 100644
--- a/src/cdn/routes/avatars.ts
+++ b/src/cdn/routes/avatars.ts
@@ -48,10 +48,10 @@ router.post(
 		if (req.headers.signature !== Config.get().security.requestSignature)
 			throw new HTTPError("Invalid request signature");
 		if (!req.file) throw new HTTPError("Missing file");
-		const { buffer, mimetype, size, originalname, fieldname } = req.file;
+		const { buffer, size } = req.file;
 		const { user_id } = req.params;
 
-		var hash = crypto
+		let hash = crypto
 			.createHash("md5")
 			.update(Snowflake.generate())
 			.digest("hex");
@@ -77,7 +77,7 @@ router.post(
 );
 
 router.get("/:user_id", async (req: Request, res: Response) => {
-	var { user_id } = req.params;
+	let { user_id } = req.params;
 	user_id = user_id.split(".")[0]; // remove .file extension
 	const path = `avatars/${user_id}`;
 
@@ -92,7 +92,8 @@ router.get("/:user_id", async (req: Request, res: Response) => {
 });
 
 export const getAvatar = async (req: Request, res: Response) => {
-	var { user_id, hash } = req.params;
+	const { user_id } = req.params;
+	let { hash } = req.params;
 	hash = hash.split(".")[0]; // remove .file extension
 	const path = `avatars/${user_id}/${hash}`;
 
diff --git a/src/cdn/routes/guild-profiles.ts b/src/cdn/routes/guild-profiles.ts
index 517550b7..a02d152c 100644
--- a/src/cdn/routes/guild-profiles.ts
+++ b/src/cdn/routes/guild-profiles.ts
@@ -45,7 +45,7 @@ router.post("/", multer.single("file"), async (req: Request, res: Response) => {
 	if (req.headers.signature !== Config.get().security.requestSignature)
 		throw new HTTPError("Invalid request signature");
 	if (!req.file) throw new HTTPError("Missing file");
-	const { buffer, mimetype, size, originalname, fieldname } = req.file;
+	const { buffer, size } = req.file;
 	const { guild_id, user_id } = req.params;
 
 	let hash = crypto
@@ -72,7 +72,8 @@ router.post("/", multer.single("file"), async (req: Request, res: Response) => {
 });
 
 router.get("/", async (req: Request, res: Response) => {
-	let { guild_id, user_id } = req.params;
+	const { guild_id } = req.params;
+	let { user_id } = req.params;
 	user_id = user_id.split(".")[0]; // remove .file extension
 	const path = `guilds/${guild_id}/users/${user_id}/avatars`;
 
@@ -87,7 +88,8 @@ router.get("/", async (req: Request, res: Response) => {
 });
 
 router.get("/:hash", async (req: Request, res: Response) => {
-	let { guild_id, user_id, hash } = req.params;
+	const { guild_id, user_id } = req.params;
+	let { hash } = req.params;
 	hash = hash.split(".")[0]; // remove .file extension
 	const path = `guilds/${guild_id}/users/${user_id}/avatars/${hash}`;
 
diff --git a/src/cdn/routes/role-icons.ts b/src/cdn/routes/role-icons.ts
index b6e6812e..c3ad51c1 100644
--- a/src/cdn/routes/role-icons.ts
+++ b/src/cdn/routes/role-icons.ts
@@ -48,10 +48,10 @@ router.post(
 		if (req.headers.signature !== Config.get().security.requestSignature)
 			throw new HTTPError("Invalid request signature");
 		if (!req.file) throw new HTTPError("Missing file");
-		const { buffer, mimetype, size, originalname, fieldname } = req.file;
+		const { buffer, size } = req.file;
 		const { role_id } = req.params;
 
-		var hash = crypto
+		const hash = crypto
 			.createHash("md5")
 			.update(Snowflake.generate())
 			.digest("hex");
@@ -76,7 +76,7 @@ router.post(
 );
 
 router.get("/:role_id", async (req: Request, res: Response) => {
-	var { role_id } = req.params;
+	const { role_id } = req.params;
 	//role_id = role_id.split(".")[0]; // remove .file extension
 	const path = `role-icons/${role_id}`;
 
@@ -91,7 +91,7 @@ router.get("/:role_id", async (req: Request, res: Response) => {
 });
 
 router.get("/:role_id/:hash", async (req: Request, res: Response) => {
-	var { role_id, hash } = req.params;
+	const { role_id, hash } = req.params;
 	//hash = hash.split(".")[0]; // remove .file extension
 	const path = `role-icons/${role_id}/${hash}`;
 
diff --git a/src/cdn/util/FileStorage.ts b/src/cdn/util/FileStorage.ts
index c8473e30..ee087c85 100644
--- a/src/cdn/util/FileStorage.ts
+++ b/src/cdn/util/FileStorage.ts
@@ -28,7 +28,7 @@ import ExifTransformer from "exif-be-gone";
 function getPath(path: string) {
 	// STORAGE_LOCATION has a default value in start.ts
 	const root = process.env.STORAGE_LOCATION || "../";
-	var filename = join(root, path);
+	const filename = join(root, path);
 
 	if (path.indexOf("\0") !== -1 || !filename.startsWith(root))
 		throw new Error("invalid path");
@@ -51,15 +51,15 @@ export class FileStorage implements Storage {
 		}
 	}
 
-	async set(path: string, value: any) {
+	async set(path: string, value: Buffer) {
 		path = getPath(path);
 		if (!fs.existsSync(dirname(path)))
 			fs.mkdirSync(dirname(path), { recursive: true });
 
-		value = Readable.from(value);
+		const ret = Readable.from(value);
 		const cleaned_file = fs.createWriteStream(path);
 
-		return value.pipe(new ExifTransformer()).pipe(cleaned_file);
+		ret.pipe(new ExifTransformer()).pipe(cleaned_file);
 	}
 
 	async delete(path: string) {
diff --git a/src/cdn/util/Storage.ts b/src/cdn/util/Storage.ts
index ee4ae889..0d55bbd0 100644
--- a/src/cdn/util/Storage.ts
+++ b/src/cdn/util/Storage.ts
@@ -19,7 +19,6 @@
 import { FileStorage } from "./FileStorage";
 import path from "path";
 import fs from "fs";
-import { bgCyan, black } from "picocolors";
 import { S3 } from "@aws-sdk/client-s3";
 import { S3Storage } from "./S3Storage";
 process.cwd();
diff --git a/src/gateway/Server.ts b/src/gateway/Server.ts
index f1ef7a27..81e4b7f4 100644
--- a/src/gateway/Server.ts
+++ b/src/gateway/Server.ts
@@ -56,7 +56,6 @@ export class Server {
 		}
 
 		this.server.on("upgrade", (request, socket, head) => {
-			// @ts-ignore
 			this.ws.handleUpgrade(request, socket, head, (socket) => {
 				this.ws.emit("connection", socket, request);
 			});
diff --git a/src/gateway/events/Close.ts b/src/gateway/events/Close.ts
index 6b069d0b..296ab5ee 100644
--- a/src/gateway/events/Close.ts
+++ b/src/gateway/events/Close.ts
@@ -26,7 +26,7 @@ import {
 	User,
 } from "@fosscord/util";
 
-export async function Close(this: WebSocket, code: number, reason: string) {
+export async function Close(this: WebSocket, code: number, reason: Buffer) {
 	console.log("[WebSocket] closed", code, reason.toString());
 	if (this.heartbeatTimeout) clearTimeout(this.heartbeatTimeout);
 	if (this.readyTimeout) clearTimeout(this.readyTimeout);
diff --git a/src/gateway/events/Connection.ts b/src/gateway/events/Connection.ts
index 85ffb1ed..82081266 100644
--- a/src/gateway/events/Connection.ts
+++ b/src/gateway/events/Connection.ts
@@ -16,6 +16,7 @@
 	along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 
+/* eslint-disable @typescript-eslint/ban-ts-comment */
 import WS from "ws";
 import { genSessionId, WebSocket } from "@fosscord/gateway";
 import { Send } from "../util/Send";
@@ -27,10 +28,12 @@ import { Message } from "./Message";
 import { Deflate, Inflate } from "fast-zlib";
 import { URL } from "url";
 import { Config } from "@fosscord/util";
-var erlpack: any;
+let erlpack: unknown;
 try {
 	erlpack = require("@yukikaze-bot/erlpack");
-} catch (error) {}
+} catch (error) {
+	/* empty */
+}
 
 // TODO: check rate limit
 // TODO: specify rate limit in config
diff --git a/src/gateway/events/Message.ts b/src/gateway/events/Message.ts
index 57899a23..b949f273 100644
--- a/src/gateway/events/Message.ts
+++ b/src/gateway/events/Message.ts
@@ -27,14 +27,16 @@ import path from "path";
 import fs from "fs/promises";
 const bigIntJson = BigIntJson({ storeAsString: true });
 
-var erlpack: any;
+let erlpack: { unpack: (buffer: Buffer) => Payload };
 try {
 	erlpack = require("@yukikaze-bot/erlpack");
-} catch (error) {}
+} catch (error) {
+	/* empty */
+}
 
 export async function Message(this: WebSocket, buffer: WS.Data) {
 	// TODO: compression
-	var data: Payload;
+	let data: Payload;
 
 	if (
 		(buffer instanceof Buffer && buffer[0] === 123) || // ASCII 123 = `{`. Bad check for JSON
@@ -44,9 +46,9 @@ export async function Message(this: WebSocket, buffer: WS.Data) {
 	} else if (this.encoding === "json" && buffer instanceof Buffer) {
 		if (this.inflate) {
 			try {
-				buffer = this.inflate.process(buffer) as any;
+				buffer = this.inflate.process(buffer);
 			} catch {
-				buffer = buffer.toString() as any;
+				buffer = buffer.toString();
 			}
 		}
 		data = bigIntJson.parse(buffer as string);
@@ -78,7 +80,6 @@ export async function Message(this: WebSocket, buffer: WS.Data) {
 
 	check.call(this, PayloadSchema, data);
 
-	// @ts-ignore
 	const OPCodeHandler = OPCodeHandlers[data.op];
 	if (!OPCodeHandler) {
 		console.error("[Gateway] Unkown opcode " + data.op);
@@ -100,7 +101,7 @@ export async function Message(this: WebSocket, buffer: WS.Data) {
 			: undefined;
 
 	try {
-		var ret = await OPCodeHandler.call(this, data);
+		const ret = await OPCodeHandler.call(this, data);
 		Sentry.withScope((scope) => {
 			scope.setSpan(transaction);
 			scope.setUser({ id: this.user_id });
diff --git a/src/gateway/listener/listener.ts b/src/gateway/listener/listener.ts
index 9bdee86a..824341f9 100644
--- a/src/gateway/listener/listener.ts
+++ b/src/gateway/listener/listener.ts
@@ -79,7 +79,10 @@ export async function setupListener(this: WebSocket) {
 	const guilds = members.map((x) => x.guild);
 	const dm_channels = recipients.map((x) => x.channel);
 
-	const opts: { acknowledge: boolean; channel?: AMQChannel } = {
+	const opts: {
+		acknowledge: boolean;
+		channel?: AMQChannel & { queues?: unknown };
+	} = {
 		acknowledge: true,
 	};
 	this.listen_options = opts;
@@ -87,7 +90,6 @@ export async function setupListener(this: WebSocket) {
 
 	if (RabbitMQ.connection) {
 		opts.channel = await RabbitMQ.connection.createChannel();
-		// @ts-ignore
 		opts.channel.queues = {};
 	}
 
@@ -113,7 +115,7 @@ export async function setupListener(this: WebSocket) {
 		guild.channels.forEach(async (channel) => {
 			if (
 				permission
-					.overwriteChannel(channel.permission_overwrites!)
+					.overwriteChannel(channel.permission_overwrites ?? [])
 					.has("VIEW_CHANNEL")
 			) {
 				this.events[channel.id] = await listenEvent(
@@ -128,7 +130,7 @@ export async function setupListener(this: WebSocket) {
 	this.once("close", () => {
 		if (opts.channel) opts.channel.close();
 		else {
-			Object.values(this.events).forEach((x) => x());
+			Object.values(this.events).forEach((x) => x?.());
 			Object.values(this.member_events).forEach((x) => x());
 		}
 	});
@@ -137,7 +139,7 @@ export async function setupListener(this: WebSocket) {
 // TODO: only subscribe for events that are in the connection intents
 async function consume(this: WebSocket, opts: EventOpts) {
 	const { data, event } = opts;
-	let id = data.id as string;
+	const id = data.id as string;
 	const permission = this.permissions[id] || new Permissions("ADMINISTRATOR"); // default permission for dm
 
 	const consumer = consume.bind(this);
@@ -150,6 +152,7 @@ async function consume(this: WebSocket, opts: EventOpts) {
 		case "GUILD_MEMBER_REMOVE":
 			this.member_events[data.user.id]?.();
 			delete this.member_events[data.user.id];
+			break;
 		case "GUILD_MEMBER_ADD":
 			if (this.member_events[data.user.id]) break; // already subscribed
 			this.member_events[data.user.id] = await listenEvent(
@@ -158,7 +161,7 @@ async function consume(this: WebSocket, opts: EventOpts) {
 				this.listen_options,
 			);
 			break;
-		case "GUILD_MEMBER_REMOVE":
+		case "GUILD_MEMBER_UPDATE":
 			if (!this.member_events[data.user.id]) break;
 			this.member_events[data.user.id]();
 			break;
@@ -188,9 +191,8 @@ async function consume(this: WebSocket, opts: EventOpts) {
 		case "GUILD_CREATE":
 			this.events[id] = await listenEvent(id, consumer, listenOpts);
 			break;
-		case "CHANNEL_UPDATE":
+		case "CHANNEL_UPDATE": {
 			const exists = this.events[id];
-			// @ts-ignore
 			if (
 				permission
 					.overwriteChannel(data.permission_overwrites)
@@ -204,6 +206,7 @@ async function consume(this: WebSocket, opts: EventOpts) {
 				delete this.events[id];
 			}
 			break;
+		}
 	}
 
 	// permission checking
@@ -218,8 +221,7 @@ async function consume(this: WebSocket, opts: EventOpts) {
 			break;
 		case "GUILD_MEMBER_ADD":
 		case "GUILD_MEMBER_REMOVE":
-		case "GUILD_MEMBER_UPDATE":
-		// only send them, if the user subscribed for this part of the member list, or is a bot
+		case "GUILD_MEMBER_UPDATE": // only send them, if the user subscribed for this part of the member list, or is a bot
 		case "PRESENCE_UPDATE": // exception if user is friend
 			break;
 		case "GUILD_BAN_ADD":
diff --git a/src/gateway/opcodes/Heartbeat.ts b/src/gateway/opcodes/Heartbeat.ts
index b7f21a56..77c8671f 100644
--- a/src/gateway/opcodes/Heartbeat.ts
+++ b/src/gateway/opcodes/Heartbeat.ts
@@ -16,11 +16,11 @@
 	along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-import { Payload, WebSocket } from "@fosscord/gateway";
+import { WebSocket } from "@fosscord/gateway";
 import { setHeartbeat } from "../util/Heartbeat";
 import { Send } from "../util/Send";
 
-export async function onHeartbeat(this: WebSocket, data: Payload) {
+export async function onHeartbeat(this: WebSocket) {
 	// TODO: validate payload
 
 	setHeartbeat(this);
diff --git a/src/gateway/opcodes/Identify.ts b/src/gateway/opcodes/Identify.ts
index 8d762967..030ca66e 100644
--- a/src/gateway/opcodes/Identify.ts
+++ b/src/gateway/opcodes/Identify.ts
@@ -42,13 +42,13 @@ import {
 	UserGuildSettings,
 	ReadyGuildDTO,
 	Guild,
+	UserTokenData,
 } from "@fosscord/util";
 import { Send } from "../util/Send";
 import { CLOSECODES, OPCODES } from "../util/Constants";
-import { genSessionId } from "../util/SessionUtils";
 import { setupListener } from "../listener/listener";
 // import experiments from "./experiments.json";
-const experiments: any = [];
+const experiments: unknown[] = [];
 import { check } from "./instanceOf";
 import { Recipient } from "@fosscord/util";
 
@@ -56,6 +56,8 @@ import { Recipient } from "@fosscord/util";
 // TODO: check privileged intents, if defined in the config
 // TODO: check if already identified
 
+// TODO: Refactor identify ( and lazyrequest, tbh )
+
 export async function onIdentify(this: WebSocket, data: Payload) {
 	clearTimeout(this.readyTimeout);
 	// TODO: is this needed now that we use `json-bigint`?
@@ -65,15 +67,16 @@ export async function onIdentify(this: WebSocket, data: Payload) {
 
 	const identify: IdentifySchema = data.d;
 
+	let decoded: UserTokenData["decoded"];
 	try {
 		const { jwtSecret } = Config.get().security;
-		var { decoded } = await checkToken(identify.token, jwtSecret); // will throw an error if invalid
+		decoded = (await checkToken(identify.token, jwtSecret)).decoded; // will throw an error if invalid
 	} catch (error) {
 		console.error("invalid token", error);
 		return this.close(CLOSECODES.Authentication_failed);
 	}
 	this.user_id = decoded.id;
-	let session_id = this.session_id;
+	const session_id = this.session_id;
 
 	const [user, read_states, members, recipients, session, application] =
 		await Promise.all([
@@ -144,7 +147,7 @@ export async function onIdentify(this: WebSocket, data: Payload) {
 			return this.close(CLOSECODES.Invalid_shard);
 		}
 	}
-	var users: PublicUser[] = [];
+	let users: PublicUser[] = [];
 
 	const merged_members = members.map((x: Member) => {
 		return [
@@ -156,18 +159,18 @@ export async function onIdentify(this: WebSocket, data: Payload) {
 			},
 		];
 	}) as PublicMember[][];
-	let guilds = members.map((x) => ({ ...x.guild, joined_at: x.joined_at }));
+	// TODO: This type is bad.
+	let guilds: Partial<Guild>[] = members.map((x) => ({
+		...x.guild,
+		joined_at: x.joined_at,
+	}));
 
 	const pending_guilds: typeof guilds = [];
-	// @ts-ignore
-	guilds = guilds.map((guild) => {
-		if (user.bot) {
+	if (user.bot)
+		guilds = guilds.map((guild) => {
 			pending_guilds.push(guild);
 			return { id: guild.id, unavailable: true };
-		}
-
-		return guild;
-	});
+		});
 
 	// TODO: Rewrite this. Perhaps a DTO?
 	const user_guild_settings_entries = members.map((x) => ({
@@ -180,24 +183,25 @@ export async function onIdentify(this: WebSocket, data: Payload) {
 			...y[1],
 			channel_id: y[0],
 		})),
-	})) as any as UserGuildSettings[];
+	})) as unknown as UserGuildSettings[];
 
 	const channels = recipients.map((x) => {
+		// eslint-disable-next-line @typescript-eslint/ban-ts-comment
 		//@ts-ignore
-		x.channel.recipients = x.channel.recipients?.map((x) =>
+		x.channel.recipients = x.channel.recipients.map((x) =>
 			x.user.toPublicUser(),
 		);
 		//TODO is this needed? check if users in group dm that are not friends are sent in the READY event
 		users = users.concat(x.channel.recipients as unknown as User[]);
 		if (x.channel.isDm()) {
-			x.channel.recipients = x.channel.recipients!.filter(
+			x.channel.recipients = x.channel.recipients?.filter(
 				(x) => x.id !== this.user_id,
 			);
 		}
 		return x.channel;
 	});
 
-	for (let relation of user.relationships) {
+	for (const relation of user.relationships) {
 		const related_user = relation.to;
 		const public_related_user = {
 			username: related_user.username,
@@ -236,7 +240,7 @@ export async function onIdentify(this: WebSocket, data: Payload) {
 		} as PresenceUpdateEvent);
 	});
 
-	read_states.forEach((s: any) => {
+	read_states.forEach((s: Partial<ReadState>) => {
 		s.id = s.channel_id;
 		delete s.user_id;
 		delete s.channel_id;
@@ -275,10 +279,11 @@ export async function onIdentify(this: WebSocket, data: Payload) {
 		}, //TODO: check this code!
 		user: privateUser,
 		user_settings: user.settings,
+		// eslint-disable-next-line @typescript-eslint/ban-ts-comment
 		// @ts-ignore
-		guilds: guilds.map((x) => {
+		guilds: guilds.map((x: Guild & { joined_at: Date }) => {
 			return {
-				...new ReadyGuildDTO(x as Guild & { joined_at: Date }).toJSON(),
+				...new ReadyGuildDTO(x).toJSON(),
 				guild_hashes: {},
 				joined_at: x.joined_at,
 			};
@@ -307,6 +312,7 @@ export async function onIdentify(this: WebSocket, data: Payload) {
 		},
 		country_code: user.settings.locale,
 		friend_suggestion_count: 0, // TODO
+		// eslint-disable-next-line @typescript-eslint/ban-ts-comment
 		// @ts-ignore
 		experiments: experiments, // TODO
 		guild_join_requests: [], // TODO what is this?
diff --git a/src/gateway/opcodes/LazyRequest.ts b/src/gateway/opcodes/LazyRequest.ts
index d4b612b8..93524058 100644
--- a/src/gateway/opcodes/LazyRequest.ts
+++ b/src/gateway/opcodes/LazyRequest.ts
@@ -46,24 +46,25 @@ async function getMembers(guild_id: string, range: [number, number]) {
 
 	let members: Member[] = [];
 	try {
-		members = await getDatabase()!
-			.getRepository(Member)
-			.createQueryBuilder("member")
-			.where("member.guild_id = :guild_id", { guild_id })
-			.leftJoinAndSelect("member.roles", "role")
-			.leftJoinAndSelect("member.user", "user")
-			.leftJoinAndSelect("user.sessions", "session")
-			.addSelect("user.settings")
-			.addSelect(
-				"CASE WHEN session.status = 'offline' THEN 0 ELSE 1 END",
-				"_status",
-			)
-			.orderBy("role.position", "DESC")
-			.addOrderBy("_status", "DESC")
-			.addOrderBy("user.username", "ASC")
-			.offset(Number(range[0]) || 0)
-			.limit(Number(range[1]) || 100)
-			.getMany();
+		members =
+			(await getDatabase()
+				?.getRepository(Member)
+				.createQueryBuilder("member")
+				.where("member.guild_id = :guild_id", { guild_id })
+				.leftJoinAndSelect("member.roles", "role")
+				.leftJoinAndSelect("member.user", "user")
+				.leftJoinAndSelect("user.sessions", "session")
+				.addSelect("user.settings")
+				.addSelect(
+					"CASE WHEN session.status = 'offline' THEN 0 ELSE 1 END",
+					"_status",
+				)
+				.orderBy("role.position", "DESC")
+				.addOrderBy("_status", "DESC")
+				.addOrderBy("user.username", "ASC")
+				.offset(Number(range[0]) || 0)
+				.limit(Number(range[1]) || 100)
+				.getMany()) ?? [];
 	} catch (e) {
 		console.error(`LazyRequest`, e);
 	}
@@ -77,7 +78,7 @@ async function getMembers(guild_id: string, range: [number, number]) {
 		};
 	}
 
-	const groups = [] as any[];
+	const groups = [];
 	const items = [];
 	const member_roles = members
 		.map((m) => m.roles)
@@ -93,10 +94,9 @@ async function getMembers(guild_id: string, range: [number, number]) {
 	const offlineItems = [];
 
 	for (const role of member_roles) {
-		// @ts-ignore
-		const [role_members, other_members]: Member[][] = partition(
+		const [role_members, other_members] = partition(
 			members,
-			(m: Member) => m.roles.find((r) => r.id === role.id),
+			(m: Member) => !!m.roles.find((r) => r.id === role.id),
 		);
 		const group = {
 			count: role_members.length,
@@ -126,7 +126,7 @@ async function getMembers(guild_id: string, range: [number, number]) {
 					(a.activities.length - b.activities.length) * 2
 				);
 			});
-			var session: Session | undefined = sessions.first();
+			const session: Session | undefined = sessions.first();
 
 			if (session?.status == "offline") {
 				session.status = member?.user?.settings?.status || "online";
@@ -189,7 +189,9 @@ async function getMembers(guild_id: string, range: [number, number]) {
 export async function onLazyRequest(this: WebSocket, { d }: Payload) {
 	// TODO: check data
 	check.call(this, LazyRequestSchema, d);
+	// eslint-disable-next-line @typescript-eslint/no-unused-vars
 	const { guild_id, typing, channels, activities } = d as LazyRequestSchema;
+	if (!channels) throw new Error("Must provide channel ranges");
 
 	const channel_id = Object.keys(channels || {}).first();
 	if (!channel_id) return;
@@ -197,7 +199,7 @@ export async function onLazyRequest(this: WebSocket, { d }: Payload) {
 	const permissions = await getPermission(this.user_id, guild_id, channel_id);
 	permissions.hasThrow("VIEW_CHANNEL");
 
-	const ranges = channels![channel_id];
+	const ranges = channels[channel_id];
 	if (!Array.isArray(ranges)) throw new Error("Not a valid Array");
 
 	const member_count = await Member.count({ where: { guild_id } });
@@ -244,15 +246,10 @@ export async function onLazyRequest(this: WebSocket, { d }: Payload) {
 	});
 }
 
-function partition<T>(array: T[], isValid: Function) {
-	// @ts-ignore
-	return array.reduce(
-		// @ts-ignore
-		([pass, fail], elem) => {
-			return isValid(elem)
-				? [[...pass, elem], fail]
-				: [pass, [...fail, elem]];
-		},
-		[[], []],
-	);
+/* https://stackoverflow.com/a/50636286 */
+function partition<T>(array: T[], filter: (elem: T) => boolean) {
+	const pass: T[] = [],
+		fail: T[] = [];
+	array.forEach((e) => (filter(e) ? pass : fail).push(e));
+	return [pass, fail];
 }
diff --git a/src/gateway/opcodes/RequestGuildMembers.ts b/src/gateway/opcodes/RequestGuildMembers.ts
index d669b30e..7822813b 100644
--- a/src/gateway/opcodes/RequestGuildMembers.ts
+++ b/src/gateway/opcodes/RequestGuildMembers.ts
@@ -16,8 +16,8 @@
 	along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-import { Payload, WebSocket } from "@fosscord/gateway";
+import { WebSocket } from "@fosscord/gateway";
 
-export function onRequestGuildMembers(this: WebSocket, data: Payload) {
+export function onRequestGuildMembers(this: WebSocket) {
 	// return this.close(CLOSECODES.Unknown_error);
 }
diff --git a/src/gateway/opcodes/Resume.ts b/src/gateway/opcodes/Resume.ts
index d4bd5320..a8650cc4 100644
--- a/src/gateway/opcodes/Resume.ts
+++ b/src/gateway/opcodes/Resume.ts
@@ -16,10 +16,10 @@
 	along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-import { WebSocket, Payload } from "@fosscord/gateway";
+import { WebSocket } from "@fosscord/gateway";
 import { Send } from "../util/Send";
 
-export async function onResume(this: WebSocket, data: Payload) {
+export async function onResume(this: WebSocket) {
 	console.log("Got Resume -> cancel not implemented");
 	await Send(this, {
 		op: 9,
diff --git a/src/gateway/opcodes/VoiceStateUpdate.ts b/src/gateway/opcodes/VoiceStateUpdate.ts
index 5ee02e82..d300d7b7 100644
--- a/src/gateway/opcodes/VoiceStateUpdate.ts
+++ b/src/gateway/opcodes/VoiceStateUpdate.ts
@@ -99,6 +99,7 @@ export async function onVoiceStateUpdate(this: WebSocket, data: Payload) {
 		voiceState.token = genVoiceToken();
 	voiceState.session_id = this.session_id;
 
+	// eslint-disable-next-line @typescript-eslint/no-unused-vars
 	const { id, ...newObj } = voiceState;
 
 	await Promise.all([
diff --git a/src/gateway/opcodes/index.ts b/src/gateway/opcodes/index.ts
index 05e8964b..1e32f1e6 100644
--- a/src/gateway/opcodes/index.ts
+++ b/src/gateway/opcodes/index.ts
@@ -25,7 +25,7 @@ import { onRequestGuildMembers } from "./RequestGuildMembers";
 import { onResume } from "./Resume";
 import { onVoiceStateUpdate } from "./VoiceStateUpdate";
 
-export type OPCodeHandler = (this: WebSocket, data: Payload) => any;
+export type OPCodeHandler = (this: WebSocket, data: Payload) => unknown;
 
 export default {
 	1: onHeartbeat,
@@ -40,4 +40,4 @@ export default {
 	// 10: Hello
 	// 13: Dm_update
 	14: onLazyRequest,
-};
+} as { [key: number]: OPCodeHandler };
diff --git a/src/gateway/opcodes/instanceOf.ts b/src/gateway/opcodes/instanceOf.ts
index 17de0a67..6c23cb08 100644
--- a/src/gateway/opcodes/instanceOf.ts
+++ b/src/gateway/opcodes/instanceOf.ts
@@ -20,7 +20,7 @@ import { instanceOf } from "lambert-server";
 import { WebSocket } from "@fosscord/gateway";
 import { CLOSECODES } from "../util/Constants";
 
-export function check(this: WebSocket, schema: any, data: any) {
+export function check(this: WebSocket, schema: unknown, data: unknown) {
 	try {
 		const error = instanceOf(schema, data, { path: "body" });
 		if (error !== true) {
diff --git a/src/gateway/start.ts b/src/gateway/start.ts
index b86c3eca..79448f91 100644
--- a/src/gateway/start.ts
+++ b/src/gateway/start.ts
@@ -24,7 +24,7 @@ import { Server } from "./Server";
 import { config } from "dotenv";
 config();
 
-var port = Number(process.env.PORT);
+let port = Number(process.env.PORT);
 if (isNaN(port)) port = 3002;
 
 const server = new Server({
diff --git a/src/gateway/util/Constants.ts b/src/gateway/util/Constants.ts
index cc67ed0f..cb60005c 100644
--- a/src/gateway/util/Constants.ts
+++ b/src/gateway/util/Constants.ts
@@ -64,6 +64,7 @@ export enum CLOSECODES {
 
 export interface Payload {
 	op: OPCODES /*  | VoiceOPCodes */;
+	// eslint-disable-next-line @typescript-eslint/no-explicit-any
 	d?: any;
 	s?: number;
 	t?: string;
diff --git a/src/gateway/util/Send.ts b/src/gateway/util/Send.ts
index 1ca143b6..a89d92d7 100644
--- a/src/gateway/util/Send.ts
+++ b/src/gateway/util/Send.ts
@@ -16,7 +16,7 @@
 	along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-var erlpack: any;
+let erlpack: { pack: (data: Payload) => Buffer };
 try {
 	erlpack = require("@yukikaze-bot/erlpack");
 } catch (error) {
@@ -63,7 +63,7 @@ export function Send(socket: WebSocket, data: Payload) {
 			return;
 		}
 
-		socket.send(buffer, (err: any) => {
+		socket.send(buffer, (err) => {
 			if (err) return rej(err);
 			return res(null);
 		});
diff --git a/src/gateway/util/WebSocket.ts b/src/gateway/util/WebSocket.ts
index d4a4b8b3..14917f21 100644
--- a/src/gateway/util/WebSocket.ts
+++ b/src/gateway/util/WebSocket.ts
@@ -16,7 +16,7 @@
 	along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-import { Intents, Permissions } from "@fosscord/util";
+import { Intents, ListenEventOpts, Permissions } from "@fosscord/util";
 import WS from "ws";
 import { Deflate, Inflate } from "fast-zlib";
 // import { Client } from "@fosscord/webrtc";
@@ -37,8 +37,8 @@ export interface WebSocket extends WS {
 	intents: Intents;
 	sequence: number;
 	permissions: Record<string, Permissions>;
-	events: Record<string, Function>;
-	member_events: Record<string, Function>;
-	listen_options: any;
+	events: Record<string, undefined | (() => unknown)>;
+	member_events: Record<string, () => unknown>;
+	listen_options: ListenEventOpts;
 	// client?: Client;
 }
diff --git a/src/util/config/types/GifConfiguration.ts b/src/util/config/types/GifConfiguration.ts
index a623448c..0e5583fa 100644
--- a/src/util/config/types/GifConfiguration.ts
+++ b/src/util/config/types/GifConfiguration.ts
@@ -18,6 +18,6 @@
 
 export class GifConfiguration {
 	enabled: boolean = true;
-	provider: "tenor" = "tenor"; // more coming soon
+	provider = "tenor" as const; // more coming soon
 	apiKey?: string = "LIVDSRZULELA";
 }
diff --git a/src/util/dtos/DmChannelDTO.ts b/src/util/dtos/DmChannelDTO.ts
index 9d4d8dc3..02f7e8f3 100644
--- a/src/util/dtos/DmChannelDTO.ts
+++ b/src/util/dtos/DmChannelDTO.ts
@@ -44,16 +44,14 @@ export class DmChannelDTO {
 		obj.type = channel.type;
 		obj.recipients = (
 			await Promise.all(
-				channel
-					.recipients!.filter(
-						(r) => !excluded_recipients.includes(r.user_id),
-					)
+				channel.recipients
+					?.filter((r) => !excluded_recipients.includes(r.user_id))
 					.map(async (r) => {
 						return await User.findOneOrFail({
 							where: { id: r.user_id },
 							select: PublicUserProjection,
 						});
-					}),
+					}) || [],
 			)
 		).map((u) => new MinimalPublicUserDTO(u));
 		return obj;
diff --git a/src/util/dtos/ReadyGuildDTO.ts b/src/util/dtos/ReadyGuildDTO.ts
index 38303aed..97e6931f 100644
--- a/src/util/dtos/ReadyGuildDTO.ts
+++ b/src/util/dtos/ReadyGuildDTO.ts
@@ -23,7 +23,7 @@ export interface IReadyGuildDTO {
 	channels: Channel[];
 	data_mode: string; // what is this
 	emojis: Emoji[];
-	guild_scheduled_events: any[];
+	guild_scheduled_events: unknown[]; // TODO
 	id: string;
 	large: boolean | undefined;
 	lazy: boolean;
@@ -57,12 +57,12 @@ export interface IReadyGuildDTO {
 		max_video_channel_users: number | undefined;
 		max_members: number | undefined;
 		nsfw_level: number | undefined;
-		hub_type?: any | null; // ????
+		hub_type?: unknown | null; // ????
 	};
 	roles: Role[];
-	stage_instances: any[];
+	stage_instances: unknown[];
 	stickers: Sticker[];
-	threads: any[];
+	threads: unknown[];
 	version: string;
 }
 
@@ -71,7 +71,7 @@ export class ReadyGuildDTO implements IReadyGuildDTO {
 	channels: Channel[];
 	data_mode: string; // what is this
 	emojis: Emoji[];
-	guild_scheduled_events: any[];
+	guild_scheduled_events: unknown[];
 	id: string;
 	large: boolean | undefined;
 	lazy: boolean;
@@ -105,12 +105,12 @@ export class ReadyGuildDTO implements IReadyGuildDTO {
 		max_video_channel_users: number | undefined;
 		max_members: number | undefined;
 		nsfw_level: number | undefined;
-		hub_type?: any | null; // ????
+		hub_type?: unknown | null; // ????
 	};
 	roles: Role[];
-	stage_instances: any[];
+	stage_instances: unknown[];
 	stickers: Sticker[];
-	threads: any[];
+	threads: unknown[];
 	version: string;
 
 	constructor(guild: Guild) {
diff --git a/src/util/entities/Application.ts b/src/util/entities/Application.ts
index 94a015e9..94709320 100644
--- a/src/util/entities/Application.ts
+++ b/src/util/entities/Application.ts
@@ -16,16 +16,8 @@
 	along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-import {
-	Column,
-	Entity,
-	JoinColumn,
-	ManyToOne,
-	OneToOne,
-	RelationId,
-} from "typeorm";
+import { Column, Entity, JoinColumn, ManyToOne, OneToOne } from "typeorm";
 import { BaseClass } from "./BaseClass";
-import { Guild } from "./Guild";
 import { Team } from "./Team";
 import { User } from "./User";
 
@@ -44,7 +36,7 @@ export class Application extends BaseClass {
 	summary: string = "";
 
 	@Column({ type: "simple-json", nullable: true })
-	type?: any;
+	type?: object; // TODO: this type is bad
 
 	@Column()
 	hook: boolean = true;
@@ -176,6 +168,6 @@ export interface ApplicationCommandInteractionData {
 
 export interface ApplicationCommandInteractionDataOption {
 	name: string;
-	value?: any;
+	value?: unknown;
 	options?: ApplicationCommandInteractionDataOption[];
 }
diff --git a/src/util/entities/AuditLog.ts b/src/util/entities/AuditLog.ts
index 68893ea8..0cc2fc04 100644
--- a/src/util/entities/AuditLog.ts
+++ b/src/util/entities/AuditLog.ts
@@ -173,8 +173,8 @@ export interface AuditLogChangeValue {
 	explicit_content_filter?: number;
 	default_message_notifications?: number;
 	vanity_url_code?: string;
-	$add?: {}[];
-	$remove?: {}[];
+	$add?: object[]; // TODO: These types are bad.
+	$remove?: object[];
 	prune_delete_days?: number;
 	widget_enabled?: boolean;
 	widget_channel_id?: string;
diff --git a/src/util/entities/BackupCodes.ts b/src/util/entities/BackupCodes.ts
index 1245ecd1..467e1fe3 100644
--- a/src/util/entities/BackupCodes.ts
+++ b/src/util/entities/BackupCodes.ts
@@ -16,7 +16,7 @@
 	along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
+import { Column, Entity, JoinColumn, ManyToOne } from "typeorm";
 import { BaseClass } from "./BaseClass";
 import { User } from "./User";
 import crypto from "crypto";
@@ -38,7 +38,7 @@ export class BackupCode extends BaseClass {
 }
 
 export function generateMfaBackupCodes(user_id: string) {
-	let backup_codes: BackupCode[] = [];
+	const backup_codes: BackupCode[] = [];
 	for (let i = 0; i < 10; i++) {
 		const code = BackupCode.create({
 			user: { id: user_id },
diff --git a/src/util/entities/BaseClass.ts b/src/util/entities/BaseClass.ts
index e3df5ad4..445b3fc9 100644
--- a/src/util/entities/BaseClass.ts
+++ b/src/util/entities/BaseClass.ts
@@ -29,7 +29,7 @@ import { getDatabase } from "../util/Database";
 import { OrmUtils } from "../imports/OrmUtils";
 
 export class BaseClassWithoutId extends BaseEntity {
-	private get construct(): any {
+	private get construct() {
 		return this.constructor;
 	}
 
@@ -37,19 +37,24 @@ export class BaseClassWithoutId extends BaseEntity {
 		return getDatabase()?.getMetadata(this.construct);
 	}
 
-	assign(props: any) {
+	assign(props: object) {
 		OrmUtils.mergeDeep(this, props);
 		return this;
 	}
 
+	// TODO: fix eslint
+	// eslint-disable-next-line @typescript-eslint/no-explicit-any
 	toJSON(): any {
 		return Object.fromEntries(
+			// eslint-disable-next-line @typescript-eslint/ban-ts-comment, @typescript-eslint/no-non-null-assertion
 			this.metadata!.columns // @ts-ignore
 				.map((x) => [x.propertyName, this[x.propertyName]])
 				.concat(
+					// eslint-disable-next-line @typescript-eslint/ban-ts-comment
 					// @ts-ignore
 					this.metadata.relations.map((x) => [
 						x.propertyName,
+						// eslint-disable-next-line @typescript-eslint/ban-ts-comment
 						// @ts-ignore
 						this[x.propertyName],
 					]),
diff --git a/src/util/entities/Channel.ts b/src/util/entities/Channel.ts
index 2e5f030c..1f128713 100644
--- a/src/util/entities/Channel.ts
+++ b/src/util/entities/Channel.ts
@@ -35,7 +35,6 @@ import {
 	Snowflake,
 	trimSpecial,
 	InvisibleCharacters,
-	ChannelTypes,
 } from "../util";
 import { ChannelCreateEvent, ChannelRecipientRemoveEvent } from "../interfaces";
 import { Recipient } from "./Recipient";
@@ -219,7 +218,7 @@ export class Channel extends BaseClass {
 				!guild.features.includes("ALLOW_INVALID_CHANNEL_NAMES") &&
 				channel.name
 			) {
-				for (var character of InvisibleCharacters)
+				for (const character of InvisibleCharacters)
 					if (channel.name.includes(character))
 						throw new HTTPError(
 							"Channel name cannot include invalid characters",
@@ -237,7 +236,7 @@ export class Channel extends BaseClass {
 							403,
 						);
 
-					if (channel.name.match(/\-\-+/g))
+					if (channel.name.match(/--+/g))
 						throw new HTTPError(
 							"Channel name cannot include multiple adjacent dashes.",
 							403,
@@ -344,8 +343,9 @@ export class Channel extends BaseClass {
 			relations: ["channel", "channel.recipients"],
 		});
 
-		for (let ur of userRecipients) {
-			let re = ur.channel.recipients!.map((r) => r.user_id);
+		for (const ur of userRecipients) {
+			if (!ur.channel.recipients) continue;
+			const re = ur.channel.recipients.map((r) => r.user_id);
 			if (re.length === channelRecipients.length) {
 				if (containsAll(re, channelRecipients)) {
 					if (channel == null) {
@@ -380,8 +380,8 @@ export class Channel extends BaseClass {
 
 		const channel_dto = await DmChannelDTO.from(channel);
 
-		if (type === ChannelType.GROUP_DM) {
-			for (let recipient of channel.recipients!) {
+		if (type === ChannelType.GROUP_DM && channel.recipients) {
+			for (const recipient of channel.recipients) {
 				await emitEvent({
 					event: "CHANNEL_CREATE",
 					data: channel_dto.excludedRecipients([recipient.user_id]),
diff --git a/src/util/entities/ConnectedAccount.ts b/src/util/entities/ConnectedAccount.ts
index 1d0d0586..9f0ce35e 100644
--- a/src/util/entities/ConnectedAccount.ts
+++ b/src/util/entities/ConnectedAccount.ts
@@ -20,8 +20,10 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
 import { BaseClass } from "./BaseClass";
 import { User } from "./User";
 
-export interface PublicConnectedAccount
-	extends Pick<ConnectedAccount, "name" | "type" | "verified"> {}
+export type PublicConnectedAccount = Pick<
+	ConnectedAccount,
+	"name" | "type" | "verified"
+>;
 
 @Entity("connected_accounts")
 export class ConnectedAccount extends BaseClass {
diff --git a/src/util/entities/Emoji.ts b/src/util/entities/Emoji.ts
index 95a641f1..94ce3d54 100644
--- a/src/util/entities/Emoji.ts
+++ b/src/util/entities/Emoji.ts
@@ -20,7 +20,6 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
 import { User } from ".";
 import { BaseClass } from "./BaseClass";
 import { Guild } from "./Guild";
-import { Role } from "./Role";
 
 @Entity("emojis")
 export class Emoji extends BaseClass {
diff --git a/src/util/entities/Encryption.ts b/src/util/entities/Encryption.ts
index db9d0983..016b4331 100644
--- a/src/util/entities/Encryption.ts
+++ b/src/util/entities/Encryption.ts
@@ -16,32 +16,8 @@
 	along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-import {
-	Column,
-	Entity,
-	JoinColumn,
-	ManyToOne,
-	OneToMany,
-	RelationId,
-} from "typeorm";
+import { Column, Entity } from "typeorm";
 import { BaseClass } from "./BaseClass";
-import { Guild } from "./Guild";
-import { PublicUserProjection, User } from "./User";
-import { HTTPError } from "lambert-server";
-import {
-	containsAll,
-	emitEvent,
-	getPermission,
-	Snowflake,
-	trimSpecial,
-	InvisibleCharacters,
-} from "../util";
-import { BitField, BitFieldResolvable, BitFlag } from "../util/BitField";
-import { Recipient } from "./Recipient";
-import { Message } from "./Message";
-import { ReadState } from "./ReadState";
-import { Invite } from "./Invite";
-import { DmChannelDTO } from "../dtos";
 
 @Entity("security_settings")
 export class SecuritySettings extends BaseClass {
diff --git a/src/util/entities/Guild.ts b/src/util/entities/Guild.ts
index 9f300334..c835f5fc 100644
--- a/src/util/entities/Guild.ts
+++ b/src/util/entities/Guild.ts
@@ -20,10 +20,8 @@ import {
 	Column,
 	Entity,
 	JoinColumn,
-	ManyToMany,
 	ManyToOne,
 	OneToMany,
-	OneToOne,
 	RelationId,
 } from "typeorm";
 import { Config, handleFile, Snowflake } from "..";
@@ -370,12 +368,12 @@ export class Guild extends BaseClass {
 			}
 		});
 
-		for (const channel of body.channels?.sort((a, b) =>
+		for (const channel of body.channels.sort((a) =>
 			a.parent_id ? 1 : -1,
 		)) {
-			var id = ids.get(channel.id) || Snowflake.generate();
+			const id = ids.get(channel.id) || Snowflake.generate();
 
-			var parent_id = ids.get(channel.parent_id);
+			const parent_id = ids.get(channel.parent_id);
 
 			await Channel.createChannel(
 				{ ...channel, guild_id, id, parent_id },
diff --git a/src/util/entities/Member.ts b/src/util/entities/Member.ts
index 801b5738..c68fe215 100644
--- a/src/util/entities/Member.ts
+++ b/src/util/entities/Member.ts
@@ -33,7 +33,7 @@ import {
 	RelationId,
 } from "typeorm";
 import { Guild } from "./Guild";
-import { Config, emitEvent, FieldErrors } from "../util";
+import { Config, emitEvent } from "../util";
 import {
 	GuildCreateEvent,
 	GuildDeleteEvent,
@@ -212,12 +212,16 @@ export class Member extends BaseClassWithoutId {
 	}
 
 	static async addRole(user_id: string, guild_id: string, role_id: string) {
-		const [member, role] = await Promise.all([
+		const [member] = await Promise.all([
 			Member.findOneOrFail({
 				where: { id: user_id, guild_id },
 				relations: ["user", "roles"], // we don't want to load  the role objects just the ids
-				//@ts-ignore
-				select: ["index", "roles.id"], // TODO fix type
+				select: {
+					index: true,
+					roles: {
+						id: true,
+					},
+				},
 			}),
 			Role.findOneOrFail({
 				where: { id: role_id, guild_id },
@@ -249,8 +253,12 @@ export class Member extends BaseClassWithoutId {
 			Member.findOneOrFail({
 				where: { id: user_id, guild_id },
 				relations: ["user", "roles"], // we don't want to load  the role objects just the ids
-				//@ts-ignore
-				select: ["roles.id", "index"], // TODO: fix type
+				select: {
+					index: true,
+					roles: {
+						id: true,
+					},
+				},
 			}),
 			await Role.findOneOrFail({ where: { id: role_id, guild_id } }),
 		]);
@@ -327,7 +335,7 @@ export class Member extends BaseClassWithoutId {
 				guild_id,
 				user: {
 					sessions: {
-						status: Not("invisible" as "invisible"), // lol typescript?
+						status: Not("invisible" as const), // lol typescript?
 					},
 				},
 			},
@@ -506,8 +514,7 @@ export const PublicMemberProjection: PublicMemberKeys[] = [
 	"premium_since",
 ];
 
-// @ts-ignore
-export type PublicMember = Pick<Member, Omit<PublicMemberKeys, "roles">> & {
+export type PublicMember = Omit<Pick<Member, PublicMemberKeys>, "roles"> & {
 	user: PublicUser;
 	roles: string[]; // only role ids not objects
 };
diff --git a/src/util/entities/ReadState.ts b/src/util/entities/ReadState.ts
index a907b701..825beb03 100644
--- a/src/util/entities/ReadState.ts
+++ b/src/util/entities/ReadState.ts
@@ -26,7 +26,6 @@ import {
 } from "typeorm";
 import { BaseClass } from "./BaseClass";
 import { Channel } from "./Channel";
-import { Message } from "./Message";
 import { User } from "./User";
 
 // for read receipts
diff --git a/src/util/entities/StickerPack.ts b/src/util/entities/StickerPack.ts
index 911d8d05..ce8d5e87 100644
--- a/src/util/entities/StickerPack.ts
+++ b/src/util/entities/StickerPack.ts
@@ -22,7 +22,6 @@ import {
 	JoinColumn,
 	ManyToOne,
 	OneToMany,
-	OneToOne,
 	RelationId,
 } from "typeorm";
 import { Sticker } from ".";
diff --git a/src/util/entities/Team.ts b/src/util/entities/Team.ts
index 730ff75f..82859409 100644
--- a/src/util/entities/Team.ts
+++ b/src/util/entities/Team.ts
@@ -20,7 +20,6 @@ import {
 	Column,
 	Entity,
 	JoinColumn,
-	ManyToMany,
 	ManyToOne,
 	OneToMany,
 	RelationId,
diff --git a/src/util/entities/User.ts b/src/util/entities/User.ts
index ed9e3884..658584c3 100644
--- a/src/util/entities/User.ts
+++ b/src/util/entities/User.ts
@@ -17,8 +17,6 @@
 */
 
 import {
-	BeforeInsert,
-	BeforeUpdate,
 	Column,
 	Entity,
 	FindOneOptions,
@@ -34,6 +32,7 @@ import { Member } from "./Member";
 import { UserSettings } from "./UserSettings";
 import { Session } from "./Session";
 import { Config, FieldErrors, Snowflake, trimSpecial, adjustEmail } from "..";
+import { Request } from "express";
 
 export enum PublicUserEnum {
 	username,
@@ -80,7 +79,7 @@ export const PrivateUserProjection = [
 // Private user data that should never get sent to the client
 export type PublicUser = Pick<User, PublicUserKeys>;
 
-export interface UserPublic extends Pick<User, PublicUserKeys> {}
+export type UserPublic = Pick<User, PublicUserKeys>;
 
 export interface UserPrivate extends Pick<User, PrivateUserKeys> {
 	locale: string;
@@ -266,6 +265,7 @@ export class User extends BaseClass {
 	}
 
 	toPublicUser() {
+		// eslint-disable-next-line @typescript-eslint/no-explicit-any
 		const user: any = {};
 		PublicUserProjection.forEach((x) => {
 			user[x] = this[x];
@@ -277,6 +277,7 @@ export class User extends BaseClass {
 		return await User.findOneOrFail({
 			where: { id: user_id },
 			...opts,
+			// eslint-disable-next-line @typescript-eslint/ban-ts-comment
 			//@ts-ignore
 			select: [...PublicUserProjection, ...(opts?.select || [])], // TODO: fix
 		});
@@ -328,7 +329,6 @@ export class User extends BaseClass {
 		email,
 		username,
 		password,
-		date_of_birth,
 		id,
 		req,
 	}: {
@@ -337,7 +337,7 @@ export class User extends BaseClass {
 		email?: string;
 		date_of_birth?: Date; // "2000-04-03"
 		id?: string;
-		req?: any;
+		req?: Request;
 	}) {
 		// trim special uf8 control characters -> Backspace, Newline, ...
 		username = trimSpecial(username);
@@ -348,7 +348,8 @@ export class User extends BaseClass {
 			throw FieldErrors({
 				username: {
 					code: "USERNAME_TOO_MANY_USERS",
-					message: req.t("auth:register.USERNAME_TOO_MANY_USERS"),
+					message:
+						req?.t("auth:register.USERNAME_TOO_MANY_USERS") || "",
 				},
 			});
 		}
@@ -357,7 +358,7 @@ export class User extends BaseClass {
 		// appearently discord doesn't save the date of birth and just calculate if nsfw is allowed
 		// if nsfw_allowed is null/undefined it'll require date_of_birth to set it to true/false
 		const language =
-			req.language === "en" ? "en-US" : req.language || "en-US";
+			req?.language === "en" ? "en-US" : req?.language || "en-US";
 
 		const settings = UserSettings.create({
 			locale: language,
@@ -386,7 +387,9 @@ export class User extends BaseClass {
 		setImmediate(async () => {
 			if (Config.get().guild.autoJoin.enabled) {
 				for (const guild of Config.get().guild.autoJoin.guilds || []) {
-					await Member.addToGuild(user.id, guild).catch((e) => {});
+					await Member.addToGuild(user.id, guild).catch((e) =>
+						console.error("[Autojoin]", e),
+					);
 				}
 			}
 		});
diff --git a/src/util/imports/OrmUtils.ts b/src/util/imports/OrmUtils.ts
index e6551471..039c81fe 100644
--- a/src/util/imports/OrmUtils.ts
+++ b/src/util/imports/OrmUtils.ts
@@ -1,25 +1,10 @@
-/*
-	Fosscord: A FOSS re-implementation and extension of the Discord.com backend.
-	Copyright (C) 2023 Fosscord and Fosscord Contributors
-	
-	This program is free software: you can redistribute it and/or modify
-	it under the terms of the GNU Affero General Public License as published
-	by the Free Software Foundation, either version 3 of the License, or
-	(at your option) any later version.
-	
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU Affero General Public License for more details.
-	
-	You should have received a copy of the GNU Affero General Public License
-	along with this program.  If not, see <https://www.gnu.org/licenses/>.
-*/
-
-//source: https://github.com/typeorm/typeorm/blob/master/src/util/OrmUtils.ts
+// source: https://github.com/typeorm/typeorm/blob/master/src/util/OrmUtils.ts
+// Copyright (c) 2015-2022 TypeORM. http://typeorm.github.io
+/* eslint-disable @typescript-eslint/no-explicit-any */
+// @fc-license-skip
 export class OrmUtils {
 	// Checks if it's an object made by Object.create(null), {} or new Object()
-	private static isPlainObject(item: any) {
+	private static isPlainObject(item: unknown) {
 		if (item === null || item === undefined) {
 			return false;
 		}
diff --git a/src/util/interfaces/Event.ts b/src/util/interfaces/Event.ts
index e902cdf3..c3bfbf9b 100644
--- a/src/util/interfaces/Event.ts
+++ b/src/util/interfaces/Event.ts
@@ -39,6 +39,7 @@ import {
 	Presence,
 	UserSettings,
 	IReadyGuildDTO,
+	ReadState,
 } from "@fosscord/util";
 
 export interface Event {
@@ -47,6 +48,7 @@ export interface Event {
 	channel_id?: string;
 	created_at?: Date;
 	event: EVENT;
+	// eslint-disable-next-line @typescript-eslint/no-explicit-any
 	data?: any;
 }
 
@@ -103,12 +105,12 @@ export interface ReadyEventData {
 		[number, [[number, [number, number]]]],
 		{ b: number; k: bigint[] }[],
 	][];
-	guild_join_requests?: any[]; // ? what is this? this is new
+	guild_join_requests?: unknown[]; // ? what is this? this is new
 	shard?: [number, number];
 	user_settings?: UserSettings;
 	relationships?: PublicRelationship[]; // TODO
 	read_state: {
-		entries: any[]; // TODO
+		entries: ReadState[]; // TODO
 		partial: boolean;
 		version: number;
 	};
@@ -124,7 +126,7 @@ export interface ReadyEventData {
 	merged_members?: PublicMember[][];
 	// probably all users who the user is in contact with
 	users?: PublicUser[];
-	sessions: any[];
+	sessions: unknown[];
 }
 
 export interface ReadyEvent extends Event {
@@ -178,7 +180,7 @@ export interface GuildCreateEvent extends Event {
 		joined_at: Date;
 		// TODO: add them to guild
 		guild_scheduled_events: never[];
-		guild_hashes: {};
+		guild_hashes: unknown;
 		presences: never[];
 		stage_instances: never[];
 		threads: never[];
@@ -408,7 +410,7 @@ export interface TypingStartEvent extends Event {
 
 export interface UserUpdateEvent extends Event {
 	event: "USER_UPDATE";
-	data: User;
+	data: Omit<User, "data">;
 }
 
 export interface UserDeleteEvent extends Event {
diff --git a/src/util/interfaces/Interaction.ts b/src/util/interfaces/Interaction.ts
index 8695fca9..4158eda1 100644
--- a/src/util/interfaces/Interaction.ts
+++ b/src/util/interfaces/Interaction.ts
@@ -21,7 +21,7 @@ import { AllowedMentions, Embed } from "../entities/Message";
 export interface Interaction {
 	id: string;
 	type: InteractionType;
-	data?: {};
+	data?: object; // TODO typing
 	guild_id: string;
 	channel_id: string;
 	member_id: string;
diff --git a/src/util/schemas/ChannelPermissionOverwriteSchema.ts b/src/util/schemas/ChannelPermissionOverwriteSchema.ts
index 97fe9dee..62d0ad14 100644
--- a/src/util/schemas/ChannelPermissionOverwriteSchema.ts
+++ b/src/util/schemas/ChannelPermissionOverwriteSchema.ts
@@ -18,5 +18,4 @@
 
 import { ChannelPermissionOverwrite } from "@fosscord/util";
 
-export interface ChannelPermissionOverwriteSchema
-	extends ChannelPermissionOverwrite {}
+export type ChannelPermissionOverwriteSchema = ChannelPermissionOverwrite;
diff --git a/src/util/schemas/IdentifySchema.ts b/src/util/schemas/IdentifySchema.ts
index 18ab2b49..9bb14ca3 100644
--- a/src/util/schemas/IdentifySchema.ts
+++ b/src/util/schemas/IdentifySchema.ts
@@ -18,6 +18,8 @@
 
 import { ActivitySchema } from "@fosscord/util";
 
+// TODO: Need a way to allow camalCase and pascal_case without just duplicating the schema
+
 export const IdentifySchema = {
 	token: String,
 	$intents: BigInt, // discord uses a Integer for bitfields we use bigints tho. | instanceOf will automatically convert the Number to a BigInt
@@ -98,7 +100,7 @@ export interface IdentifySchema {
 		referring_domain_current?: string;
 		release_channel?: "stable" | "dev" | "ptb" | "canary";
 		client_build_number?: number;
-		client_event_source?: any;
+		client_event_source?: string;
 		client_version?: string;
 		system_locale?: string;
 	};
@@ -111,23 +113,23 @@ export interface IdentifySchema {
 	guild_subscriptions?: boolean;
 	capabilities?: number;
 	client_state?: {
-		guild_hashes?: any;
+		guild_hashes?: unknown;
 		highest_last_message_id?: string | number;
 		read_state_version?: number;
 		user_guild_settings_version?: number;
 		user_settings_version?: number;
 		useruser_guild_settings_version?: number;
 		private_channels_version?: number;
-		guild_versions?: any;
+		guild_versions?: unknown;
 		api_code_version?: number;
 	};
 	clientState?: {
-		guildHashes?: any;
+		guildHashes?: unknown;
 		highestLastMessageId?: string | number;
 		readStateVersion?: number;
 		userGuildSettingsVersion?: number;
 		useruserGuildSettingsVersion?: number;
-		guildVersions?: any;
+		guildVersions?: unknown;
 		apiCodeVersion?: number;
 	};
 	v?: number;
diff --git a/src/util/schemas/LazyRequestSchema.ts b/src/util/schemas/LazyRequestSchema.ts
index 02fe0d8b..7cf3fd36 100644
--- a/src/util/schemas/LazyRequestSchema.ts
+++ b/src/util/schemas/LazyRequestSchema.ts
@@ -22,8 +22,8 @@ export interface LazyRequestSchema {
 	activities?: boolean;
 	threads?: boolean;
 	typing?: true;
-	members?: any[];
-	thread_member_lists?: any[];
+	members?: unknown[];
+	thread_member_lists?: unknown[];
 }
 
 export const LazyRequestSchema = {
@@ -32,6 +32,6 @@ export const LazyRequestSchema = {
 	$channels: Object,
 	$typing: Boolean,
 	$threads: Boolean,
-	$members: [] as any[],
-	$thread_member_lists: [] as any[],
+	$members: [] as unknown[],
+	$thread_member_lists: [] as unknown[],
 };
diff --git a/src/util/schemas/MessageCreateSchema.ts b/src/util/schemas/MessageCreateSchema.ts
index 1dd5d32c..4ee6e738 100644
--- a/src/util/schemas/MessageCreateSchema.ts
+++ b/src/util/schemas/MessageCreateSchema.ts
@@ -18,6 +18,11 @@
 
 import { Embed } from "@fosscord/util";
 
+type Attachment = {
+	id: string;
+	filename: string;
+};
+
 export interface MessageCreateSchema {
 	type?: number;
 	content?: string;
@@ -41,11 +46,11 @@ export interface MessageCreateSchema {
 		fail_if_not_exists?: boolean;
 	};
 	payload_json?: string;
-	file?: any;
+	file?: { filename: string };
 	/**
 	TODO: we should create an interface for attachments
 	TODO: OpenWAAO<-->attachment-style metadata conversion
 	**/
-	attachments?: any[];
+	attachments?: Attachment[];
 	sticker_ids?: string[];
 }
diff --git a/src/util/schemas/UserSettingsSchema.ts b/src/util/schemas/UserSettingsSchema.ts
index e25588c4..5a590b02 100644
--- a/src/util/schemas/UserSettingsSchema.ts
+++ b/src/util/schemas/UserSettingsSchema.ts
@@ -18,4 +18,4 @@
 
 import { UserSettings } from "@fosscord/util";
 
-export interface UserSettingsSchema extends Partial<UserSettings> {}
+export type UserSettingsSchema = Partial<UserSettings>;
diff --git a/src/util/schemas/Validator.ts b/src/util/schemas/Validator.ts
index 26a88ef9..3190dd05 100644
--- a/src/util/schemas/Validator.ts
+++ b/src/util/schemas/Validator.ts
@@ -45,7 +45,7 @@ export const ajv = new Ajv({
 
 addFormats(ajv);
 
-export function validateSchema<G>(schema: string, data: G): G {
+export function validateSchema<G extends object>(schema: string, data: G): G {
 	const valid = ajv.validate(schema, normalizeBody(data));
 	if (!valid) throw ajv.errors;
 	return data;
@@ -55,13 +55,13 @@ export function validateSchema<G>(schema: string, data: G): G {
 // this removes null values as ajv doesn't treat them as undefined
 // normalizeBody allows to handle circular structures without issues
 // taken from https://github.com/serverless/serverless/blob/master/lib/classes/ConfigSchemaHandler/index.js#L30 (MIT license)
-export const normalizeBody = (body: any = {}) => {
+export const normalizeBody = (body: object = {}) => {
 	const normalizedObjectsSet = new WeakSet();
-	const normalizeObject = (object: any) => {
+	const normalizeObject = (object: object) => {
 		if (normalizedObjectsSet.has(object)) return;
 		normalizedObjectsSet.add(object);
 		if (Array.isArray(object)) {
-			for (const [index, value] of object.entries()) {
+			for (const [, value] of object.entries()) {
 				if (typeof value === "object") normalizeObject(value);
 			}
 		} else {
@@ -75,6 +75,8 @@ export const normalizeBody = (body: any = {}) => {
 						key === "discovery_splash"
 					)
 						continue;
+					// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+					//@ts-ignore
 					delete object[key];
 				} else if (typeof value === "object") {
 					normalizeObject(value);
diff --git a/src/util/util/Array.ts b/src/util/util/Array.ts
index 1935fa7a..dbc75b85 100644
--- a/src/util/util/Array.ts
+++ b/src/util/util/Array.ts
@@ -16,6 +16,8 @@
 	along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-export function containsAll(arr: any[], target: any[]) {
+// TODO: remove this function.
+
+export function containsAll(arr: unknown[], target: unknown[]) {
 	return target.every((v) => arr.includes(v));
 }
diff --git a/src/util/util/AutoUpdate.ts b/src/util/util/AutoUpdate.ts
index 08836ea2..a4a97f3f 100644
--- a/src/util/util/AutoUpdate.ts
+++ b/src/util/util/AutoUpdate.ts
@@ -36,7 +36,7 @@ export function enableAutoUpdate(opts: {
 	downloadType?: "zip";
 }) {
 	if (!opts.checkInterval) return;
-	var interval = 1000 * 60 * 60 * 24;
+	const interval = 1000 * 60 * 60 * 24;
 	if (typeof opts.checkInterval === "number")
 		opts.checkInterval = 1000 * interval;
 
@@ -70,6 +70,7 @@ export function enableAutoUpdate(opts: {
 	});
 }
 
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
 async function download(url: string, dir: string) {
 	try {
 		// TODO: use file stream instead of buffer (to prevent crash because of high memory usage for big files)
@@ -99,7 +100,7 @@ async function getLatestVersion(url: string) {
 	try {
 		const agent = new ProxyAgent();
 		const response = await fetch(url, { agent });
-		const content = (await response.json()) as any; // TODO: types
+		const content = await response.json();
 		return content.version;
 	} catch (error) {
 		throw new Error("[Auto update] check failed for " + url);
diff --git a/src/util/util/BitField.ts b/src/util/util/BitField.ts
index 62bc3c46..d8758327 100644
--- a/src/util/util/BitField.ts
+++ b/src/util/util/BitField.ts
@@ -6,7 +6,7 @@
 
 export type BitFieldResolvable =
 	| number
-	| BigInt
+	| bigint
 	| BitField
 	| string
 	| BitFieldResolvable[];
@@ -135,6 +135,7 @@ export class BitField {
 	 * @returns {number}
 	 */
 	static resolve(bit: BitFieldResolvable = BigInt(0)): bigint {
+		// eslint-disable-next-line @typescript-eslint/ban-ts-comment
 		// @ts-ignore
 		const FLAGS = this.FLAGS || this.constructor?.FLAGS;
 
@@ -152,6 +153,7 @@ export class BitField {
 		if (bit instanceof BitField) return bit.bitfield;
 
 		if (Array.isArray(bit)) {
+			// eslint-disable-next-line @typescript-eslint/ban-ts-comment
 			// @ts-ignore
 			const resolve = this.constructor?.resolve || this.resolve;
 			return bit
diff --git a/src/util/util/Config.ts b/src/util/util/Config.ts
index 4b2dbb0d..b83f1d7b 100644
--- a/src/util/util/Config.ts
+++ b/src/util/util/Config.ts
@@ -24,8 +24,8 @@ import { ConfigValue } from "../config";
 // TODO: yaml instead of json
 const overridePath = process.env.CONFIG_PATH ?? "";
 
-var config: ConfigValue;
-var pairs: ConfigEntity[];
+let config: ConfigValue;
+let pairs: ConfigEntity[];
 
 // TODO: use events to inform about config updates
 // Config keys are separated with _
@@ -84,6 +84,8 @@ export const Config = {
 };
 
 function applyConfig(val: ConfigValue) {
+	// TODO: typings
+	// eslint-disable-next-line @typescript-eslint/no-explicit-any
 	async function apply(obj: any, key = ""): Promise<any> {
 		if (typeof obj === "object" && obj !== null)
 			return Promise.all(
@@ -107,7 +109,9 @@ function applyConfig(val: ConfigValue) {
 }
 
 function pairsToConfig(pairs: ConfigEntity[]) {
-	var value: any = {};
+	// TODO: typings
+	// eslint-disable-next-line @typescript-eslint/no-explicit-any
+	const value: any = {};
 
 	pairs.forEach((p) => {
 		const keys = p.key.split("_");
diff --git a/src/util/util/Constants.ts b/src/util/util/Constants.ts
index d65fda58..1afdce49 100644
--- a/src/util/util/Constants.ts
+++ b/src/util/util/Constants.ts
@@ -1125,7 +1125,7 @@ export const MembershipStates = ["INSERTED", "INVITED", "ACCEPTED"];
 export const WebhookTypes = ["Custom", "Incoming", "Channel Follower"];
 
 function keyMirror(arr: string[]) {
-	let tmp = Object.create(null);
+	const tmp = Object.create(null);
 	for (const value of arr) tmp[value] = value;
 	return tmp;
 }
diff --git a/src/util/util/Database.ts b/src/util/util/Database.ts
index 38011b9c..e1a4003f 100644
--- a/src/util/util/Database.ts
+++ b/src/util/util/Database.ts
@@ -25,14 +25,14 @@ import path from "path";
 // UUID extension option is only supported with postgres
 // We want to generate all id's with Snowflakes that's why we have our own BaseEntity class
 
-var dbConnection: DataSource | undefined;
+let dbConnection: DataSource | undefined;
 
 // For typeorm cli
 if (!process.env) {
 	config();
 }
 
-let dbConnectionString =
+const dbConnectionString =
 	process.env.DATABASE || path.join(process.cwd(), "database.db");
 
 const DatabaseType = dbConnectionString.includes("://")
@@ -41,6 +41,7 @@ const DatabaseType = dbConnectionString.includes("://")
 const isSqlite = DatabaseType.includes("sqlite");
 
 const DataSourceOptions = new DataSource({
+	// eslint-disable-next-line @typescript-eslint/ban-ts-comment
 	//@ts-ignore type 'string' is not 'mysql' | 'sqlite' | 'mariadb' | etc etc
 	type: DatabaseType,
 	charset: "utf8mb4",
diff --git a/src/util/util/Email.ts b/src/util/util/Email.ts
index f45728fc..48d8cae1 100644
--- a/src/util/util/Email.ts
+++ b/src/util/util/Email.ts
@@ -17,27 +17,29 @@
 */
 
 export const EMAIL_REGEX =
-	/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
+	/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
 
 export function adjustEmail(email?: string): string | undefined {
 	if (!email) return email;
 	// body parser already checked if it is a valid email
 	const parts = <RegExpMatchArray>email.match(EMAIL_REGEX);
-	// @ts-ignore
 	if (!parts || parts.length < 5) return undefined;
-	const domain = parts[5];
-	const user = parts[1];
 
-	// TODO: check accounts with uncommon email domains
-	if (domain === "gmail.com" || domain === "googlemail.com") {
-		// replace .dots and +alternatives -> Gmail Dot Trick https://support.google.com/mail/answer/7436150 and https://generator.email/blog/gmail-generator
-		let v = user.replace(/[.]|(\+.*)/g, "") + "@gmail.com";
-	}
+	return email;
+	// // TODO: The below code doesn't actually do anything.
+	// const domain = parts[5];
+	// const user = parts[1];
 
-	if (domain === "google.com") {
-		// replace .dots and +alternatives -> Google Staff GMail Dot Trick
-		let v = user.replace(/[.]|(\+.*)/g, "") + "@google.com";
-	}
+	// // TODO: check accounts with uncommon email domains
+	// if (domain === "gmail.com" || domain === "googlemail.com") {
+	// 	// replace .dots and +alternatives -> Gmail Dot Trick https://support.google.com/mail/answer/7436150 and https://generator.email/blog/gmail-generator
+	// 	const v = user.replace(/[.]|(\+.*)/g, "") + "@gmail.com";
+	// }
 
-	return email;
+	// if (domain === "google.com") {
+	// 	// replace .dots and +alternatives -> Google Staff GMail Dot Trick
+	// 	const v = user.replace(/[.]|(\+.*)/g, "") + "@google.com";
+	// }
+
+	// return email;
 }
diff --git a/src/util/util/Event.ts b/src/util/util/Event.ts
index 5e01e644..79be1a10 100644
--- a/src/util/util/Event.ts
+++ b/src/util/util/Event.ts
@@ -55,6 +55,7 @@ export async function emitEvent(payload: Omit<Event, "created_at">) {
 export async function initEvent() {
 	await RabbitMQ.init(); // does nothing if rabbitmq is not setup
 	if (RabbitMQ.connection) {
+		// empty on purpose?
 	} else {
 		// use event emitter
 		// use process messages
@@ -62,9 +63,9 @@ export async function initEvent() {
 }
 
 export interface EventOpts extends Event {
-	acknowledge?: Function;
+	acknowledge?: () => unknown;
 	channel?: Channel;
-	cancel: Function;
+	cancel: (id?: string) => unknown;
 }
 
 export interface ListenEventOpts {
@@ -80,17 +81,18 @@ export interface ProcessEvent {
 
 export async function listenEvent(
 	event: string,
-	callback: (event: EventOpts) => any,
+	callback: (event: EventOpts) => unknown,
 	opts?: ListenEventOpts,
 ) {
 	if (RabbitMQ.connection) {
-		return await rabbitListen(
-			// @ts-ignore
-			opts?.channel || RabbitMQ.channel,
-			event,
-			callback,
-			{ acknowledge: opts?.acknowledge },
-		);
+		const channel = opts?.channel || RabbitMQ.channel;
+		if (!channel)
+			throw new Error(
+				"[Events] An event was sent without an associated channel",
+			);
+		return await rabbitListen(channel, event, callback, {
+			acknowledge: opts?.acknowledge,
+		});
 	} else if (process.env.EVENT_TRANSMISSION === "process") {
 		const cancel = async () => {
 			process.removeListener("message", listener);
@@ -103,13 +105,13 @@ export async function listenEvent(
 				callback({ ...msg.event, cancel });
 		};
 
-		//@ts-ignore apparently theres no function addListener with this signature
-		process.addListener("message", listener);
+		// TODO: assert the type is correct?
+		process.addListener("message", (msg) => listener(msg as ProcessEvent));
 		process.setMaxListeners(process.getMaxListeners() + 1);
 
 		return cancel;
 	} else {
-		const listener = (opts: any) => callback({ ...opts, cancel });
+		const listener = (opts: EventOpts) => callback({ ...opts, cancel });
 		const cancel = async () => {
 			events.removeListener(event, listener);
 			events.setMaxListeners(events.getMaxListeners() - 1);
@@ -124,7 +126,7 @@ export async function listenEvent(
 async function rabbitListen(
 	channel: Channel,
 	id: string,
-	callback: (event: EventOpts) => any,
+	callback: (event: EventOpts) => unknown,
 	opts?: { acknowledge?: boolean },
 ) {
 	await channel.assertExchange(id, "fanout", { durable: false });
diff --git a/src/util/util/FieldError.ts b/src/util/util/FieldError.ts
index 69df6f8e..eff793a8 100644
--- a/src/util/util/FieldError.ts
+++ b/src/util/util/FieldError.ts
@@ -42,7 +42,7 @@ export class FieldError extends Error {
 	constructor(
 		public code: string | number,
 		public message: string,
-		public errors?: any,
+		public errors?: object, // TODO: I don't like this typing.
 	) {
 		super(message);
 	}
diff --git a/src/util/util/Permissions.ts b/src/util/util/Permissions.ts
index 19614640..996c72ea 100644
--- a/src/util/util/Permissions.ts
+++ b/src/util/util/Permissions.ts
@@ -12,14 +12,7 @@ import {
 import { BitField } from "./BitField";
 import "missing-native-js-functions";
 import { BitFieldResolvable, BitFlag } from "./BitField";
-
-var HTTPError: any;
-
-try {
-	HTTPError = require("lambert-server").HTTPError;
-} catch (e) {
-	HTTPError = Error;
-}
+import { HTTPError } from "lambert-server";
 
 export type PermissionResolvable =
 	| bigint
@@ -31,7 +24,7 @@ export type PermissionResolvable =
 type PermissionString = keyof typeof Permissions.FLAGS;
 
 // BigInt doesn't have a bit limit (https://stackoverflow.com/questions/53335545/whats-the-biggest-bigint-value-in-js-as-per-spec)
-const CUSTOM_PERMISSION_OFFSET = BigInt(1) << BigInt(64); // 27 permission bits left for discord to add new ones
+// const CUSTOM_PERMISSION_OFFSET = BigInt(1) << BigInt(64); // 27 permission bits left for discord to add new ones
 
 export class Permissions extends BitField {
 	cache: PermissionCache = {};
@@ -114,7 +107,6 @@ export class Permissions extends BitField {
 	 */
 	hasThrow(permission: PermissionResolvable) {
 		if (this.has(permission) && this.has("VIEW_CHANNEL")) return true;
-		// @ts-ignore
 		throw new HTTPError(
 			`You are missing the following permissions ${permission}`,
 			403,
@@ -177,11 +169,11 @@ export class Permissions extends BitField {
 	}) {
 		if (user.id === "0") return new Permissions("ADMINISTRATOR"); // system user id
 
-		let roles = guild.roles.filter((x) => user.roles.includes(x.id));
+		const roles = guild.roles.filter((x) => user.roles.includes(x.id));
 		let permission = Permissions.rolePermission(roles);
 
 		if (channel?.overwrites) {
-			let overwrites = channel.overwrites.filter((x) => {
+			const overwrites = channel.overwrites.filter((x) => {
 				if (x.type === 0 && user.roles.includes(x.id)) return true;
 				if (x.type === 1 && x.id == user.id) return true;
 				return false;
@@ -244,9 +236,9 @@ export async function getPermission(
 	} = {},
 ) {
 	if (!user_id) throw new HTTPError("User not found");
-	var channel: Channel | undefined;
-	var member: Member | undefined;
-	var guild: Guild | undefined;
+	let channel: Channel | undefined;
+	let member: Member | undefined;
+	let guild: Guild | undefined;
 
 	if (channel_id) {
 		channel = await Channel.findOneOrFail({
@@ -258,7 +250,6 @@ export async function getPermission(
 				"permission_overwrites",
 				"owner_id",
 				"guild_id",
-				// @ts-ignore
 				...(opts.channel_select || []),
 			],
 		});
@@ -268,12 +259,7 @@ export async function getPermission(
 	if (guild_id) {
 		guild = await Guild.findOneOrFail({
 			where: { id: guild_id },
-			select: [
-				"id",
-				"owner_id",
-				// @ts-ignore
-				...(opts.guild_select || []),
-			],
+			select: ["id", "owner_id", ...(opts.guild_select || [])],
 			relations: opts.guild_relations,
 		});
 		if (guild.owner_id === user_id)
@@ -285,17 +271,16 @@ export async function getPermission(
 			// select: [
 			// "id",		// TODO: Bug in typeorm? adding these selects breaks the query.
 			// "roles",
-			// @ts-ignore
 			// ...(opts.member_select || []),
 			// ],
 		});
 	}
 
-	let recipient_ids: any = channel?.recipients?.map((x) => x.user_id);
-	if (!recipient_ids?.length) recipient_ids = null;
+	let recipient_ids = channel?.recipients?.map((x) => x.user_id);
+	if (!recipient_ids?.length) recipient_ids = undefined;
 
 	// TODO: remove guild.roles and convert recipient_ids to recipients
-	var permission = Permissions.finalPermission({
+	const permission = Permissions.finalPermission({
 		user: {
 			id: user_id,
 			roles: member?.roles.map((x) => x.id) || [],
diff --git a/src/util/util/Rights.ts b/src/util/util/Rights.ts
index 4d437956..b48477ed 100644
--- a/src/util/util/Rights.ts
+++ b/src/util/util/Rights.ts
@@ -20,14 +20,7 @@ import { BitField } from "./BitField";
 import "missing-native-js-functions";
 import { BitFieldResolvable, BitFlag } from "./BitField";
 import { User } from "../entities";
-
-var HTTPError: any;
-
-try {
-	HTTPError = require("lambert-server").HTTPError;
-} catch (e) {
-	HTTPError = Error;
-}
+import { HTTPError } from "lambert-server";
 
 export type RightResolvable =
 	| bigint
@@ -118,7 +111,6 @@ export class Rights extends BitField {
 
 	hasThrow(permission: RightResolvable) {
 		if (this.has(permission)) return true;
-		// @ts-ignore
 		throw new HTTPError(
 			`You are missing the following rights ${permission}`,
 			403,
@@ -137,6 +129,6 @@ export async function getRights(
 		in_behalf?: (keyof User)[];
 	} = {} **/
 ) {
-	let user = await User.findOneOrFail({ where: { id: user_id } });
+	const user = await User.findOneOrFail({ where: { id: user_id } });
 	return new Rights(user.rights);
 }
diff --git a/src/util/util/Sentry.ts b/src/util/util/Sentry.ts
index b0eee169..e1248353 100644
--- a/src/util/util/Sentry.ts
+++ b/src/util/util/Sentry.ts
@@ -34,7 +34,7 @@ export const Sentry = {
 			Config.get().sentry;
 		if (!enabled) return;
 
-		if (!!SentryNode.getCurrentHub().getClient()) return; // we've already initialised sentry
+		if (SentryNode.getCurrentHub().getClient()) return; // we've already initialised sentry
 
 		console.log("[Sentry] Enabling sentry...");
 
@@ -60,7 +60,7 @@ export const Sentry = {
 			environment,
 		});
 
-		SentryNode.addGlobalEventProcessor((event, hint) => {
+		SentryNode.addGlobalEventProcessor((event) => {
 			if (event.transaction) {
 				// Rewrite things that look like IDs to `:id` for sentry
 				event.transaction = event.transaction
@@ -112,6 +112,8 @@ export const Sentry = {
 		errorHandlersUsed = true;
 
 		app.use(SentryNode.Handlers.errorHandler());
+		// The typings for this are broken?
+		// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
 		app.use(function onError(err: any, req: any, res: any, next: any) {
 			res.statusCode = 500;
 			res.end(res.sentry + "\n");
diff --git a/src/util/util/Snowflake.ts b/src/util/util/Snowflake.ts
index 65546958..93898fbb 100644
--- a/src/util/util/Snowflake.ts
+++ b/src/util/util/Snowflake.ts
@@ -1,3 +1,4 @@
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
 // @ts-nocheck
 import * as cluster from "cluster";
 
@@ -87,10 +88,10 @@ export class Snowflake {
 
 	static generateWorkerProcess() {
 		// worker process - returns a number
-		var time = BigInt(Date.now() - Snowflake.EPOCH) << BigInt(22);
-		var worker = Snowflake.workerId << 17n;
-		var process = Snowflake.processId << 12n;
-		var increment = Snowflake.INCREMENT++;
+		const time = BigInt(Date.now() - Snowflake.EPOCH) << BigInt(22);
+		const worker = Snowflake.workerId << 17n;
+		const process = Snowflake.processId << 12n;
+		const increment = Snowflake.INCREMENT++;
 		return BigInt(time | worker | process | increment);
 	}
 
diff --git a/src/util/util/String.ts b/src/util/util/String.ts
index 7addd49a..74fd0295 100644
--- a/src/util/util/String.ts
+++ b/src/util/util/String.ts
@@ -19,7 +19,6 @@
 import { SPECIAL_CHAR } from "./Regex";
 
 export function trimSpecial(str?: string): string {
-	// @ts-ignore
-	if (!str) return;
+	if (!str) return "";
 	return str.replace(SPECIAL_CHAR, "").trim();
 }
diff --git a/src/util/util/Token.ts b/src/util/util/Token.ts
index c00142bb..ca81eaaa 100644
--- a/src/util/util/Token.ts
+++ b/src/util/util/Token.ts
@@ -22,7 +22,15 @@ import { User } from "../entities";
 
 export const JWTOptions: VerifyOptions = { algorithms: ["HS256"] };
 
-export function checkToken(token: string, jwtSecret: string): Promise<any> {
+export type UserTokenData = {
+	user: User;
+	decoded: { id: string; iat: number };
+};
+
+export function checkToken(
+	token: string,
+	jwtSecret: string,
+): Promise<UserTokenData> {
 	return new Promise((res, rej) => {
 		token = token.replace("Bot ", "");
 		token = token.replace("Bearer ", "");
@@ -31,24 +39,35 @@ export function checkToken(token: string, jwtSecret: string): Promise<any> {
 		as we don't really have separate pathways for bots 
 		**/
 
-		jwt.verify(token, jwtSecret, JWTOptions, async (err, decoded: any) => {
+		jwt.verify(token, jwtSecret, JWTOptions, async (err, decoded) => {
 			if (err || !decoded) return rej("Invalid Token");
+			if (
+				typeof decoded == "string" ||
+				!("id" in decoded) ||
+				!decoded.iat
+			)
+				return rej("Invalid Token"); // will never happen, just for typings.
 
 			const user = await User.findOne({
 				where: { id: decoded.id },
 				select: ["data", "bot", "disabled", "deleted", "rights"],
 			});
+
 			if (!user) return rej("Invalid Token");
+
 			// we need to round it to seconds as it saved as seconds in jwt iat and valid_tokens_since is stored in milliseconds
 			if (
 				decoded.iat * 1000 <
 				new Date(user.data.valid_tokens_since).setSeconds(0, 0)
 			)
 				return rej("Invalid Token");
+
 			if (user.disabled) return rej("User disabled");
 			if (user.deleted) return rej("User not found");
 
-			return res({ decoded, user });
+			// Using as here because we assert `id` and `iat` are in decoded.
+			// TS just doesn't want to assume its there, though.
+			return res({ decoded, user } as UserTokenData);
 		});
 	});
 }
diff --git a/src/util/util/TraverseDirectory.ts b/src/util/util/TraverseDirectory.ts
index 0cc48d4a..223e3ee0 100644
--- a/src/util/util/TraverseDirectory.ts
+++ b/src/util/util/TraverseDirectory.ts
@@ -22,7 +22,7 @@ import { Server, traverseDirectory } from "lambert-server";
 const extension =
 	Symbol.for("ts-node.register.instance") in process ? "ts" : "js";
 
-const DEFAULT_FILTER = new RegExp("^([^.].*)(?<!\.d).(" + extension + ")$");
+const DEFAULT_FILTER = new RegExp("^([^.].*)(?<!\\.d).(" + extension + ")$");
 
 export function registerRoutes(server: Server, root: string) {
 	return traverseDirectory(
diff --git a/src/util/util/cdn.ts b/src/util/util/cdn.ts
index 6d2fd0f1..7f447c53 100644
--- a/src/util/util/cdn.ts
+++ b/src/util/util/cdn.ts
@@ -24,7 +24,8 @@ import { Config } from "./Config";
 
 export async function uploadFile(
 	path: string,
-	file?: Express.Multer.File,
+	// These are the only props we use, don't need to enforce the full type.
+	file?: Pick<Express.Multer.File, "mimetype" | "originalname" | "buffer">,
 ): Promise<Attachment> {
 	if (!file?.buffer) throw new HTTPError("Missing file in body");
 
@@ -60,7 +61,6 @@ export async function handleFile(
 		const mimetype = body.split(":")[1].split(";")[0];
 		const buffer = Buffer.from(body.split(",")[1], "base64");
 
-		// @ts-ignore
 		const { id } = await uploadFile(path, {
 			buffer,
 			mimetype,