summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/config.yml18
-rw-r--r--.github/relase_body_template.md12
-rw-r--r--.prettierignore2
-rw-r--r--.prettierrc.json11
-rw-r--r--.vscode/launch.json12
-rw-r--r--package-lock.json22
-rw-r--r--package.json12
-rw-r--r--scripts/benchmark/connections.js2
-rw-r--r--scripts/client.js50
-rw-r--r--scripts/rights.js4
-rw-r--r--scripts/schema.js14
-rw-r--r--scripts/stresstest/src/login/index.js4
-rw-r--r--scripts/stresstest/src/message/send.js19
-rw-r--r--scripts/stresstest/src/register/index.js10
-rw-r--r--src-slowcord/README.md2
-rw-r--r--src-slowcord/bot/.vscode/launch.json7
-rw-r--r--src-slowcord/bot/.vscode/tasks.json2
-rw-r--r--src-slowcord/bot/src/Bot.ts16
-rw-r--r--src-slowcord/bot/src/commands/index.ts13
-rw-r--r--src-slowcord/bot/src/commands/instance.ts50
-rw-r--r--src-slowcord/bot/src/index.ts4
-rw-r--r--src-slowcord/bot/tsconfig.json184
-rw-r--r--src-slowcord/login/public/css/index.css9
-rw-r--r--src-slowcord/login/public/js/handler.js13
-rw-r--r--src-slowcord/login/public/login.html212
-rw-r--r--src-slowcord/login/public/register.html152
-rw-r--r--src-slowcord/login/src/index.ts76
-rw-r--r--src-slowcord/login/tsconfig.json40
-rw-r--r--src-slowcord/rules.md16
-rw-r--r--src-slowcord/status/src/gateway.ts51
-rw-r--r--src-slowcord/status/src/index.ts140
-rw-r--r--src-slowcord/status/tsconfig.json38
-rw-r--r--src/api/Server.ts52
-rw-r--r--src/api/index.ts2
-rw-r--r--src/api/middlewares/Authentication.ts18
-rw-r--r--src/api/middlewares/BodyParser.ts3
-rw-r--r--src/api/middlewares/CORS.ts12
-rw-r--r--src/api/middlewares/ErrorHandler.ts25
-rw-r--r--src/api/middlewares/RateLimit.ts70
-rw-r--r--src/api/middlewares/Translation.ts14
-rw-r--r--src/api/routes/-/monitorz.ts24
-rw-r--r--src/api/routes/auth/location-metadata.ts14
-rw-r--r--src/api/routes/auth/login.ts175
-rw-r--r--src/api/routes/auth/logout.ts5
-rw-r--r--src/api/routes/auth/mfa/totp.ts73
-rw-r--r--src/api/routes/auth/register.ts303
-rw-r--r--src/api/routes/auth/verify/view-backup-codes-challenge.ts34
-rw-r--r--src/api/routes/channels/#channel_id/index.ts117
-rw-r--r--src/api/routes/channels/#channel_id/invites.ts65
-rw-r--r--src/api/routes/channels/#channel_id/messages/#message_id/ack.ts62
-rw-r--r--src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts52
-rw-r--r--src/api/routes/channels/#channel_id/messages/#message_id/index.ts164
-rw-r--r--src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts327
-rw-r--r--src/api/routes/channels/#channel_id/messages/bulk-delete.ts85
-rw-r--r--src/api/routes/channels/#channel_id/messages/index.ts138
-rw-r--r--src/api/routes/channels/#channel_id/permissions.ts79
-rw-r--r--src/api/routes/channels/#channel_id/pins.ts163
-rw-r--r--src/api/routes/channels/#channel_id/purge.ts105
-rw-r--r--src/api/routes/channels/#channel_id/recipients.ts42
-rw-r--r--src/api/routes/channels/#channel_id/typing.ts54
-rw-r--r--src/api/routes/channels/#channel_id/webhooks.ts41
-rw-r--r--src/api/routes/discoverable-guilds.ts26
-rw-r--r--src/api/routes/discovery.ts4
-rw-r--r--src/api/routes/downloads.ts7
-rw-r--r--src/api/routes/experiments.ts2
-rw-r--r--src/api/routes/gateway/bot.ts10
-rw-r--r--src/api/routes/gateway/index.ts10
-rw-r--r--src/api/routes/gifs/search.ts19
-rw-r--r--src/api/routes/gifs/trending-gifs.ts19
-rw-r--r--src/api/routes/gifs/trending.ts46
-rw-r--r--src/api/routes/guild-recommendations.ts15
-rw-r--r--src/api/routes/guilds/#guild_id/audit-logs.ts2
-rw-r--r--src/api/routes/guilds/#guild_id/bans.ts304
-rw-r--r--src/api/routes/guilds/#guild_id/channels.ts101
-rw-r--r--src/api/routes/guilds/#guild_id/delete.ts26
-rw-r--r--src/api/routes/guilds/#guild_id/discovery-requirements.ts46
-rw-r--r--src/api/routes/guilds/#guild_id/emojis.ts157
-rw-r--r--src/api/routes/guilds/#guild_id/index.ts106
-rw-r--r--src/api/routes/guilds/#guild_id/invites.ts17
-rw-r--r--src/api/routes/guilds/#guild_id/member-verification.ts4
-rw-r--r--src/api/routes/guilds/#guild_id/members/#member_id/index.ts110
-rw-r--r--src/api/routes/guilds/#guild_id/members/#member_id/nick.ts28
-rw-r--r--src/api/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts28
-rw-r--r--src/api/routes/guilds/#guild_id/members/index.ts5
-rw-r--r--src/api/routes/guilds/#guild_id/messages/search.ts100
-rw-r--r--src/api/routes/guilds/#guild_id/prune.ts75
-rw-r--r--src/api/routes/guilds/#guild_id/regions.ts7
-rw-r--r--src/api/routes/guilds/#guild_id/roles/#role_id/index.ts107
-rw-r--r--src/api/routes/guilds/#guild_id/roles/index.ts139
-rw-r--r--src/api/routes/guilds/#guild_id/stickers.ts56
-rw-r--r--src/api/routes/guilds/#guild_id/templates.ts132
-rw-r--r--src/api/routes/guilds/#guild_id/vanity-url.ts120
-rw-r--r--src/api/routes/guilds/#guild_id/voice-states/#user_id/index.ts93
-rw-r--r--src/api/routes/guilds/#guild_id/welcome-screen.ts40
-rw-r--r--src/api/routes/guilds/#guild_id/widget.json.ts29
-rw-r--r--src/api/routes/guilds/#guild_id/widget.png.ts92
-rw-r--r--src/api/routes/guilds/#guild_id/widget.ts33
-rw-r--r--src/api/routes/guilds/index.ts61
-rw-r--r--src/api/routes/guilds/templates/index.ts155
-rw-r--r--src/api/routes/invites/index.ts64
-rw-r--r--src/api/routes/partners/#guild_id/requirements.ts47
-rw-r--r--src/api/routes/policies/instance/domains.ts19
-rw-r--r--src/api/routes/policies/instance/index.ts3
-rw-r--r--src/api/routes/policies/instance/limits.ts2
-rw-r--r--src/api/routes/scheduled-maintenances/upcoming_json.ts16
-rw-r--r--src/api/routes/stop.ts16
-rw-r--r--src/api/routes/store/published-listings/applications.ts20
-rw-r--r--src/api/routes/store/published-listings/applications/#id/subscription-plans.ts4
-rw-r--r--src/api/routes/store/published-listings/skus.ts20
-rw-r--r--src/api/routes/store/published-listings/skus/#sku_id/subscription-plans.ts40
-rw-r--r--src/api/routes/updates.ts6
-rw-r--r--src/api/routes/users/#id/profile.ts150
-rw-r--r--src/api/routes/users/#id/relationships.ts63
-rw-r--r--src/api/routes/users/@me/channels.ts33
-rw-r--r--src/api/routes/users/@me/delete.ts10
-rw-r--r--src/api/routes/users/@me/disable.ts10
-rw-r--r--src/api/routes/users/@me/email-settings.ts4
-rw-r--r--src/api/routes/users/@me/guilds.ts39
-rw-r--r--src/api/routes/users/@me/guilds/#guild_id/settings.ts42
-rw-r--r--src/api/routes/users/@me/index.ts187
-rw-r--r--src/api/routes/users/@me/mfa/codes-verification.ts72
-rw-r--r--src/api/routes/users/@me/mfa/codes.ts83
-rw-r--r--src/api/routes/users/@me/mfa/totp/disable.ts81
-rw-r--r--src/api/routes/users/@me/mfa/totp/enable.ts90
-rw-r--r--src/api/routes/users/@me/notes.ts34
-rw-r--r--src/api/routes/users/@me/relationships.ts175
-rw-r--r--src/api/routes/users/@me/settings.ts26
-rw-r--r--src/api/start.ts2
-rw-r--r--src/api/util/handlers/Message.ts186
-rw-r--r--src/api/util/handlers/Voice.ts11
-rw-r--r--src/api/util/handlers/route.ts35
-rw-r--r--src/api/util/index.ts2
-rw-r--r--src/api/util/utility/Base64.ts3
-rw-r--r--src/api/util/utility/RandomInviteID.ts13
-rw-r--r--src/api/util/utility/String.ts14
-rw-r--r--src/api/util/utility/captcha.ts19
-rw-r--r--src/api/util/utility/ipAddress.ts44
-rw-r--r--src/api/util/utility/passwordStrength.ts20
-rw-r--r--src/bundle/Server.ts25
-rw-r--r--src/bundle/index.ts2
-rw-r--r--src/bundle/start.ts22
-rw-r--r--src/bundle/stats.ts11
-rw-r--r--src/cdn/Server.ts8
-rw-r--r--src/cdn/routes/attachments.ts8
-rw-r--r--src/cdn/routes/avatars.ts4
-rw-r--r--src/cdn/routes/external.ts11
-rw-r--r--src/cdn/routes/guilds.ts2
-rw-r--r--src/cdn/routes/role-icons.ts2
-rw-r--r--src/cdn/start.ts2
-rw-r--r--src/cdn/util/S3Storage.ts2
-rw-r--r--src/cdn/util/Storage.ts6
-rw-r--r--src/gateway/events/Connection.ts12
-rw-r--r--src/gateway/events/Message.ts8
-rw-r--r--src/gateway/listener/listener.ts14
-rw-r--r--src/gateway/opcodes/Identify.ts12
-rw-r--r--src/gateway/opcodes/LazyRequest.ts72
-rw-r--r--src/gateway/opcodes/PresenceUpdate.ts10
-rw-r--r--src/gateway/opcodes/VoiceStateUpdate.ts8
-rw-r--r--src/gateway/start.ts2
-rw-r--r--src/gateway/util/Send.ts4
-rw-r--r--src/util/dtos/DmChannelDTO.ts21
-rw-r--r--src/util/entities/Attachment.ts19
-rw-r--r--src/util/entities/AuditLog.ts16
-rw-r--r--src/util/entities/BackupCodes.ts4
-rw-r--r--src/util/entities/BaseClass.ts36
-rw-r--r--src/util/entities/Categories.ts24
-rw-r--r--src/util/entities/Channel.ts846
-rw-r--r--src/util/entities/ClientRelease.ts2
-rw-r--r--src/util/entities/Config.ts31
-rw-r--r--src/util/entities/ConnectedAccount.ts3
-rw-r--r--src/util/entities/Emoji.ts2
-rw-r--r--src/util/entities/Encryption.ts20
-rw-r--r--src/util/entities/Guild.ts42
-rw-r--r--src/util/entities/Invite.ts12
-rw-r--r--src/util/entities/Member.ts68
-rw-r--r--src/util/entities/Message.ts27
-rw-r--r--src/util/entities/Migration.ts11
-rw-r--r--src/util/entities/Note.ts2
-rw-r--r--src/util/entities/ReadState.ts13
-rw-r--r--src/util/entities/Relationship.ts9
-rw-r--r--src/util/entities/StickerPack.ts10
-rw-r--r--src/util/entities/Team.ts10
-rw-r--r--src/util/entities/TeamMember.ts10
-rw-r--r--src/util/entities/User.ts122
-rw-r--r--src/util/entities/index.ts2
-rw-r--r--src/util/imports/OrmUtils.ts22
-rw-r--r--src/util/imports/index.ts2
-rw-r--r--src/util/index.ts2
-rw-r--r--src/util/interfaces/Activity.ts3
-rw-r--r--src/util/interfaces/Event.ts2
-rw-r--r--src/util/migrations/1633864260873-EmojiRoles.ts8
-rw-r--r--src/util/migrations/1633864669243-EmojiUser.ts12
-rw-r--r--src/util/migrations/1633881705509-VanityInvite.ts14
-rw-r--r--src/util/migrations/1634308884591-Stickers.ts73
-rw-r--r--src/util/migrations/1634424361103-Presence.ts5
-rw-r--r--src/util/migrations/1634426540271-MigrationTimestamp.ts6
-rw-r--r--src/util/migrations/1660678870706-opencordFixes.ts37
-rw-r--r--src/util/migrations/1660689892073-mobileFixes2.ts25
-rw-r--r--src/util/schemas/ActivitySchema.ts5
-rw-r--r--src/util/schemas/BackupCodesChallengeSchema.ts2
-rw-r--r--src/util/schemas/BanCreateSchema.ts2
-rw-r--r--src/util/schemas/BanModeratorSchema.ts2
-rw-r--r--src/util/schemas/BanRegistrySchema.ts2
-rw-r--r--src/util/schemas/BulkDeleteSchema.ts2
-rw-r--r--src/util/schemas/ChannelModifySchema.ts2
-rw-r--r--src/util/schemas/CodesVerificationSchema.ts2
-rw-r--r--src/util/schemas/DmChannelCreateSchema.ts2
-rw-r--r--src/util/schemas/EmojiCreateSchema.ts2
-rw-r--r--src/util/schemas/EmojiModifySchema.ts2
-rw-r--r--src/util/schemas/GuildCreateSchema.ts2
-rw-r--r--src/util/schemas/GuildTemplateCreateSchema.ts2
-rw-r--r--src/util/schemas/GuildUpdateWelcomeScreenSchema.ts2
-rw-r--r--src/util/schemas/InviteCreateSchema.ts2
-rw-r--r--src/util/schemas/LoginSchema.ts2
-rw-r--r--src/util/schemas/MemberChangeSchema.ts2
-rw-r--r--src/util/schemas/MemberNickChangeSchema.ts2
-rw-r--r--src/util/schemas/MessageAcknowledgeSchema.ts2
-rw-r--r--src/util/schemas/MessageCreateSchema.ts2
-rw-r--r--src/util/schemas/MfaCodesSchema.ts2
-rw-r--r--src/util/schemas/ModifyGuildStickerSchema.ts2
-rw-r--r--src/util/schemas/PruneSchema.ts2
-rw-r--r--src/util/schemas/PurgeSchema.ts2
-rw-r--r--src/util/schemas/RegisterSchema.ts2
-rw-r--r--src/util/schemas/RelationshipPostSchema.ts2
-rw-r--r--src/util/schemas/RelationshipPutSchema.ts2
-rw-r--r--src/util/schemas/RoleModifySchema.ts2
-rw-r--r--src/util/schemas/SelectProtocolSchema.ts14
-rw-r--r--src/util/schemas/TemplateCreateSchema.ts2
-rw-r--r--src/util/schemas/TemplateModifySchema.ts2
-rw-r--r--src/util/schemas/TotpDisableSchema.ts2
-rw-r--r--src/util/schemas/TotpEnableSchema.ts2
-rw-r--r--src/util/schemas/TotpSchema.ts10
-rw-r--r--src/util/schemas/UserModifySchema.ts2
-rw-r--r--src/util/schemas/Validator.ts22
-rw-r--r--src/util/schemas/VanityUrlSchema.ts2
-rw-r--r--src/util/schemas/VoiceIdentifySchema.ts2
-rw-r--r--src/util/schemas/VoiceStateUpdateSchema.ts4
-rw-r--r--src/util/schemas/VoiceVideoSchema.ts4
-rw-r--r--src/util/schemas/WebhookCreateSchema.ts2
-rw-r--r--src/util/schemas/WidgetModifySchema.ts2
-rw-r--r--src/util/schemas/index.ts2
-rw-r--r--src/util/util/ApiError.ts19
-rw-r--r--src/util/util/AutoUpdate.ts17
-rw-r--r--src/util/util/BannedWords.ts10
-rw-r--r--src/util/util/BitField.ts23
-rw-r--r--src/util/util/Categories.ts2
-rw-r--r--src/util/util/Config.ts15
-rw-r--r--src/util/util/Constants.ts576
-rw-r--r--src/util/util/Database.ts15
-rw-r--r--src/util/util/Email.ts2
-rw-r--r--src/util/util/Event.ts48
-rw-r--r--src/util/util/FieldError.ts12
-rw-r--r--src/util/util/Intents.ts7
-rw-r--r--src/util/util/InvisibleCharacters.ts112
-rw-r--r--src/util/util/Permissions.ts72
-rw-r--r--src/util/util/RabbitMQ.ts6
-rw-r--r--src/util/util/Rights.ts40
-rw-r--r--src/util/util/Snowflake.ts13
-rw-r--r--src/util/util/Token.ts9
-rw-r--r--src/util/util/TraverseDirectory.ts7
-rw-r--r--src/util/util/cdn.ts48
-rw-r--r--src/util/util/index.ts2
-rw-r--r--src/webrtc/Server.ts12
-rw-r--r--src/webrtc/events/Close.ts2
-rw-r--r--src/webrtc/events/Connection.ts17
-rw-r--r--src/webrtc/events/Message.ts13
-rw-r--r--src/webrtc/index.ts2
-rw-r--r--src/webrtc/opcodes/BackendVersion.ts7
-rw-r--r--src/webrtc/opcodes/Heartbeat.ts10
-rw-r--r--src/webrtc/opcodes/Identify.ts35
-rw-r--r--src/webrtc/opcodes/SelectProtocol.ts27
-rw-r--r--src/webrtc/opcodes/Speaking.ts6
-rw-r--r--src/webrtc/opcodes/Video.ts39
-rw-r--r--src/webrtc/opcodes/index.ts4
-rw-r--r--src/webrtc/opcodes/sdp.json2
-rw-r--r--src/webrtc/start.ts4
-rw-r--r--src/webrtc/util/Constants.ts6
-rw-r--r--src/webrtc/util/MediaServer.ts14
-rw-r--r--src/webrtc/util/index.ts2
-rw-r--r--tsconfig.json207
280 files changed, 6940 insertions, 4048 deletions
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index a4ca0bb9..8ab6ab5a 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -1,11 +1,11 @@
 blank_issues_enabled: true
 contact_links:
-  - name: Fosscord Documentation
-    url: https://docs.fosscord.com/
-    about: Need documentation and examples for the Fosscord? Head over to Fosscord's official documentation.
-  - name: Discord's Developer Documentation
-    url: https://discord.com/developers/docs/intro
-    about: Need help with the Discord resources? Head here instead of asking on Fosscord!
-  - name: Fosscord' Official Discord server
-    url: https://discord.com/invite/Ms5Ev7S6bF
-    about: Need help with the server? Talk with us in our official server.
+    - name: Fosscord Documentation
+      url: https://docs.fosscord.com/
+      about: Need documentation and examples for the Fosscord? Head over to Fosscord's official documentation.
+    - name: Discord's Developer Documentation
+      url: https://discord.com/developers/docs/intro
+      about: Need help with the Discord resources? Head here instead of asking on Fosscord!
+    - name: Fosscord' Official Discord server
+      url: https://discord.com/invite/Ms5Ev7S6bF
+      about: Need help with the server? Talk with us in our official server.
diff --git a/.github/relase_body_template.md b/.github/relase_body_template.md
index 994e83d3..c410b0c2 100644
--- a/.github/relase_body_template.md
+++ b/.github/relase_body_template.md
@@ -1,13 +1,17 @@
 ## Notes
 
 ## Additions
-- 
+
+-
 
 ## Fixes
+
 -
+
 ## Download
-- [Windows]()
-- [MacOS]()
-- [Linux]()
+
+-   [Windows]()
+-   [MacOS]()
+-   [Linux]()
 
 After (extracting) and starting the server executable you can access your own Fosscord server on http://localhost:3001/
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 00000000..49bc63ad
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,2 @@
+assets
+dist
\ No newline at end of file
diff --git a/.prettierrc.json b/.prettierrc.json
new file mode 100644
index 00000000..7f0d7f20
--- /dev/null
+++ b/.prettierrc.json
@@ -0,0 +1,11 @@
+{
+	"trailingComma": "all",
+	"tabWidth": 4,
+	"semi": true,
+	"arrowParens": "always",
+	"bracketSameLine": false,
+	"bracketSpacing": true,
+	"quoteProps": "as-needed",
+	"useTabs": true,
+	"singleQuote": false
+}
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 86eb202e..09a69132 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -8,21 +8,17 @@
 			"name": "Launch current file",
 			"program": "${relativeFile}",
 			"request": "launch",
-			"skipFiles": [
-				"<node_internals>/**"
-			],
+			"skipFiles": ["<node_internals>/**"],
 			"type": "node"
 		},
 		{
 			"type": "node",
 			"request": "launch",
 			"name": "Bundle",
-			"skipFiles": [
-				"<node_internals>/**"
-			],
+			"skipFiles": ["<node_internals>/**"],
 			"program": "${workspaceFolder}/src/bundle/start.ts",
-			"outFiles": [ "${workspaceFolder}/dist/**/*.js" ],
+			"outFiles": ["${workspaceFolder}/dist/**/*.js"],
 			"preLaunchTask": "tsc: build - tsconfig.json"
 		}
 	]
-}
\ No newline at end of file
+}
diff --git a/package-lock.json b/package-lock.json
index fd43bef5..4b19a8bf 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -60,6 +60,7 @@
 				"@types/sharp": "^0.31.0",
 				"@types/ws": "^8.5.3",
 				"express": "^4.18.1",
+				"prettier": "^2.7.1",
 				"typescript": "^4.8.3"
 			},
 			"optionalDependencies": {
@@ -4715,6 +4716,21 @@
 				"node": ">= 0.8.0"
 			}
 		},
+		"node_modules/prettier": {
+			"version": "2.7.1",
+			"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
+			"integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
+			"dev": true,
+			"bin": {
+				"prettier": "bin-prettier.js"
+			},
+			"engines": {
+				"node": ">=10.13.0"
+			},
+			"funding": {
+				"url": "https://github.com/prettier/prettier?sponsor=1"
+			}
+		},
 		"node_modules/process-nextick-args": {
 			"version": "2.0.1",
 			"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -9846,6 +9862,12 @@
 			"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
 			"integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w=="
 		},
+		"prettier": {
+			"version": "2.7.1",
+			"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
+			"integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
+			"dev": true
+		},
 		"process-nextick-args": {
 			"version": "2.0.1",
 			"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
diff --git a/package.json b/package.json
index 8a737424..9c86f918 100644
--- a/package.json
+++ b/package.json
@@ -40,11 +40,16 @@
 		"@types/sharp": "^0.31.0",
 		"@types/ws": "^8.5.3",
 		"express": "^4.18.1",
+		"prettier": "^2.7.1",
 		"typescript": "^4.8.3"
 	},
 	"dependencies": {
+		"@aws-sdk/client-s3": "^3.178.0",
+		"@sentry/node": "^7.13.0",
+		"@sentry/tracing": "^7.13.0",
 		"ajv": "^8.6.2",
 		"ajv-formats": "^2.1.1",
+		"amqplib": "^0.10.3",
 		"bcrypt": "^5.0.1",
 		"cheerio": "^1.0.0-rc.12",
 		"cookie-parser": "^1.4.6",
@@ -72,12 +77,7 @@
 		"sqlite3": "^5.1.1",
 		"typeorm": "^0.3.10",
 		"typescript-json-schema": "^0.50.1",
-		"ws": "^8.9.0",
-
-		"@aws-sdk/client-s3": "^3.178.0",
-		"@sentry/node": "^7.13.0",
-		"@sentry/tracing": "^7.13.0",
-		"amqplib": "^0.10.3"
+		"ws": "^8.9.0"
 	},
 	"optionalDependencies": {
 		"@yukikaze-bot/erlpack": "^1.0.1"
diff --git a/scripts/benchmark/connections.js b/scripts/benchmark/connections.js
index 515f76e9..1a30d49f 100644
--- a/scripts/benchmark/connections.js
+++ b/scripts/benchmark/connections.js
@@ -48,7 +48,7 @@ function connect() {
 							token,
 							properties: {},
 						},
-					})
+					}),
 				);
 
 				break;
diff --git a/scripts/client.js b/scripts/client.js
index e73bc7ee..ed1a94b9 100644
--- a/scripts/client.js
+++ b/scripts/client.js
@@ -8,21 +8,21 @@ const BASE_URL = "https://discord.com";
 
 // Manual for now
 const INDEX_SCRIPTS = [
-	"83ace7450e110d16319e",	// 50
-	"e02290aaa8dac5d195c2",	// 1
-	"4f3b3c576b879a5f75d1",	// 0?
-	"699456246fdfe7589855",	// ~4500.
+	"83ace7450e110d16319e", // 50
+	"e02290aaa8dac5d195c2", // 1
+	"4f3b3c576b879a5f75d1", // 0?
+	"699456246fdfe7589855", // ~4500.
 ];
 
 const doPatch = (content) => {
 	//remove nitro references
 	content = content.replace(/Discord Nitro/g, "Fosscord Premium");
-	content = content.replace(/"Nitro"/g, "\"Premium\"");
+	content = content.replace(/"Nitro"/g, '"Premium"');
 	content = content.replace(/Nitro /g, "Premium ");
 	content = content.replace(/ Nitro/g, " Premium");
 	content = content.replace(/\[Nitro\]/g, "[Premium]");
 	content = content.replace(/\*Nitro\*/g, "*Premium*");
-	content = content.replace(/\"Nitro \. /g, "\"Premium. ");
+	content = content.replace(/\"Nitro \. /g, '"Premium. ');
 
 	//remove discord references
 	content = content.replace(/ Discord /g, " Fosscord ");
@@ -35,11 +35,11 @@ const doPatch = (content) => {
 	content = content.replace(/\*Discord\*/g, "*Fosscord*");
 
 	//server -> guild
-	content = content.replace(/"Server"/g, "\"Guild\"");
-	content.replaceAll("server.\"", "guild.\"");
+	content = content.replace(/"Server"/g, '"Guild"');
+	content.replaceAll('server."', 'guild."');
 	content.replaceAll(" server ", " guild ");
 	content.replaceAll(" Server ", " Guild ");
-	content.replaceAll("\"Server", "\"Guild");
+	content.replaceAll('"Server', '"Guild');
 
 	// //change some vars
 	// content = content.replace('dsn: "https://fa97a90475514c03a42f80cd36d147c4@sentry.io/140984"', "dsn: (/true/.test(localStorage.sentryOptIn)?'https://6bad92b0175d41a18a037a73d0cff282@sentry.thearcanebrony.net/12':'')");
@@ -52,8 +52,14 @@ const doPatch = (content) => {
 	// content = content.replace('width: n, height: o, viewBox: "0 0 28 20"', 'width: 48, height: 48, viewBox: "0 0 48 48"');
 
 	//save some time on load resolving asset urls...
-	content = content.replaceAll('e.exports = n.p + "', 'e.exports = "/assets/');
-	content = content.replaceAll('e.exports = r.p + "', 'e.exports = "/assets/');
+	content = content.replaceAll(
+		'e.exports = n.p + "',
+		'e.exports = "/assets/',
+	);
+	content = content.replaceAll(
+		'e.exports = r.p + "',
+		'e.exports = "/assets/',
+	);
 
 	return content;
 };
@@ -66,7 +72,7 @@ const processFile = async (name) => {
 
 	await fs.writeFile(path.join(CACHE_PATH, `${name}.js`), text);
 
-	return [...new Set(text.match((/[A-Fa-f0-9]{20}/g)))];
+	return [...new Set(text.match(/[A-Fa-f0-9]{20}/g))];
 };
 
 (async () => {
@@ -83,7 +89,9 @@ const processFile = async (name) => {
 
 		process.stdout.clearLine(0);
 		process.stdout.cursorTo(0);
-		process.stdout.write(`Scraping asset ${asset}. Remaining: ${INDEX_SCRIPTS.length}`);
+		process.stdout.write(
+			`Scraping asset ${asset}. Remaining: ${INDEX_SCRIPTS.length}`,
+		);
 
 		const newAssets = await processFile(asset);
 		assets.push(...newAssets);
@@ -103,15 +111,21 @@ const processFile = async (name) => {
 		}
 
 		while (rates.length > 20) rates.shift();
-		const averageRate = rates.length ? rates.reduce((prev, curr) => prev + curr) / rates.length : 1;
-		const finishTime = (averageRate * (assets.length - i));
+		const averageRate = rates.length
+			? rates.reduce((prev, curr) => prev + curr) / rates.length
+			: 1;
+		const finishTime = averageRate * (assets.length - i);
 
 		process.stdout.clearLine(0);
 		process.stdout.cursorTo(0);
 		process.stdout.write(
 			`Caching asset ${asset}. ` +
-			`${i}/${assets.length - 1} = ${Math.floor((i / (assets.length - 1)) * 100)}% ` +
-			`Finish at: ${new Date(Date.now() + finishTime).toLocaleTimeString()}`
+				`${i}/${assets.length - 1} = ${Math.floor(
+					(i / (assets.length - 1)) * 100,
+				)}% ` +
+				`Finish at: ${new Date(
+					Date.now() + finishTime,
+				).toLocaleTimeString()}`,
 		);
 
 		await processFile(asset);
@@ -122,4 +136,4 @@ const processFile = async (name) => {
 	}
 
 	console.log(`\nDone`);
-})();
\ No newline at end of file
+})();
diff --git a/scripts/rights.js b/scripts/rights.js
index a4eb0b31..d0d1e163 100644
--- a/scripts/rights.js
+++ b/scripts/rights.js
@@ -1,4 +1,4 @@
-require('module-alias/register');
+require("module-alias/register");
 const { Rights } = require("..");
 
 const allRights = new Rights(1).bitfield;
@@ -18,4 +18,4 @@ discordLike -= Rights.FLAGS.BYPASS_RATE_LIMITS;
 discordLike -= Rights.FLAGS.CREDITABLE;
 discordLike -= Rights.FLAGS.MANAGE_GUILD_DIRECTORY;
 discordLike -= Rights.FLAGS.SEND_BACKDATED_EVENTS;
-console.log(`Discord.com-like rights:`, discordLike);
\ No newline at end of file
+console.log(`Discord.com-like rights:`, discordLike);
diff --git a/scripts/schema.js b/scripts/schema.js
index de062d63..90a346c9 100644
--- a/scripts/schema.js
+++ b/scripts/schema.js
@@ -11,10 +11,10 @@ const settings = {
 	excludePrivate: true,
 	defaultNumberType: "integer",
 	noExtraProps: true,
-	defaultProps: false
+	defaultProps: false,
 };
 const compilerOptions = {
-	strictNullChecks: true
+	strictNullChecks: true,
 };
 const Excluded = [
 	"DefaultSchema",
@@ -47,11 +47,17 @@ function modify(obj) {
 }
 
 function main() {
-	const program = TJS.programFromConfig("tsconfig.json")
+	const program = TJS.programFromConfig("tsconfig.json");
 	const generator = TJS.buildGenerator(program, settings);
 	if (!generator || !program) return;
 
-	let schemas = generator.getUserSymbols().filter((x) => (x.endsWith("Schema") || x.endsWith("Response")) && !Excluded.includes(x));
+	let schemas = generator
+		.getUserSymbols()
+		.filter(
+			(x) =>
+				(x.endsWith("Schema") || x.endsWith("Response")) &&
+				!Excluded.includes(x),
+		);
 	console.log(schemas);
 
 	var definitions = {};
diff --git a/scripts/stresstest/src/login/index.js b/scripts/stresstest/src/login/index.js
index 96603652..291e2b8b 100644
--- a/scripts/stresstest/src/login/index.js
+++ b/scripts/stresstest/src/login/index.js
@@ -6,12 +6,12 @@ async function login(account) {
 	var body = {
 		fingerprint: "805826570869932034.wR8vi8lGlFBJerErO9LG5NViJFw",
 		login: account.email,
-		password: account.password
+		password: account.password,
 	};
 	var x = await fetch(config.url + "/auth/login", {
 		method: "POST",
 		headers: { "Content-Type": "application/json" },
-		body: JSON.stringify(body)
+		body: JSON.stringify(body),
 	});
 	console.log(x);
 	x = await x.json();
diff --git a/scripts/stresstest/src/message/send.js b/scripts/stresstest/src/message/send.js
index d21560d7..1e5ea062 100644
--- a/scripts/stresstest/src/message/send.js
+++ b/scripts/stresstest/src/message/send.js
@@ -6,16 +6,19 @@ async function sendMessage(account) {
 	var body = {
 		fingerprint: "805826570869932034.wR8vi8lGlFBJerErO9LG5NViJFw",
 		content: "Test",
-		tts: false
+		tts: false,
 	};
-	var x = await fetch(config.url + "/channels/" + config["text-channel"] + "/messages", {
-		method: "POST",
-		headers: {
-			"Content-Type": "application/json",
-			Authorization: account.token
+	var x = await fetch(
+		config.url + "/channels/" + config["text-channel"] + "/messages",
+		{
+			method: "POST",
+			headers: {
+				"Content-Type": "application/json",
+				Authorization: account.token,
+			},
+			body: JSON.stringify(body),
 		},
-		body: JSON.stringify(body)
-	});
+	);
 	console.log(x);
 	x = await x.json();
 	console.log(x);
diff --git a/scripts/stresstest/src/register/index.js b/scripts/stresstest/src/register/index.js
index 86f908cd..38089dc7 100644
--- a/scripts/stresstest/src/register/index.js
+++ b/scripts/stresstest/src/register/index.js
@@ -4,7 +4,11 @@ var config = require("../../config.json");
 module.exports = generate;
 async function generate() {
 	var mail = (Math.random() + 10).toString(36).substring(2);
-	mail = mail + "." + (Math.random() + 10).toString(36).substring(2) + "@stresstest.com";
+	mail =
+		mail +
+		"." +
+		(Math.random() + 10).toString(36).substring(2) +
+		"@stresstest.com";
 	var password =
 		(Math.random() * 69).toString(36).substring(-7) +
 		(Math.random() * 69).toString(36).substring(-7) +
@@ -20,12 +24,12 @@ async function generate() {
 		consent: true,
 		date_of_birth: "2000-04-04",
 		gift_code_sku_id: null,
-		captcha_key: null
+		captcha_key: null,
 	};
 	var x = await fetch(config.url + "/auth/register", {
 		method: "POST",
 		headers: { "Content-Type": "application/json" },
-		body: JSON.stringify(body)
+		body: JSON.stringify(body),
 	});
 	console.log(x);
 	x = await x.json();
diff --git a/src-slowcord/README.md b/src-slowcord/README.md
index 892b5763..ac42117a 100644
--- a/src-slowcord/README.md
+++ b/src-slowcord/README.md
@@ -1 +1 @@
-Additional resources/services for [Slowcord](https://slowcord.maddy.k.vu/login)
\ No newline at end of file
+Additional resources/services for [Slowcord](https://slowcord.maddy.k.vu/login)
diff --git a/src-slowcord/bot/.vscode/launch.json b/src-slowcord/bot/.vscode/launch.json
index 92765e22..c1c765a8 100644
--- a/src-slowcord/bot/.vscode/launch.json
+++ b/src-slowcord/bot/.vscode/launch.json
@@ -4,12 +4,9 @@
 			"name": "Slowcord Bot",
 			"program": "${workspaceFolder}/build/index.js",
 			"request": "launch",
-			"skipFiles": [
-				"<node_internals>/**"
-			],
+			"skipFiles": ["<node_internals>/**"],
 			"type": "node",
 			"preLaunchTask": "npm: build"
 		}
-
 	]
-}
\ No newline at end of file
+}
diff --git a/src-slowcord/bot/.vscode/tasks.json b/src-slowcord/bot/.vscode/tasks.json
index 356126d8..be345ecd 100644
--- a/src-slowcord/bot/.vscode/tasks.json
+++ b/src-slowcord/bot/.vscode/tasks.json
@@ -10,4 +10,4 @@
 			"detail": "tsc -b"
 		}
 	]
-}
\ No newline at end of file
+}
diff --git a/src-slowcord/bot/src/Bot.ts b/src-slowcord/bot/src/Bot.ts
index 45938846..cf3ff09f 100644
--- a/src-slowcord/bot/src/Bot.ts
+++ b/src-slowcord/bot/src/Bot.ts
@@ -1,11 +1,11 @@
 import { Message } from "discord.js";
-import { Client } from "fosscord-gopnik/build/lib";	// huh? oh well. some bugs in my lib Ig
+import { Client } from "fosscord-gopnik/build/lib"; // huh? oh well. some bugs in my lib Ig
 
 import { Command, getCommands } from "./commands/index.js";
 
 export default class Bot {
 	client: Client;
-	commands: { [key: string]: Command; } = {};
+	commands: { [key: string]: Command } = {};
 
 	constructor(client: Client) {
 		this.client = client;
@@ -17,10 +17,12 @@ export default class Bot {
 		console.log(`Logged in as ${this.client.user!.tag}`);
 
 		this.client.user!.setPresence({
-			activities: [{
-				name: "EVERYTHING",
-				type: "WATCHING",
-			}]
+			activities: [
+				{
+					name: "EVERYTHING",
+					type: "WATCHING",
+				},
+			],
 		});
 	};
 
@@ -45,4 +47,4 @@ export default class Bot {
 			args: args,
 		});
 	};
-}
\ No newline at end of file
+}
diff --git a/src-slowcord/bot/src/commands/index.ts b/src-slowcord/bot/src/commands/index.ts
index d3b39e0f..0130b2bc 100644
--- a/src-slowcord/bot/src/commands/index.ts
+++ b/src-slowcord/bot/src/commands/index.ts
@@ -2,11 +2,11 @@ import { Message, GuildMember, Guild, User } from "discord.js";
 import fs from "fs";
 
 export type CommandContext = {
-	user: User,
-	guild: Guild | null,
-	member: GuildMember | null,
-	message: Message,
-	args: string[],
+	user: User;
+	guild: Guild | null;
+	member: GuildMember | null;
+	message: Message;
+	args: string[];
 };
 
 export type Command = {
@@ -19,8 +19,7 @@ const walk = async (path: string) => {
 	const out = [];
 	for (var file of files) {
 		if (fs.statSync(`${path}/${file}`).isDirectory()) continue;
-		if (file.indexOf("index") !== -1)
-			continue;
+		if (file.indexOf("index") !== -1) continue;
 		if (file.indexOf(".js") !== file.length - 3) continue;
 		var imported = (await import(`./${file}`)).default;
 		out.push(imported);
diff --git a/src-slowcord/bot/src/commands/instance.ts b/src-slowcord/bot/src/commands/instance.ts
index ac0c9b2d..170d8f76 100644
--- a/src-slowcord/bot/src/commands/instance.ts
+++ b/src-slowcord/bot/src/commands/instance.ts
@@ -1,7 +1,7 @@
 import { Command } from "./index.js";
 import { User, Guild, Message } from "@fosscord/util";
 
-const cache: { [key: string]: number; } = {
+const cache: { [key: string]: number } = {
 	users: 0,
 	guilds: 0,
 	messages: 0,
@@ -11,7 +11,10 @@ const cache: { [key: string]: number; } = {
 export default {
 	name: "instance",
 	exec: async ({ message }) => {
-		if (Date.now() > cache.lastChecked + parseInt(process.env.CACHE_TTL as string)) {
+		if (
+			Date.now() >
+			cache.lastChecked + parseInt(process.env.CACHE_TTL as string)
+		) {
 			cache.users = await User.count();
 			cache.guilds = await Guild.count();
 			cache.messages = await Message.count();
@@ -19,18 +22,35 @@ export default {
 		}
 
 		return message.reply({
-			embeds: [{
-				title: "Instance Stats",
-				description: "For more indepth information, check out https://grafana.understars.dev",
-				footer: {
-					text: `Last checked: ${Math.floor((Date.now() - cache.lastChecked) / (1000 * 60))} minutes ago`,
+			embeds: [
+				{
+					title: "Instance Stats",
+					description:
+						"For more indepth information, check out https://grafana.understars.dev",
+					footer: {
+						text: `Last checked: ${Math.floor(
+							(Date.now() - cache.lastChecked) / (1000 * 60),
+						)} minutes ago`,
+					},
+					fields: [
+						{
+							inline: true,
+							name: "Total Users",
+							value: cache.users.toString(),
+						},
+						{
+							inline: true,
+							name: "Total Guilds",
+							value: cache.guilds.toString(),
+						},
+						{
+							inline: true,
+							name: "Total Messages",
+							value: cache.messages.toString(),
+						},
+					],
 				},
-				fields: [
-					{ inline: true, name: "Total Users", value: cache.users.toString() },
-					{ inline: true, name: "Total Guilds", value: cache.guilds.toString() },
-					{ inline: true, name: "Total Messages", value: cache.messages.toString() },
-				]
-			}]
+			],
 		});
-	}
-} as Command;
\ No newline at end of file
+	},
+} as Command;
diff --git a/src-slowcord/bot/src/index.ts b/src-slowcord/bot/src/index.ts
index 253f759c..fa97313f 100644
--- a/src-slowcord/bot/src/index.ts
+++ b/src-slowcord/bot/src/index.ts
@@ -1,6 +1,6 @@
 import "dotenv/config";
 import Fosscord from "fosscord-gopnik";
-import Bot from "./Bot.js";	// huh?
+import Bot from "./Bot.js"; // huh?
 import { initDatabase } from "fosscord-server/src/util";
 
 const client = new Fosscord.Client({
@@ -21,4 +21,4 @@ client.on("messageCreate", bot.onMessageCreate);
 (async () => {
 	await initDatabase();
 	await client.login(process.env.TOKEN);
-})();
\ No newline at end of file
+})();
diff --git a/src-slowcord/bot/tsconfig.json b/src-slowcord/bot/tsconfig.json
index 05bfc5c7..f055681a 100644
--- a/src-slowcord/bot/tsconfig.json
+++ b/src-slowcord/bot/tsconfig.json
@@ -1,101 +1,103 @@
 {
-  "compilerOptions": {
-    /* Visit https://aka.ms/tsconfig.json to read more about this file */
+	"compilerOptions": {
+		/* Visit https://aka.ms/tsconfig.json to read more about this file */
 
-    /* Projects */
-    // "incremental": true,                              /* Enable incremental compilation */
-    // "composite": true,                                /* Enable constraints that allow a TypeScript project to be used with project references. */
-    // "tsBuildInfoFile": "./",                          /* Specify the folder for .tsbuildinfo incremental compilation files. */
-    // "disableSourceOfProjectReferenceRedirect": true,  /* Disable preferring source files instead of declaration files when referencing composite projects */
-    // "disableSolutionSearching": true,                 /* Opt a project out of multi-project reference checking when editing. */
-    // "disableReferencedProjectLoad": true,             /* Reduce the number of projects loaded automatically by TypeScript. */
+		/* Projects */
+		// "incremental": true,                              /* Enable incremental compilation */
+		// "composite": true,                                /* Enable constraints that allow a TypeScript project to be used with project references. */
+		// "tsBuildInfoFile": "./",                          /* Specify the folder for .tsbuildinfo incremental compilation files. */
+		// "disableSourceOfProjectReferenceRedirect": true,  /* Disable preferring source files instead of declaration files when referencing composite projects */
+		// "disableSolutionSearching": true,                 /* Opt a project out of multi-project reference checking when editing. */
+		// "disableReferencedProjectLoad": true,             /* Reduce the number of projects loaded automatically by TypeScript. */
 
-    /* Language and Environment */
-    "target": "ES6",                                  /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
-    "lib": ["ES2021"],                                        /* Specify a set of bundled library declaration files that describe the target runtime environment. */
-    // "jsx": "preserve",                                /* Specify what JSX code is generated. */
-    "experimentalDecorators": true,                   /* Enable experimental support for TC39 stage 2 draft decorators. */
-    // "emitDecoratorMetadata": true,                    /* Emit design-type metadata for decorated declarations in source files. */
-    // "jsxFactory": "",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
-    // "jsxFragmentFactory": "",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
-    // "jsxImportSource": "",                            /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
-    // "reactNamespace": "",                             /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
-    // "noLib": true,                                    /* Disable including any library files, including the default lib.d.ts. */
-    // "useDefineForClassFields": true,                  /* Emit ECMAScript-standard-compliant class fields. */
+		/* Language and Environment */
+		"target": "ES6" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
+		"lib": [
+			"ES2021"
+		] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,
+		// "jsx": "preserve",                                /* Specify what JSX code is generated. */
+		"experimentalDecorators": true /* Enable experimental support for TC39 stage 2 draft decorators. */,
+		// "emitDecoratorMetadata": true,                    /* Emit design-type metadata for decorated declarations in source files. */
+		// "jsxFactory": "",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
+		// "jsxFragmentFactory": "",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
+		// "jsxImportSource": "",                            /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
+		// "reactNamespace": "",                             /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
+		// "noLib": true,                                    /* Disable including any library files, including the default lib.d.ts. */
+		// "useDefineForClassFields": true,                  /* Emit ECMAScript-standard-compliant class fields. */
 
-    /* Modules */
-    "module": "CommonJS",                                /* Specify what module code is generated. */
-    // "rootDir": "./",                                  /* Specify the root folder within your source files. */
-    "moduleResolution": "node",                       /* Specify how TypeScript looks up a file from a given module specifier. */
-    // "baseUrl": "./",                                  /* Specify the base directory to resolve non-relative module names. */
-    // "paths": {},                                      /* Specify a set of entries that re-map imports to additional lookup locations. */
-    // "rootDirs": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */
-    // "typeRoots": [],                                  /* Specify multiple folders that act like `./node_modules/@types`. */
-    // "types": [],                                      /* Specify type package names to be included without being referenced in a source file. */
-    // "allowUmdGlobalAccess": true,                     /* Allow accessing UMD globals from modules. */
-    // "resolveJsonModule": true,                        /* Enable importing .json files */
-    // "noResolve": true,                                /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
+		/* Modules */
+		"module": "CommonJS" /* Specify what module code is generated. */,
+		// "rootDir": "./",                                  /* Specify the root folder within your source files. */
+		"moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */,
+		// "baseUrl": "./",                                  /* Specify the base directory to resolve non-relative module names. */
+		// "paths": {},                                      /* Specify a set of entries that re-map imports to additional lookup locations. */
+		// "rootDirs": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */
+		// "typeRoots": [],                                  /* Specify multiple folders that act like `./node_modules/@types`. */
+		// "types": [],                                      /* Specify type package names to be included without being referenced in a source file. */
+		// "allowUmdGlobalAccess": true,                     /* Allow accessing UMD globals from modules. */
+		// "resolveJsonModule": true,                        /* Enable importing .json files */
+		// "noResolve": true,                                /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
 
-    /* JavaScript Support */
-    // "allowJs": true,                                  /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
-    // "checkJs": true,                                  /* Enable error reporting in type-checked JavaScript files. */
-    // "maxNodeModuleJsDepth": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
+		/* JavaScript Support */
+		// "allowJs": true,                                  /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
+		// "checkJs": true,                                  /* Enable error reporting in type-checked JavaScript files. */
+		// "maxNodeModuleJsDepth": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
 
-    /* Emit */
-    // "declaration": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
-    // "declarationMap": true,                           /* Create sourcemaps for d.ts files. */
-    // "emitDeclarationOnly": true,                      /* Only output d.ts files and not JavaScript files. */
-    "sourceMap": true,                                /* Create source map files for emitted JavaScript files. */
-    // "outFile": "./",                                  /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
-    "outDir": "./build",                                   /* Specify an output folder for all emitted files. */
-    // "removeComments": true,                           /* Disable emitting comments. */
-    // "noEmit": true,                                   /* Disable emitting files from a compilation. */
-    // "importHelpers": true,                            /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
-    // "importsNotUsedAsValues": "remove",               /* Specify emit/checking behavior for imports that are only used for types */
-    // "downlevelIteration": true,                       /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
-    // "sourceRoot": "",                                 /* Specify the root path for debuggers to find the reference source code. */
-    // "mapRoot": "",                                    /* Specify the location where debugger should locate map files instead of generated locations. */
-    // "inlineSourceMap": true,                          /* Include sourcemap files inside the emitted JavaScript. */
-    // "inlineSources": true,                            /* Include source code in the sourcemaps inside the emitted JavaScript. */
-    // "emitBOM": true,                                  /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
-    // "newLine": "crlf",                                /* Set the newline character for emitting files. */
-    // "stripInternal": true,                            /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
-    // "noEmitHelpers": true,                            /* Disable generating custom helper functions like `__extends` in compiled output. */
-    // "noEmitOnError": true,                            /* Disable emitting files if any type checking errors are reported. */
-    // "preserveConstEnums": true,                       /* Disable erasing `const enum` declarations in generated code. */
-    // "declarationDir": "./",                           /* Specify the output directory for generated declaration files. */
-    // "preserveValueImports": true,                     /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
+		/* Emit */
+		// "declaration": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
+		// "declarationMap": true,                           /* Create sourcemaps for d.ts files. */
+		// "emitDeclarationOnly": true,                      /* Only output d.ts files and not JavaScript files. */
+		"sourceMap": true /* Create source map files for emitted JavaScript files. */,
+		// "outFile": "./",                                  /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
+		"outDir": "./build" /* Specify an output folder for all emitted files. */,
+		// "removeComments": true,                           /* Disable emitting comments. */
+		// "noEmit": true,                                   /* Disable emitting files from a compilation. */
+		// "importHelpers": true,                            /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
+		// "importsNotUsedAsValues": "remove",               /* Specify emit/checking behavior for imports that are only used for types */
+		// "downlevelIteration": true,                       /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
+		// "sourceRoot": "",                                 /* Specify the root path for debuggers to find the reference source code. */
+		// "mapRoot": "",                                    /* Specify the location where debugger should locate map files instead of generated locations. */
+		// "inlineSourceMap": true,                          /* Include sourcemap files inside the emitted JavaScript. */
+		// "inlineSources": true,                            /* Include source code in the sourcemaps inside the emitted JavaScript. */
+		// "emitBOM": true,                                  /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
+		// "newLine": "crlf",                                /* Set the newline character for emitting files. */
+		// "stripInternal": true,                            /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
+		// "noEmitHelpers": true,                            /* Disable generating custom helper functions like `__extends` in compiled output. */
+		// "noEmitOnError": true,                            /* Disable emitting files if any type checking errors are reported. */
+		// "preserveConstEnums": true,                       /* Disable erasing `const enum` declarations in generated code. */
+		// "declarationDir": "./",                           /* Specify the output directory for generated declaration files. */
+		// "preserveValueImports": true,                     /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
 
-    /* Interop Constraints */
-    // "isolatedModules": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */
-    // "allowSyntheticDefaultImports": true,             /* Allow 'import x from y' when a module doesn't have a default export. */
-    "esModuleInterop": true,                             /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
-    // "preserveSymlinks": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
-    "forceConsistentCasingInFileNames": true,            /* Ensure that casing is correct in imports. */
+		/* Interop Constraints */
+		// "isolatedModules": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */
+		// "allowSyntheticDefaultImports": true,             /* Allow 'import x from y' when a module doesn't have a default export. */
+		"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */,
+		// "preserveSymlinks": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
+		"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
 
-    /* Type Checking */
-    "strict": true,                                      /* Enable all strict type-checking options. */
-    // "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied `any` type.. */
-    // "strictNullChecks": true,                         /* When type checking, take into account `null` and `undefined`. */
-    // "strictFunctionTypes": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
-    // "strictBindCallApply": true,                      /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
-    "strictPropertyInitialization": false,             /* Check for class properties that are declared but not set in the constructor. */
-    // "noImplicitThis": true,                           /* Enable error reporting when `this` is given the type `any`. */
-    // "useUnknownInCatchVariables": true,               /* Type catch clause variables as 'unknown' instead of 'any'. */
-    // "alwaysStrict": true,                             /* Ensure 'use strict' is always emitted. */
-    // "noUnusedLocals": true,                           /* Enable error reporting when a local variables aren't read. */
-    // "noUnusedParameters": true,                       /* Raise an error when a function parameter isn't read */
-    // "exactOptionalPropertyTypes": true,               /* Interpret optional property types as written, rather than adding 'undefined'. */
-    // "noImplicitReturns": true,                        /* Enable error reporting for codepaths that do not explicitly return in a function. */
-    // "noFallthroughCasesInSwitch": true,               /* Enable error reporting for fallthrough cases in switch statements. */
-    // "noUncheckedIndexedAccess": true,                 /* Include 'undefined' in index signature results */
-    // "noImplicitOverride": true,                       /* Ensure overriding members in derived classes are marked with an override modifier. */
-    // "noPropertyAccessFromIndexSignature": true,       /* Enforces using indexed accessors for keys declared using an indexed type */
-    // "allowUnusedLabels": true,                        /* Disable error reporting for unused labels. */
-    // "allowUnreachableCode": true,                     /* Disable error reporting for unreachable code. */
+		/* Type Checking */
+		"strict": true /* Enable all strict type-checking options. */,
+		// "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied `any` type.. */
+		// "strictNullChecks": true,                         /* When type checking, take into account `null` and `undefined`. */
+		// "strictFunctionTypes": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
+		// "strictBindCallApply": true,                      /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
+		"strictPropertyInitialization": false /* Check for class properties that are declared but not set in the constructor. */,
+		// "noImplicitThis": true,                           /* Enable error reporting when `this` is given the type `any`. */
+		// "useUnknownInCatchVariables": true,               /* Type catch clause variables as 'unknown' instead of 'any'. */
+		// "alwaysStrict": true,                             /* Ensure 'use strict' is always emitted. */
+		// "noUnusedLocals": true,                           /* Enable error reporting when a local variables aren't read. */
+		// "noUnusedParameters": true,                       /* Raise an error when a function parameter isn't read */
+		// "exactOptionalPropertyTypes": true,               /* Interpret optional property types as written, rather than adding 'undefined'. */
+		// "noImplicitReturns": true,                        /* Enable error reporting for codepaths that do not explicitly return in a function. */
+		// "noFallthroughCasesInSwitch": true,               /* Enable error reporting for fallthrough cases in switch statements. */
+		// "noUncheckedIndexedAccess": true,                 /* Include 'undefined' in index signature results */
+		// "noImplicitOverride": true,                       /* Ensure overriding members in derived classes are marked with an override modifier. */
+		// "noPropertyAccessFromIndexSignature": true,       /* Enforces using indexed accessors for keys declared using an indexed type */
+		// "allowUnusedLabels": true,                        /* Disable error reporting for unused labels. */
+		// "allowUnreachableCode": true,                     /* Disable error reporting for unreachable code. */
 
-    /* Completeness */
-    // "skipDefaultLibCheck": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */
-    "skipLibCheck": true                                 /* Skip type checking all .d.ts files. */
-  }
+		/* Completeness */
+		// "skipDefaultLibCheck": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */
+		"skipLibCheck": true /* Skip type checking all .d.ts files. */
+	}
 }
diff --git a/src-slowcord/login/public/css/index.css b/src-slowcord/login/public/css/index.css
index d4f5a4b4..cf294ccb 100644
--- a/src-slowcord/login/public/css/index.css
+++ b/src-slowcord/login/public/css/index.css
@@ -4,13 +4,13 @@ html {
 	--background-primary: rgb(22, 23, 25);
 	--background-secondary: rgb(15, 16, 18);
 	--foreground-primary: rgb(200, 200, 200);
-	--background-login-discord: #5865F2;
+	--background-login-discord: #5865f2;
 
 	background: url("https://slowcord.maddy.k.vu/assets/background.png");
 	background-size: 100% 100%;
 	background-repeat: no-repeat;
 
-	font-family: 'Montserrat', sans-serif;
+	font-family: "Montserrat", sans-serif;
 
 	color: var(--foreground-primary);
 }
@@ -55,7 +55,8 @@ html {
 	text-align: center;
 }
 
-.header-subtext a, .header-subtext p {
+.header-subtext a,
+.header-subtext p {
 	display: inline-block;
 	margin: 0 10px 0 10px;
 }
@@ -109,4 +110,4 @@ label {
 	display: flex;
 	justify-content: center;
 	margin-top: 10px;
-}
\ No newline at end of file
+}
diff --git a/src-slowcord/login/public/js/handler.js b/src-slowcord/login/public/js/handler.js
index 68a656b4..2d7b164b 100644
--- a/src-slowcord/login/public/js/handler.js
+++ b/src-slowcord/login/public/js/handler.js
@@ -29,13 +29,12 @@ const handleSubmit = async (path, body) => {
 	}
 
 	// Very fun error message here lol
-	const error =
-		json.errors
-			? Object.values(json.errors)[0]._errors[0].message
-			: (
-				json.captcha_key ? "Captcha required" : json.message
-			);
+	const error = json.errors
+		? Object.values(json.errors)[0]._errors[0].message
+		: json.captcha_key
+		? "Captcha required"
+		: json.message;
 
 	failureMessage.innerHTML = error;
 	failureMessage.style.display = "block";
-};
\ No newline at end of file
+};
diff --git a/src-slowcord/login/public/login.html b/src-slowcord/login/public/login.html
index 8cecd20b..fa367b70 100644
--- a/src-slowcord/login/public/login.html
+++ b/src-slowcord/login/public/login.html
@@ -1,103 +1,127 @@
 <html lang="en">
-
-<head>
-	<meta charset="UTF-8">
-	<meta http-equiv="X-UA-Compatible" content="IE=edge">
-	<meta name="viewport" content="width=device-width, initial-scale=1.0">
-	<title>Slowcord</title>
-
-	<link rel="preconnect" href="https://fonts.googleapis.com">
-	<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-	<link href="https://fonts.googleapis.com/css2?family=Montserrat&display=swap" rel="stylesheet">
-
-	<link rel="stylesheet" href="./css/index.css">
-	<script src="js/handler.js"></script>
-</head>
-
-<body>
-	<div class="content">
-		<div class="login">
-			<div class="header">
-				<h1>Welcome to Slowcord</h1>
-				<div class="header-subtext">
-					<p>Glad to see you &lt;3 </p>
-					<a href="/register">Wait, I'm new!</a>
+	<head>
+		<meta charset="UTF-8" />
+		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+		<title>Slowcord</title>
+
+		<link rel="preconnect" href="https://fonts.googleapis.com" />
+		<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
+		<link
+			href="https://fonts.googleapis.com/css2?family=Montserrat&display=swap"
+			rel="stylesheet"
+		/>
+
+		<link rel="stylesheet" href="./css/index.css" />
+		<script src="js/handler.js"></script>
+	</head>
+
+	<body>
+		<div class="content">
+			<div class="login">
+				<div class="header">
+					<h1>Welcome to Slowcord</h1>
+					<div class="header-subtext">
+						<p>Glad to see you &lt;3</p>
+						<a href="/register">Wait, I'm new!</a>
+					</div>
+
+					<p id="failure">Login failed</p>
 				</div>
 
-				<p id="failure">Login failed</p>
+				<form action="javascript:void(0);" name="login">
+					<label for="email">Email</label>
+					<input type="email" name="email" />
+
+					<label for="password">Password</label>
+					<input type="password" name="password" />
+
+					<input type="submit" value="Login" />
+
+					<a
+						id="loginDiscord"
+						class="oauth"
+						href="https://discord.com/api/oauth2/authorize?client_id=991688571415175198&redirect_uri=https%3A%2F%2Fslowcord.maddy.k.vu%2Foauth%2Fdiscord&response_type=code&scope=identify%20email"
+					>
+						Login with Discord
+					</a>
+
+					<div
+						class="h-captcha"
+						data-sitekey="fa3163ea-79a7-4b7b-b752-b58c545906c8"
+						data-theme="dark"
+					></div>
+					<script
+						src="https://js.hcaptcha.com/1/api.js"
+						async
+						defer
+					></script>
+				</form>
+
+				<form
+					action="javascript:void(0);"
+					name="2fa"
+					style="display: none"
+				>
+					<label for="code">2FA Code</label>
+					<input type="number" name="code" />
+
+					<input type="hidden" name="ticket" />
+
+					<input type="submit" value="Login" />
+				</form>
 			</div>
-
-			<form action="javascript:void(0);" name="login">
-				<label for="email">Email</label>
-				<input type="email" name="email" />
-
-				<label for="password">Password</label>
-				<input type="password" name="password" />
-
-				<input type="submit" value="Login" />
-
-				<a id="loginDiscord" class="oauth"
-					href="https://discord.com/api/oauth2/authorize?client_id=991688571415175198&redirect_uri=https%3A%2F%2Fslowcord.maddy.k.vu%2Foauth%2Fdiscord&response_type=code&scope=identify%20email">
-					Login with Discord
-				</a>
-
-				<div class="h-captcha" data-sitekey="fa3163ea-79a7-4b7b-b752-b58c545906c8" data-theme="dark"></div>
-				<script src="https://js.hcaptcha.com/1/api.js" async defer></script>
-			</form>
-
-			<form action="javascript:void(0);" name="2fa" style="display: none">
-				<label for="code">2FA Code</label>
-				<input type="number" name="code" />
-
-				<input type="hidden" name="ticket" />
-
-				<input type="submit" value="Login"/>
-			</form>
 		</div>
-	</div>
-
-	<script>
-		/* https://stackoverflow.com/questions/5639346/what-is-the-shortest-function-for-reading-a-cookie-by-name-in-javascript */
-		const getCookieValue = (name) => (
-			document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]+)')?.pop() || ''
-		);
-
-		let token = getCookieValue("token");
-		if (token.trim().length) {
-			/* https://stackoverflow.com/a/27374365 */
-			// why is clearing cookies so weird? wtf
-			document.cookie.split(";").forEach(function (c) { document.cookie = c.replace(/^ +/, "").replace(/=.*/, "=;expires=" + new Date().toUTCString() + ";path=/"); });
-			window.localStorage.setItem("token", `"${token}"`);
-			window.location.href = "/app";
-		}
-
-		token = window.localStorage.getItem("token");
-		if (token) window.location.href = "/app";
-
-		document.forms["login"].addEventListener("submit", async (e) => {
-			const data = new FormData(e.target);
-			const email = data.get("email");
-			const password = data.get("password");
-			const hcaptcha = data.get("h-captcha-response");
-
-			await handleSubmit("/api/v9/auth/login", {
-				login: email,
-				password: password,
-				captcha_key: hcaptcha,
+
+		<script>
+			/* https://stackoverflow.com/questions/5639346/what-is-the-shortest-function-for-reading-a-cookie-by-name-in-javascript */
+			const getCookieValue = (name) =>
+				document.cookie
+					.match("(^|;)\\s*" + name + "\\s*=\\s*([^;]+)")
+					?.pop() || "";
+
+			let token = getCookieValue("token");
+			if (token.trim().length) {
+				/* https://stackoverflow.com/a/27374365 */
+				// why is clearing cookies so weird? wtf
+				document.cookie.split(";").forEach(function (c) {
+					document.cookie = c
+						.replace(/^ +/, "")
+						.replace(
+							/=.*/,
+							"=;expires=" + new Date().toUTCString() + ";path=/",
+						);
+				});
+				window.localStorage.setItem("token", `"${token}"`);
+				window.location.href = "/app";
+			}
+
+			token = window.localStorage.getItem("token");
+			if (token) window.location.href = "/app";
+
+			document.forms["login"].addEventListener("submit", async (e) => {
+				const data = new FormData(e.target);
+				const email = data.get("email");
+				const password = data.get("password");
+				const hcaptcha = data.get("h-captcha-response");
+
+				await handleSubmit("/api/v9/auth/login", {
+					login: email,
+					password: password,
+					captcha_key: hcaptcha,
+				});
 			});
-		})
 
-		document.forms["2fa"].addEventListener("submit", async (e) => {
-			const data = new FormData(e.target);
-			const code = data.get("code");
-			const ticket = data.get("ticket");
+			document.forms["2fa"].addEventListener("submit", async (e) => {
+				const data = new FormData(e.target);
+				const code = data.get("code");
+				const ticket = data.get("ticket");
 
-			await handleSubmit("/api/v9/auth/mfa/totp", {
-				code: code,
-				ticket: ticket,
+				await handleSubmit("/api/v9/auth/mfa/totp", {
+					code: code,
+					ticket: ticket,
+				});
 			});
-		})
-	</script>
-</body>
-
-</html>
\ No newline at end of file
+		</script>
+	</body>
+</html>
diff --git a/src-slowcord/login/public/register.html b/src-slowcord/login/public/register.html
index 40eecdbe..30b560a4 100644
--- a/src-slowcord/login/public/register.html
+++ b/src-slowcord/login/public/register.html
@@ -1,78 +1,88 @@
 <html lang="en">
-
-<head>
-	<meta charset="UTF-8">
-	<meta http-equiv="X-UA-Compatible" content="IE=edge">
-	<meta name="viewport" content="width=device-width, initial-scale=1.0">
-	<title>Slowcord</title>
-
-	<link rel="preconnect" href="https://fonts.googleapis.com">
-	<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-	<link href="https://fonts.googleapis.com/css2?family=Montserrat&display=swap" rel="stylesheet">
-
-	<link rel="stylesheet" href="./css/index.css">
-	<script src="js/handler.js"></script>
-</head>
-
-<body>
-	<div class="content">
-		<div class="login">
-			<div class="header">
-				<h1>Welcome to Slowcord</h1>
-				<div class="header-subtext">
-					<p>You're new?</p>
-					<a href="/login">Actually, I'm not!</a>
+	<head>
+		<meta charset="UTF-8" />
+		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+		<title>Slowcord</title>
+
+		<link rel="preconnect" href="https://fonts.googleapis.com" />
+		<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
+		<link
+			href="https://fonts.googleapis.com/css2?family=Montserrat&display=swap"
+			rel="stylesheet"
+		/>
+
+		<link rel="stylesheet" href="./css/index.css" />
+		<script src="js/handler.js"></script>
+	</head>
+
+	<body>
+		<div class="content">
+			<div class="login">
+				<div class="header">
+					<h1>Welcome to Slowcord</h1>
+					<div class="header-subtext">
+						<p>You're new?</p>
+						<a href="/login">Actually, I'm not!</a>
+					</div>
+
+					<p id="failure">Register failed</p>
 				</div>
 
-				<p id="failure">Register failed</p>
+				<form action="javascript:void(0);">
+					<label for="email">Email</label>
+					<input type="email" name="email" />
+
+					<label for="username">Username</label>
+					<input type="username" name="username" />
+
+					<label for="password">Password</label>
+					<input type="password" name="password" />
+
+					<label for="dob">Date of Birth</label>
+					<input type="date" name="dob" />
+
+					<input type="submit" value="Register" />
+
+					<a
+						id="loginDiscord"
+						class="oauth"
+						href="https://discord.com/api/oauth2/authorize?client_id=991688571415175198&redirect_uri=https%3A%2F%2Fslowcord.maddy.k.vu%2Foauth%2Fdiscord&response_type=code&scope=identify%20email"
+					>
+						Login with Discord
+					</a>
+
+					<div
+						class="h-captcha"
+						data-sitekey="fa3163ea-79a7-4b7b-b752-b58c545906c8"
+					></div>
+					<script
+						src="https://js.hcaptcha.com/1/api.js"
+						async
+						defer
+					></script>
+				</form>
 			</div>
-
-
-			<form action="javascript:void(0);">
-				<label for="email">Email</label>
-				<input type="email" name="email" />
-
-				<label for="username">Username</label>
-				<input type="username" name="username" />
-
-				<label for="password">Password</label>
-				<input type="password" name="password" />
-
-				<label for="dob">Date of Birth</label>
-				<input type="date" name="dob" />
-
-				<input type="submit" value="Register" />
-
-				<a id="loginDiscord" class="oauth"
-					href="https://discord.com/api/oauth2/authorize?client_id=991688571415175198&redirect_uri=https%3A%2F%2Fslowcord.maddy.k.vu%2Foauth%2Fdiscord&response_type=code&scope=identify%20email">
-					Login with Discord
-				</a>
-
-				<div class="h-captcha" data-sitekey="fa3163ea-79a7-4b7b-b752-b58c545906c8"></div>
-				<script src="https://js.hcaptcha.com/1/api.js" async defer></script>
-			</form>
 		</div>
-	</div>
-
-	<script>
-		document.forms[0].addEventListener("submit", async (e) => {
-			const data = new FormData(e.target);
-			const email = data.get("email");
-			const username = data.get("username");
-			const password = data.get("password");
-			const dob = data.get("dob");
-			const hcaptcha = data.get("h-captcha-response")
 
-			await handleSubmit("/api/v9/auth/register", {
-				consent: true,
-				email: email,
-				username: username,
-				password: password,
-				date_of_birth: dob,
-				captcha_key: hcaptcha,
+		<script>
+			document.forms[0].addEventListener("submit", async (e) => {
+				const data = new FormData(e.target);
+				const email = data.get("email");
+				const username = data.get("username");
+				const password = data.get("password");
+				const dob = data.get("dob");
+				const hcaptcha = data.get("h-captcha-response");
+
+				await handleSubmit("/api/v9/auth/register", {
+					consent: true,
+					email: email,
+					username: username,
+					password: password,
+					date_of_birth: dob,
+					captcha_key: hcaptcha,
+				});
 			});
-		})
-	</script>
-</body>
-
-</html>
\ No newline at end of file
+		</script>
+	</body>
+</html>
diff --git a/src-slowcord/login/src/index.ts b/src-slowcord/login/src/index.ts
index 56d0a687..ced35dcf 100644
--- a/src-slowcord/login/src/index.ts
+++ b/src-slowcord/login/src/index.ts
@@ -1,7 +1,13 @@
 import "dotenv/config";
 import express, { Request, Response } from "express";
 import cookieParser from "cookie-parser";
-import { initDatabase, generateToken, User, Config, handleFile } from "fosscord-server/src/util";
+import {
+	initDatabase,
+	generateToken,
+	User,
+	Config,
+	handleFile,
+} from "fosscord-server/src/util";
 import path from "path";
 import fetch from "node-fetch";
 
@@ -16,8 +22,8 @@ app.use(cookieParser());
 const port = process.env.PORT;
 
 // ip -> unix epoch that requests will be accepted again
-const rateLimits: { [ip: string]: number; } = {};
-const allowRequestsEveryMs = 0.5 * 1000;	// every half second
+const rateLimits: { [ip: string]: number } = {};
+const allowRequestsEveryMs = 0.5 * 1000; // every half second
 
 const allowedRequestsPerSecond = 50;
 let requestsThisSecond = 0;
@@ -36,23 +42,25 @@ class Discord {
 	static getAccessToken = async (req: Request, res: Response) => {
 		const { code } = req.query;
 
-		const body = new URLSearchParams(Object.entries({
-			client_id: process.env.DISCORD_CLIENT_ID as string,
-			client_secret: process.env.DISCORD_SECRET as string,
-			redirect_uri: process.env.DISCORD_REDIRECT as string,
-			code: code as string,
-			grant_type: "authorization_code",
-		})).toString();
+		const body = new URLSearchParams(
+			Object.entries({
+				client_id: process.env.DISCORD_CLIENT_ID as string,
+				client_secret: process.env.DISCORD_SECRET as string,
+				redirect_uri: process.env.DISCORD_REDIRECT as string,
+				code: code as string,
+				grant_type: "authorization_code",
+			}),
+		).toString();
 
 		const resp = await fetch("https://discord.com/api/oauth2/token", {
 			method: "POST",
 			headers: {
 				"Content-Type": "application/x-www-form-urlencoded",
 			},
-			body: body
+			body: body,
 		});
 
-		const json = await resp.json() as any;
+		const json = (await resp.json()) as any;
 		if (json.error) return null;
 
 		return {
@@ -67,24 +75,26 @@ class Discord {
 	static getUserDetails = async (token: string) => {
 		const resp = await fetch("https://discord.com/api/users/@me", {
 			headers: {
-				"Authorization": `Bearer ${token}`,
-			}
+				Authorization: `Bearer ${token}`,
+			},
 		});
 
-		const json = await resp.json() as any;
-		if (!json.username || !json.email) return null;	// eh, deal with bad code later
+		const json = (await resp.json()) as any;
+		if (!json.username || !json.email) return null; // eh, deal with bad code later
 
 		return {
 			id: json.id,
 			email: json.email,
 			username: json.username,
-			avatar_url: json.avatar ? `https://cdn.discordapp.com/avatars/${json.id}/${json.avatar}?size=2048` : null,
+			avatar_url: json.avatar
+				? `https://cdn.discordapp.com/avatars/${json.id}/${json.avatar}?size=2048`
+				: null,
 		};
 	};
 }
 
-const handlers: { [key: string]: any; } = {
-	"discord": Discord,
+const handlers: { [key: string]: any } = {
+	discord: Discord,
 };
 
 app.get("/oauth/:type", async (req, res) => {
@@ -92,17 +102,21 @@ app.get("/oauth/:type", async (req, res) => {
 	if (requestsThisSecond > allowedRequestsPerSecond)
 		return res.sendStatus(429);
 
-	const ip = (req.headers["x-forwarded-for"] as string) || req.socket.remoteAddress as string;
+	const ip =
+		(req.headers["x-forwarded-for"] as string) ||
+		(req.socket.remoteAddress as string);
 	console.log(`${ip}`);
 	if (!rateLimits[ip]) {
 		rateLimits[ip] = Date.now() + allowRequestsEveryMs;
-	}
-	else if (rateLimits[ip] > Date.now()) {
+	} else if (rateLimits[ip] > Date.now()) {
 		rateLimits[ip] += allowRequestsEveryMs;
-		console.log(`${new Date()} : user ${ip} was timed out for ${(rateLimits[ip] - Date.now()) / 1000}s`);
+		console.log(
+			`${new Date()} : user ${ip} was timed out for ${
+				(rateLimits[ip] - Date.now()) / 1000
+			}s`,
+		);
 		return res.sendStatus(429);
-	}
-	else {
+	} else {
 		delete rateLimits[ip];
 	}
 
@@ -121,16 +135,18 @@ app.get("/oauth/:type", async (req, res) => {
 		user = await User.register({
 			email: details.email,
 			username: details.username,
-			req
+			req,
 		});
 
 		if (details.avatar_url) {
 			try {
-				const avatar = await handleFile(`/avatars/${user.id}`, await toDataURL(details.avatar_url) as string);
+				const avatar = await handleFile(
+					`/avatars/${user.id}`,
+					(await toDataURL(details.avatar_url)) as string,
+				);
 				user.avatar = avatar;
 				await user.save();
-			}
-			catch (e) {
+			} catch (e) {
 				console.error(e);
 			}
 		}
@@ -152,4 +168,4 @@ app.use(express.static("public", { extensions: ["html"] }));
 	app.listen(port, () => {
 		console.log(`Listening on port ${port}`);
 	});
-})();
\ No newline at end of file
+})();
diff --git a/src-slowcord/login/tsconfig.json b/src-slowcord/login/tsconfig.json
index b8a5965d..4d96714c 100644
--- a/src-slowcord/login/tsconfig.json
+++ b/src-slowcord/login/tsconfig.json
@@ -1,10 +1,6 @@
 {
-	"exclude": [
-		"node_modules"
-	],
-	"include": [
-		"src/**/*.ts"
-	],
+	"exclude": ["node_modules"],
+	"include": ["src/**/*.ts"],
 	"compilerOptions": {
 		/* Visit https://aka.ms/tsconfig.json to read more about this file */
 		/* Projects */
@@ -15,10 +11,12 @@
 		// "disableSolutionSearching": true,                 /* Opt a project out of multi-project reference checking when editing. */
 		// "disableReferencedProjectLoad": true,             /* Reduce the number of projects loaded automatically by TypeScript. */
 		/* Language and Environment */
-		"target": "ES6", 								/* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
-		"lib": ["ES2021"],                                        /* Specify a set of bundled library declaration files that describe the target runtime environment. */
+		"target": "ES6" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
+		"lib": [
+			"ES2021"
+		] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,
 		// "jsx": "preserve",                                /* Specify what JSX code is generated. */
-		"experimentalDecorators": true,                   /* Enable experimental support for TC39 stage 2 draft decorators. */
+		"experimentalDecorators": true /* Enable experimental support for TC39 stage 2 draft decorators. */,
 		// "emitDecoratorMetadata": true,                    /* Emit design-type metadata for decorated declarations in source files. */
 		// "jsxFactory": "",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
 		// "jsxFragmentFactory": "",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
@@ -27,14 +25,16 @@
 		// "noLib": true,                                    /* Disable including any library files, including the default lib.d.ts. */
 		// "useDefineForClassFields": true,                  /* Emit ECMAScript-standard-compliant class fields. */
 		/* Modules */
-		"module": "ES2020", 								/* Specify what module code is generated. */
+		"module": "ES2020" /* Specify what module code is generated. */,
 		// "rootDir": "./",                                  /* Specify the root folder within your source files. */
-		"moduleResolution": "node",                       /* Specify how TypeScript looks up a file from a given module specifier. */
+		"moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */,
 		// "baseUrl": "./",                                  /* Specify the base directory to resolve non-relative module names. */
 		// "paths": {},                                      /* Specify a set of entries that re-map imports to additional lookup locations. */
 		// "rootDirs": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */
 		// "typeRoots": [],                                  /* Specify multiple folders that act like `./node_modules/@types`. */
-		"types": ["node"],                                      /* Specify type package names to be included without being referenced in a source file. */
+		"types": [
+			"node"
+		] /* Specify type package names to be included without being referenced in a source file. */,
 		// "allowUmdGlobalAccess": true,                     /* Allow accessing UMD globals from modules. */
 		// "resolveJsonModule": true,                        /* Enable importing .json files */
 		// "noResolve": true,                                /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
@@ -46,9 +46,9 @@
 		// "declaration": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
 		// "declarationMap": true,                           /* Create sourcemaps for d.ts files. */
 		// "emitDeclarationOnly": true,                      /* Only output d.ts files and not JavaScript files. */
-		"sourceMap": true,                                /* Create source map files for emitted JavaScript files. */
+		"sourceMap": true /* Create source map files for emitted JavaScript files. */,
 		// "outFile": "./",                                  /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
-		"outDir": "./build",                                   /* Specify an output folder for all emitted files. */
+		"outDir": "./build" /* Specify an output folder for all emitted files. */,
 		// "removeComments": true,                           /* Disable emitting comments. */
 		// "noEmit": true,                                   /* Disable emitting files from a compilation. */
 		// "importHelpers": true,                            /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
@@ -69,16 +69,16 @@
 		/* Interop Constraints */
 		// "isolatedModules": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */
 		// "allowSyntheticDefaultImports": true,             /* Allow 'import x from y' when a module doesn't have a default export. */
-		"esModuleInterop": true, 							 /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
+		"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */,
 		// "preserveSymlinks": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
-		"forceConsistentCasingInFileNames": true, 			 /* Ensure that casing is correct in imports. */
+		"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
 		/* Type Checking */
-		"strict": true, 									 /* Enable all strict type-checking options. */
+		"strict": true /* Enable all strict type-checking options. */,
 		// "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied `any` type.. */
 		// "strictNullChecks": true,                         /* When type checking, take into account `null` and `undefined`. */
 		// "strictFunctionTypes": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
 		// "strictBindCallApply": true,                      /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
-		"strictPropertyInitialization": false,             /* Check for class properties that are declared but not set in the constructor. */
+		"strictPropertyInitialization": false /* Check for class properties that are declared but not set in the constructor. */,
 		// "noImplicitThis": true,                           /* Enable error reporting when `this` is given the type `any`. */
 		// "useUnknownInCatchVariables": true,               /* Type catch clause variables as 'unknown' instead of 'any'. */
 		// "alwaysStrict": true,                             /* Ensure 'use strict' is always emitted. */
@@ -94,6 +94,6 @@
 		// "allowUnreachableCode": true,                     /* Disable error reporting for unreachable code. */
 		/* Completeness */
 		// "skipDefaultLibCheck": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */
-		"skipLibCheck": true								 /* Skip type checking all .d.ts files. */
+		"skipLibCheck": true /* Skip type checking all .d.ts files. */
 	}
-}
\ No newline at end of file
+}
diff --git a/src-slowcord/rules.md b/src-slowcord/rules.md
index ffae0846..1097060a 100644
--- a/src-slowcord/rules.md
+++ b/src-slowcord/rules.md
@@ -3,11 +3,12 @@
 Slowcord is a heavily modded Fosscord instance. You can browse it's source here: https://github.com/MaddyUnderStars/fosscord-server/tree/slowcord
 
 ## Here are some general instance-wide rules:
-* **Harassment, homophobia, transphobia, etc, violence, and hate speech are forbidden.**
-* Behaviour that harms the service - be it malicious/intentional or not - is strictly forbidden. This may include API abuse/spam, exploits, etc.
-* * If you do discover an exploit/bug, it would be greatly appreciated if you could create an issue in the above repo, or DM @MaddyUnderStars#0000. 
-* Any content that would be considered illegal in Australia is also forbidden. Additionally, if it is illegal in your own country, it shouldn't be here.
-* Bots/selfbots are allowed. If you would like an account to be given bot status, DM @MaddyUnderStars#0000.
+
+-   **Harassment, homophobia, transphobia, etc, violence, and hate speech are forbidden.**
+-   Behaviour that harms the service - be it malicious/intentional or not - is strictly forbidden. This may include API abuse/spam, exploits, etc.
+-   -   If you do discover an exploit/bug, it would be greatly appreciated if you could create an issue in the above repo, or DM @MaddyUnderStars#0000.
+-   Any content that would be considered illegal in Australia is also forbidden. Additionally, if it is illegal in your own country, it shouldn't be here.
+-   Bots/selfbots are allowed. If you would like an account to be given bot status, DM @MaddyUnderStars#0000.
 
 These rules are non-exhaustive, but should give a good idea of what will be enforced.
 
@@ -16,5 +17,6 @@ Permanent Slowcord guild invite: https://slowcord.understars.dev/invite/slowcord
 ### If a message or user breaks these rules, you can report it here: https://forms.gle/sd6RkdM7gRgJLV368
 
 #### Lastly ( and not rules ):
-* If you use BetterDiscord or Powercord, and want an easier time accessing Slowcord and other Fosscord instances, check out https://github.com/maddyunderstars/fosscord-bd!
-* Also, if you're on Android, you can download the mobile client at https://slowcord.understars.dev/assets/slowcord.apk
+
+-   If you use BetterDiscord or Powercord, and want an easier time accessing Slowcord and other Fosscord instances, check out https://github.com/maddyunderstars/fosscord-bd!
+-   Also, if you're on Android, you can download the mobile client at https://slowcord.understars.dev/assets/slowcord.apk
diff --git a/src-slowcord/status/src/gateway.ts b/src-slowcord/status/src/gateway.ts
index 14944d09..bc00c2d4 100644
--- a/src-slowcord/status/src/gateway.ts
+++ b/src-slowcord/status/src/gateway.ts
@@ -5,14 +5,22 @@ import mysql from "mysql2";
 import fetch from "node-fetch";
 
 const dbConn = mysql.createConnection(process.env.DATABASE as string);
-const executePromise = (sql: string, args: any[]) => new Promise((resolve, reject) => dbConn.execute(sql, args, (err, res) => { if (err) reject(err); else resolve(res); }));
+const executePromise = (sql: string, args: any[]) =>
+	new Promise((resolve, reject) =>
+		dbConn.execute(sql, args, (err, res) => {
+			if (err) reject(err);
+			else resolve(res);
+		}),
+	);
 const savePerf = async (time: number, name: string, error?: string | Error) => {
 	if (error && typeof error != "string") error = error.message;
 	try {
-		await executePromise("INSERT INTO performance (value, endpoint, timestamp, error) VALUES (?, ?, ?, ?)", [time ?? 0, name, new Date(), error ?? null]);
+		await executePromise(
+			"INSERT INTO performance (value, endpoint, timestamp, error) VALUES (?, ?, ?, ?)",
+			[time ?? 0, name, new Date(), error ?? null],
+		);
 		// await executePromise("DELETE FROM performance WHERE DATE(timestamp) < now() - interval ? DAY", [process.env.RETENTION_DAYS]);
-	}
-	catch (e) {
+	} catch (e) {
 		console.error(e);
 	}
 };
@@ -23,7 +31,11 @@ const doMeasurements = async (channel: Discord.TextChannel) => {
 	timestamp = Date.now();
 	await channel.send("hello this is a special message kthxbye");
 
-	setTimeout(doMeasurements, parseInt(process.env.MEASURE_INTERVAL as string), channel);
+	setTimeout(
+		doMeasurements,
+		parseInt(process.env.MEASURE_INTERVAL as string),
+		channel,
+	);
 };
 
 const instance = {
@@ -37,8 +49,8 @@ const client = new Fosscord.Client({
 	intents: [],
 	http: {
 		api: instance.api,
-		cdn: instance.cdn
-	}
+		cdn: instance.cdn,
+	},
 });
 
 client.on("ready", async () => {
@@ -52,19 +64,24 @@ client.on("ready", async () => {
 
 client.on("messageCreate", async (msg: Discord.Message) => {
 	if (!timestamp) return;
-	if (msg.author.id != "992745947417141682"
-		|| msg.channel.id != "1019955729054267764"
-		|| msg.content != "hello this is a special message kthxbye")
+	if (
+		msg.author.id != "992745947417141682" ||
+		msg.channel.id != "1019955729054267764" ||
+		msg.content != "hello this is a special message kthxbye"
+	)
 		return;
 	await savePerf(Date.now() - timestamp, "messageCreate", undefined);
 	timestamp = undefined;
 
-	await fetch(`${instance.api}/channels/1019955729054267764/messages/${msg.id}`, {
-		method: "DELETE",
-		headers: {
-			authorization: instance.token
-		}
-	})
+	await fetch(
+		`${instance.api}/channels/1019955729054267764/messages/${msg.id}`,
+		{
+			method: "DELETE",
+			headers: {
+				authorization: instance.token,
+			},
+		},
+	);
 });
 
 client.on("error", (error: any) => {
@@ -79,4 +96,4 @@ client.on("warn", (msg: any) => {
 	await new Promise((resolve) => dbConn.connect(resolve));
 	console.log("Connected to db");
 	await client.login(instance.token);
-})();
\ No newline at end of file
+})();
diff --git a/src-slowcord/status/src/index.ts b/src-slowcord/status/src/index.ts
index 735b8a9b..979469b6 100644
--- a/src-slowcord/status/src/index.ts
+++ b/src-slowcord/status/src/index.ts
@@ -4,7 +4,13 @@ import mysql from "mysql2";
 import fetch from "node-fetch";
 
 const dbConn = mysql.createConnection(process.env.DATABASE as string);
-const executePromise = (sql: string, args: any[]) => new Promise((resolve, reject) => dbConn.execute(sql, args, (err, res) => { if (err) reject(err); else resolve(res); }));
+const executePromise = (sql: string, args: any[]) =>
+	new Promise((resolve, reject) =>
+		dbConn.execute(sql, args, (err, res) => {
+			if (err) reject(err);
+			else resolve(res);
+		}),
+	);
 
 const instance = {
 	app: process.env.INSTANCE_WEB_APP as string,
@@ -16,73 +22,86 @@ const instance = {
 const savePerf = async (time: number, name: string, error?: string | Error) => {
 	if (error && typeof error != "string") error = error.message;
 	try {
-		await executePromise("INSERT INTO performance (value, endpoint, timestamp, error) VALUES (?, ?, ?, ?)", [time ?? 0, name, new Date(), error ?? null]);
+		await executePromise(
+			"INSERT INTO performance (value, endpoint, timestamp, error) VALUES (?, ?, ?, ?)",
+			[time ?? 0, name, new Date(), error ?? null],
+		);
 		// await executePromise("DELETE FROM performance WHERE DATE(timestamp) < now() - interval ? DAY", [process.env.RETENTION_DAYS]);
-	}
-	catch (e) {
+	} catch (e) {
 		console.error(e);
 	}
 };
 
-const saveSystemUsage = async (load: number, procUptime: number, sysUptime: number, ram: number, sessions: number) => {
+const saveSystemUsage = async (
+	load: number,
+	procUptime: number,
+	sysUptime: number,
+	ram: number,
+	sessions: number,
+) => {
 	try {
-		await executePromise("INSERT INTO monitor (time, cpu, procUp, sysUp, ram, sessions) VALUES (?, ?, ?, ?, ?, ?)", [new Date(), load, procUptime, sysUptime, ram, sessions]);
-	}
-	catch (e) {
+		await executePromise(
+			"INSERT INTO monitor (time, cpu, procUp, sysUp, ram, sessions) VALUES (?, ?, ?, ?, ?, ?)",
+			[new Date(), load, procUptime, sysUptime, ram, sessions],
+		);
+	} catch (e) {
 		console.error(e);
 	}
 };
 
-const makeTimedRequest = (path: string, body?: object): Promise<number> => new Promise((resolve, reject) => {
-	const opts = {
-		hostname: new URL(path).hostname,
-		port: 443,
-		path: new URL(path).pathname,
-		method: "GET",
-		headers: {
-			"Content-Type": "application/json",
-			"Authorization": instance.token,
-		},
-		timeout: 1000,
-	};
-
-	let start: number, end: number;
-	const req = https.request(opts, res => {
-		if (res.statusCode! < 200 || res.statusCode! > 300) {
-			return reject(`${res.statusCode} ${res.statusMessage}`);
-		}
-
-		res.on("data", (data) => {
+const makeTimedRequest = (path: string, body?: object): Promise<number> =>
+	new Promise((resolve, reject) => {
+		const opts = {
+			hostname: new URL(path).hostname,
+			port: 443,
+			path: new URL(path).pathname,
+			method: "GET",
+			headers: {
+				"Content-Type": "application/json",
+				Authorization: instance.token,
+			},
+			timeout: 1000,
+		};
+
+		let start: number, end: number;
+		const req = https.request(opts, (res) => {
+			if (res.statusCode! < 200 || res.statusCode! > 300) {
+				return reject(`${res.statusCode} ${res.statusMessage}`);
+			}
+
+			res.on("data", (data) => {});
+
+			res.on("end", () => {
+				end = Date.now();
+				resolve(end - start);
+			});
 		});
 
-		res.on("end", () => {
-			end = Date.now();
-			resolve(end - start);
+		req.on("finish", () => {
+			if (body) req.write(JSON.stringify(body));
+			start = Date.now();
 		});
-	});
 
-	req.on("finish", () => {
-		if (body) req.write(JSON.stringify(body));
-		start = Date.now();
-	});
+		req.on("error", (error) => {
+			reject(error);
+		});
 
-	req.on("error", (error) => {
-		reject(error);
+		req.end();
 	});
 
-	req.end();
-});
-
 const measureApi = async (name: string, path: string, body?: object) => {
-	let error, time = -1;
+	let error,
+		time = -1;
 	try {
 		time = await makeTimedRequest(path, body);
-	}
-	catch (e) {
+	} catch (e) {
 		error = e as Error | string;
 	}
 
-	console.log(`${name} took ${time}ms ${(error ? "with error" : "")}`, error ?? "");
+	console.log(
+		`${name} took ${time}ms ${error ? "with error" : ""}`,
+		error ?? "",
+	);
 
 	await savePerf(time, name, error);
 };
@@ -100,7 +119,11 @@ const app = async () => {
 	console.log("Connected to db");
 	// await client.login(instance.token);
 
-	console.log(`Monitoring performance for instance at ${new URL(instance.api).hostname}`);
+	console.log(
+		`Monitoring performance for instance at ${
+			new URL(instance.api).hostname
+		}`,
+	);
 
 	const doMeasurements = async () => {
 		await measureApi("ping", `${instance.api}/ping`);
@@ -112,18 +135,25 @@ const app = async () => {
 			const res = await fetch(`${instance.api}/-/monitorz`, {
 				headers: {
 					Authorization: process.env.INSTANCE_TOKEN as string,
-				}
+				},
 			});
-			const json = await res.json() as monitorzSchema;
-			await saveSystemUsage(json.load[1], json.procUptime, json.sysUptime, json.memPercent, json.sessions);
-		}
-		catch (e) {
-		}
-
-		setTimeout(doMeasurements, parseInt(process.env.MEASURE_INTERVAL as string));
+			const json = (await res.json()) as monitorzSchema;
+			await saveSystemUsage(
+				json.load[1],
+				json.procUptime,
+				json.sysUptime,
+				json.memPercent,
+				json.sessions,
+			);
+		} catch (e) {}
+
+		setTimeout(
+			doMeasurements,
+			parseInt(process.env.MEASURE_INTERVAL as string),
+		);
 	};
 
 	doMeasurements();
 };
 
-app();
\ No newline at end of file
+app();
diff --git a/src-slowcord/status/tsconfig.json b/src-slowcord/status/tsconfig.json
index 6d6ec56d..4d96714c 100644
--- a/src-slowcord/status/tsconfig.json
+++ b/src-slowcord/status/tsconfig.json
@@ -1,10 +1,6 @@
 {
-	"exclude": [
-		"node_modules"
-	],
-	"include": [
-		"src/**/*.ts"
-	],
+	"exclude": ["node_modules"],
+	"include": ["src/**/*.ts"],
 	"compilerOptions": {
 		/* Visit https://aka.ms/tsconfig.json to read more about this file */
 		/* Projects */
@@ -15,10 +11,12 @@
 		// "disableSolutionSearching": true,                 /* Opt a project out of multi-project reference checking when editing. */
 		// "disableReferencedProjectLoad": true,             /* Reduce the number of projects loaded automatically by TypeScript. */
 		/* Language and Environment */
-		"target": "ES6", 								 /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
-		"lib": ["ES2021"],                                        /* Specify a set of bundled library declaration files that describe the target runtime environment. */
+		"target": "ES6" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
+		"lib": [
+			"ES2021"
+		] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,
 		// "jsx": "preserve",                                /* Specify what JSX code is generated. */
-		"experimentalDecorators": true,                   /* Enable experimental support for TC39 stage 2 draft decorators. */
+		"experimentalDecorators": true /* Enable experimental support for TC39 stage 2 draft decorators. */,
 		// "emitDecoratorMetadata": true,                    /* Emit design-type metadata for decorated declarations in source files. */
 		// "jsxFactory": "",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
 		// "jsxFragmentFactory": "",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
@@ -27,14 +25,16 @@
 		// "noLib": true,                                    /* Disable including any library files, including the default lib.d.ts. */
 		// "useDefineForClassFields": true,                  /* Emit ECMAScript-standard-compliant class fields. */
 		/* Modules */
-		"module": "ES2020", 								 /* Specify what module code is generated. */
+		"module": "ES2020" /* Specify what module code is generated. */,
 		// "rootDir": "./",                                  /* Specify the root folder within your source files. */
-		"moduleResolution": "node",                       /* Specify how TypeScript looks up a file from a given module specifier. */
+		"moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */,
 		// "baseUrl": "./",                                  /* Specify the base directory to resolve non-relative module names. */
 		// "paths": {},                                      /* Specify a set of entries that re-map imports to additional lookup locations. */
 		// "rootDirs": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */
 		// "typeRoots": [],                                  /* Specify multiple folders that act like `./node_modules/@types`. */
-		"types": ["node"],                                      /* Specify type package names to be included without being referenced in a source file. */
+		"types": [
+			"node"
+		] /* Specify type package names to be included without being referenced in a source file. */,
 		// "allowUmdGlobalAccess": true,                     /* Allow accessing UMD globals from modules. */
 		// "resolveJsonModule": true,                        /* Enable importing .json files */
 		// "noResolve": true,                                /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
@@ -46,9 +46,9 @@
 		// "declaration": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
 		// "declarationMap": true,                           /* Create sourcemaps for d.ts files. */
 		// "emitDeclarationOnly": true,                      /* Only output d.ts files and not JavaScript files. */
-		"sourceMap": true,                                /* Create source map files for emitted JavaScript files. */
+		"sourceMap": true /* Create source map files for emitted JavaScript files. */,
 		// "outFile": "./",                                  /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
-		"outDir": "./build",                                   /* Specify an output folder for all emitted files. */
+		"outDir": "./build" /* Specify an output folder for all emitted files. */,
 		// "removeComments": true,                           /* Disable emitting comments. */
 		// "noEmit": true,                                   /* Disable emitting files from a compilation. */
 		// "importHelpers": true,                            /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
@@ -69,16 +69,16 @@
 		/* Interop Constraints */
 		// "isolatedModules": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */
 		// "allowSyntheticDefaultImports": true,             /* Allow 'import x from y' when a module doesn't have a default export. */
-		"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
+		"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */,
 		// "preserveSymlinks": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
-		"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
+		"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
 		/* Type Checking */
-		"strict": true, /* Enable all strict type-checking options. */
+		"strict": true /* Enable all strict type-checking options. */,
 		// "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied `any` type.. */
 		// "strictNullChecks": true,                         /* When type checking, take into account `null` and `undefined`. */
 		// "strictFunctionTypes": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
 		// "strictBindCallApply": true,                      /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
-		"strictPropertyInitialization": false,               /* Check for class properties that are declared but not set in the constructor. */
+		"strictPropertyInitialization": false /* Check for class properties that are declared but not set in the constructor. */,
 		// "noImplicitThis": true,                           /* Enable error reporting when `this` is given the type `any`. */
 		// "useUnknownInCatchVariables": true,               /* Type catch clause variables as 'unknown' instead of 'any'. */
 		// "alwaysStrict": true,                             /* Ensure 'use strict' is always emitted. */
@@ -96,4 +96,4 @@
 		// "skipDefaultLibCheck": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */
 		"skipLibCheck": true /* Skip type checking all .d.ts files. */
 	}
-}
\ No newline at end of file
+}
diff --git a/src/api/Server.ts b/src/api/Server.ts
index 4cf0917d..bd9bc4b9 100644
--- a/src/api/Server.ts
+++ b/src/api/Server.ts
@@ -12,7 +12,7 @@ import { initTranslation } from "./middlewares/Translation";
 import morgan from "morgan";
 import { initInstance } from "./util/handlers/Instance";
 import { registerRoutes } from "@fosscord/util";
-import { red } from "picocolors"
+import { red } from "picocolors";
 
 export interface FosscordServerOptions extends ServerOptions {}
 
@@ -44,13 +44,18 @@ export class FosscordServer extends Server {
 			this.app.use(
 				morgan("combined", {
 					skip: (req, res) => {
-						var skip = !(process.env["LOG_REQUESTS"]?.includes(res.statusCode.toString()) ?? false);
-						if (process.env["LOG_REQUESTS"]?.charAt(0) == "-") skip = !skip;
+						var skip = !(
+							process.env["LOG_REQUESTS"]?.includes(
+								res.statusCode.toString(),
+							) ?? false
+						);
+						if (process.env["LOG_REQUESTS"]?.charAt(0) == "-")
+							skip = !skip;
 						return skip;
-					}
-				})
+					},
+				}),
 			);
-		};
+		}
 
 		this.app.use(CORS);
 		this.app.use(BodyParser({ inflate: true, limit: "10mb" }));
@@ -63,16 +68,22 @@ export class FosscordServer extends Server {
 		await initRateLimits(api);
 		await initTranslation(api);
 
-		this.routes = await registerRoutes(this, path.join(__dirname, "routes", "/"));
+		this.routes = await registerRoutes(
+			this,
+			path.join(__dirname, "routes", "/"),
+		);
 
-		api.use("*", (error: any, req: Request, res: Response, next: NextFunction) => {
-			if (error) return next(error);
-			res.status(404).json({
-				message: "404 endpoint not found",
-				code: 0
-			});
-			next();
-		});
+		api.use(
+			"*",
+			(error: any, req: Request, res: Response, next: NextFunction) => {
+				if (error) return next(error);
+				res.status(404).json({
+					message: "404 endpoint not found",
+					code: 0,
+				});
+				next();
+			},
+		);
 
 		this.app = app;
 
@@ -87,8 +98,13 @@ export class FosscordServer extends Server {
 		this.app.use(ErrorHandler);
 		TestClient(this.app);
 
-		if (logRequests) console.log(red(`Warning: Request logging is enabled! This will spam your console!\nTo disable this, unset the 'LOG_REQUESTS' environment variable!`));
-		
+		if (logRequests)
+			console.log(
+				red(
+					`Warning: Request logging is enabled! This will spam your console!\nTo disable this, unset the 'LOG_REQUESTS' environment variable!`,
+				),
+			);
+
 		return super.start();
 	}
-};
\ No newline at end of file
+}
diff --git a/src/api/index.ts b/src/api/index.ts
index 09663452..adc7649c 100644
--- a/src/api/index.ts
+++ b/src/api/index.ts
@@ -1,3 +1,3 @@
 export * from "./Server";
 export * from "./middlewares/";
-export * from "./util/";
\ No newline at end of file
+export * from "./util/";
diff --git a/src/api/middlewares/Authentication.ts b/src/api/middlewares/Authentication.ts
index 1df7911b..50048b12 100644
--- a/src/api/middlewares/Authentication.ts
+++ b/src/api/middlewares/Authentication.ts
@@ -10,7 +10,7 @@ export const NO_AUTHORIZATION_ROUTES = [
 	"/auth/mfa/totp",
 	// Routes with a seperate auth system
 	"/webhooks/",
-	// Public information endpoints 
+	// Public information endpoints
 	"/ping",
 	"/gateway",
 	"/experiments",
@@ -26,7 +26,7 @@ export const NO_AUTHORIZATION_ROUTES = [
 	// Public policy pages
 	"/policies/instance",
 	// Asset delivery
-	/\/guilds\/\d+\/widget\.(json|png)/
+	/\/guilds\/\d+\/widget\.(json|png)/,
 ];
 
 export const API_PREFIX = /^\/api(\/v\d+)?/;
@@ -43,7 +43,11 @@ declare global {
 	}
 }
 
-export async function Authentication(req: Request, res: Response, next: NextFunction) {
+export async function Authentication(
+	req: Request,
+	res: Response,
+	next: NextFunction,
+) {
 	if (req.method === "OPTIONS") return res.sendStatus(204);
 	const url = req.url.replace(API_PREFIX, "");
 	if (url.startsWith("/invites") && req.method === "GET") return next();
@@ -54,12 +58,16 @@ export async function Authentication(req: Request, res: Response, next: NextFunc
 		})
 	)
 		return next();
-	if (!req.headers.authorization) return next(new HTTPError("Missing Authorization Header", 401));
+	if (!req.headers.authorization)
+		return next(new HTTPError("Missing Authorization Header", 401));
 
 	try {
 		const { jwtSecret } = Config.get().security;
 
-		const { decoded, user }: any = await checkToken(req.headers.authorization, jwtSecret);
+		const { decoded, user }: any = await checkToken(
+			req.headers.authorization,
+			jwtSecret,
+		);
 
 		req.token = decoded;
 		req.user_id = decoded.id;
diff --git a/src/api/middlewares/BodyParser.ts b/src/api/middlewares/BodyParser.ts
index 4cb376bc..7741f1fd 100644
--- a/src/api/middlewares/BodyParser.ts
+++ b/src/api/middlewares/BodyParser.ts
@@ -6,7 +6,8 @@ export function BodyParser(opts?: OptionsJson) {
 	const jsonParser = bodyParser.json(opts);
 
 	return (req: Request, res: Response, next: NextFunction) => {
-		if (!req.headers["content-type"]) req.headers["content-type"] = "application/json";
+		if (!req.headers["content-type"])
+			req.headers["content-type"] = "application/json";
 
 		jsonParser(req, res, (err) => {
 			if (err) {
diff --git a/src/api/middlewares/CORS.ts b/src/api/middlewares/CORS.ts
index 20260cf9..2dce51c6 100644
--- a/src/api/middlewares/CORS.ts
+++ b/src/api/middlewares/CORS.ts
@@ -7,10 +7,16 @@ export function CORS(req: Request, res: Response, next: NextFunction) {
 	// TODO: use better CSP
 	res.set(
 		"Content-security-policy",
-		"default-src *  data: blob: filesystem: about: ws: wss: 'unsafe-inline' 'unsafe-eval'; script-src * data: blob: 'unsafe-inline' 'unsafe-eval'; connect-src * data: blob: 'unsafe-inline'; img-src * data: blob: 'unsafe-inline'; frame-src * data: blob: ; style-src * data: blob: 'unsafe-inline'; font-src * data: blob: 'unsafe-inline';"
+		"default-src *  data: blob: filesystem: about: ws: wss: 'unsafe-inline' 'unsafe-eval'; script-src * data: blob: 'unsafe-inline' 'unsafe-eval'; connect-src * data: blob: 'unsafe-inline'; img-src * data: blob: 'unsafe-inline'; frame-src * data: blob: ; style-src * data: blob: 'unsafe-inline'; font-src * data: blob: 'unsafe-inline';",
+	);
+	res.set(
+		"Access-Control-Allow-Headers",
+		req.header("Access-Control-Request-Headers") || "*",
+	);
+	res.set(
+		"Access-Control-Allow-Methods",
+		req.header("Access-Control-Request-Methods") || "*",
 	);
-	res.set("Access-Control-Allow-Headers", req.header("Access-Control-Request-Headers") || "*");
-	res.set("Access-Control-Allow-Methods", req.header("Access-Control-Request-Methods") || "*");
 
 	next();
 }
diff --git a/src/api/middlewares/ErrorHandler.ts b/src/api/middlewares/ErrorHandler.ts
index 2012b91c..bf3b011a 100644
--- a/src/api/middlewares/ErrorHandler.ts
+++ b/src/api/middlewares/ErrorHandler.ts
@@ -3,7 +3,12 @@ import { HTTPError } from "lambert-server";
 import { ApiError, FieldError } from "@fosscord/util";
 const EntityNotFoundErrorRegex = /"(\w+)"/;
 
-export function ErrorHandler(error: Error, req: Request, res: Response, next: NextFunction) {
+export function ErrorHandler(
+	error: Error,
+	req: Request,
+	res: Response,
+	next: NextFunction,
+) {
 	if (!error) return next();
 
 	try {
@@ -12,20 +17,28 @@ export function ErrorHandler(error: Error, req: Request, res: Response, next: Ne
 		let message = error?.toString();
 		let errors = undefined;
 
-		if (error instanceof HTTPError && error.code) code = httpcode = error.code;
+		if (error instanceof HTTPError && error.code)
+			code = httpcode = error.code;
 		else if (error instanceof ApiError) {
 			code = error.code;
 			message = error.message;
 			httpcode = error.httpStatus;
 		} else if (error.name === "EntityNotFoundError") {
-			message = `${error.message.match(EntityNotFoundErrorRegex)?.[1] || "Item"} could not be found`;
+			message = `${
+				error.message.match(EntityNotFoundErrorRegex)?.[1] || "Item"
+			} could not be found`;
 			code = httpcode = 404;
 		} else if (error instanceof FieldError) {
 			code = Number(error.code);
 			message = error.message;
 			errors = error.errors;
 		} else {
-			console.error(`[Error] ${code} ${req.url}\n`, errors || error, "\nbody:", req.body);
+			console.error(
+				`[Error] ${code} ${req.url}\n`,
+				errors || error,
+				"\nbody:",
+				req.body,
+			);
 
 			if (req.server?.options?.production) {
 				// don't expose internal errors to the user, instead human errors should be thrown as HTTPError
@@ -39,6 +52,8 @@ export function ErrorHandler(error: Error, req: Request, res: Response, next: Ne
 		res.status(httpcode).json({ code: code, message, errors });
 	} catch (error) {
 		console.error(`[Internal Server Error] 500`, error);
-		return res.status(500).json({ code: 500, message: "Internal Server Error" });
+		return res
+			.status(500)
+			.json({ code: 500, message: "Internal Server Error" });
 	}
 }
diff --git a/src/api/middlewares/RateLimit.ts b/src/api/middlewares/RateLimit.ts
index 57645c0b..b3976a16 100644
--- a/src/api/middlewares/RateLimit.ts
+++ b/src/api/middlewares/RateLimit.ts
@@ -40,21 +40,32 @@ export default function rateLimit(opts: {
 	success?: boolean;
 	onlyIp?: boolean;
 }): any {
-	return async (req: Request, res: Response, next: NextFunction): Promise<any> => {
+	return async (
+		req: Request,
+		res: Response,
+		next: NextFunction,
+	): Promise<any> => {
 		// exempt user? if so, immediately short circuit
 		if (req.user_id) {
 			const rights = await getRights(req.user_id);
 			if (rights.has("BYPASS_RATE_LIMITS")) return next();
 		}
 
-		const bucket_id = opts.bucket || req.originalUrl.replace(API_PREFIX_TRAILING_SLASH, "");
+		const bucket_id =
+			opts.bucket ||
+			req.originalUrl.replace(API_PREFIX_TRAILING_SLASH, "");
 		let executor_id = getIpAdress(req);
 		if (!opts.onlyIp && req.user_id) executor_id = req.user_id;
 
 		let max_hits = opts.count;
 		if (opts.bot && req.user_bot) max_hits = opts.bot;
-		if (opts.GET && ["GET", "OPTIONS", "HEAD"].includes(req.method)) max_hits = opts.GET;
-		else if (opts.MODIFY && ["POST", "DELETE", "PATCH", "PUT"].includes(req.method)) max_hits = opts.MODIFY;
+		if (opts.GET && ["GET", "OPTIONS", "HEAD"].includes(req.method))
+			max_hits = opts.GET;
+		else if (
+			opts.MODIFY &&
+			["POST", "DELETE", "PATCH", "PUT"].includes(req.method)
+		)
+			max_hits = opts.MODIFY;
 
 		let offender = Cache.get(executor_id + bucket_id);
 
@@ -75,11 +86,15 @@ export default function rateLimit(opts: {
 				const global = bucket_id === "global";
 				// each block violation pushes the expiry one full window further
 				reset += opts.window * 1000;
-				offender.expires_at = new Date(offender.expires_at.getTime() + opts.window * 1000);
+				offender.expires_at = new Date(
+					offender.expires_at.getTime() + opts.window * 1000,
+				);
 				resetAfterMs = reset - Date.now();
 				resetAfterSec = Math.ceil(resetAfterMs / 1000);
 
-				console.log(`blocked bucket: ${bucket_id} ${executor_id}`, { resetAfterMs });
+				console.log(`blocked bucket: ${bucket_id} ${executor_id}`, {
+					resetAfterMs,
+				});
 				return (
 					res
 						.status(429)
@@ -91,20 +106,33 @@ export default function rateLimit(opts: {
 						.set("Retry-After", `${Math.ceil(resetAfterSec)}`)
 						.set("X-RateLimit-Bucket", `${bucket_id}`)
 						// TODO: error rate limit message translation
-						.send({ message: "You are being rate limited.", retry_after: resetAfterSec, global })
+						.send({
+							message: "You are being rate limited.",
+							retry_after: resetAfterSec,
+							global,
+						})
 				);
 			}
 		}
 
 		next();
-		const hitRouteOpts = { bucket_id, executor_id, max_hits, window: opts.window };
+		const hitRouteOpts = {
+			bucket_id,
+			executor_id,
+			max_hits,
+			window: opts.window,
+		};
 
 		if (opts.error || opts.success) {
 			res.once("finish", () => {
 				// check if error and increment error rate limit
 				if (res.statusCode >= 400 && opts.error) {
 					return hitRoute(hitRouteOpts);
-				} else if (res.statusCode >= 200 && res.statusCode < 300 && opts.success) {
+				} else if (
+					res.statusCode >= 200 &&
+					res.statusCode < 300 &&
+					opts.success
+				) {
 					return hitRoute(hitRouteOpts);
 				}
 			});
@@ -141,8 +169,8 @@ export async function initRateLimits(app: Router) {
 		rateLimit({
 			bucket: "global",
 			onlyIp: true,
-			...ip
-		})
+			...ip,
+		}),
 	);
 	app.use(rateLimit({ bucket: "global", ...global }));
 	app.use(
@@ -150,17 +178,25 @@ export async function initRateLimits(app: Router) {
 			bucket: "error",
 			error: true,
 			onlyIp: true,
-			...error
-		})
+			...error,
+		}),
 	);
 	app.use("/guilds/:id", rateLimit(routes.guild));
 	app.use("/webhooks/:id", rateLimit(routes.webhook));
 	app.use("/channels/:id", rateLimit(routes.channel));
 	app.use("/auth/login", rateLimit(routes.auth.login));
-	app.use("/auth/register", rateLimit({ onlyIp: true, success: true, ...routes.auth.register }));
+	app.use(
+		"/auth/register",
+		rateLimit({ onlyIp: true, success: true, ...routes.auth.register }),
+	);
 }
 
-async function hitRoute(opts: { executor_id: string; bucket_id: string; max_hits: number; window: number; }) {
+async function hitRoute(opts: {
+	executor_id: string;
+	bucket_id: string;
+	max_hits: number;
+	window: number;
+}) {
 	const id = opts.executor_id + opts.bucket_id;
 	let limit = Cache.get(id);
 	if (!limit) {
@@ -169,7 +205,7 @@ async function hitRoute(opts: { executor_id: string; bucket_id: string; max_hits
 			executor_id: opts.executor_id,
 			expires_at: new Date(Date.now() + opts.window * 1000),
 			hits: 0,
-			blocked: false
+			blocked: false,
 		};
 		Cache.set(id, limit);
 	}
@@ -205,4 +241,4 @@ async function hitRoute(opts: { executor_id: string; bucket_id: string; max_hits
 	}
 	await ratelimit.save();
 	*/
-}
\ No newline at end of file
+}
diff --git a/src/api/middlewares/Translation.ts b/src/api/middlewares/Translation.ts
index c0b7a4b8..05038040 100644
--- a/src/api/middlewares/Translation.ts
+++ b/src/api/middlewares/Translation.ts
@@ -9,8 +9,12 @@ const ASSET_FOLDER_PATH = path.join(__dirname, "..", "..", "..", "assets");
 
 export async function initTranslation(router: Router) {
 	const languages = fs.readdirSync(path.join(ASSET_FOLDER_PATH, "locales"));
-	const namespaces = fs.readdirSync(path.join(ASSET_FOLDER_PATH, "locales", "en"));
-	const ns = namespaces.filter((x) => x.endsWith(".json")).map((x) => x.slice(0, x.length - 5));
+	const namespaces = fs.readdirSync(
+		path.join(ASSET_FOLDER_PATH, "locales", "en"),
+	);
+	const ns = namespaces
+		.filter((x) => x.endsWith(".json"))
+		.map((x) => x.slice(0, x.length - 5));
 
 	await i18next
 		.use(i18nextBackend)
@@ -21,9 +25,11 @@ export async function initTranslation(router: Router) {
 			fallbackLng: "en",
 			ns,
 			backend: {
-				loadPath:  path.join(ASSET_FOLDER_PATH, "locales") + "/{{lng}}/{{ns}}.json",
+				loadPath:
+					path.join(ASSET_FOLDER_PATH, "locales") +
+					"/{{lng}}/{{ns}}.json",
 			},
-			load: "all"
+			load: "all",
 		});
 
 	router.use(i18nextMiddleware.handle(i18next, {}));
diff --git a/src/api/routes/-/monitorz.ts b/src/api/routes/-/monitorz.ts
index f85cd099..630a832b 100644
--- a/src/api/routes/-/monitorz.ts
+++ b/src/api/routes/-/monitorz.ts
@@ -5,14 +5,18 @@ import os from "os";
 
 const router = Router();
 
-router.get("/", route({ right: "OPERATOR" }), async (req: Request, res: Response) => {
-	return res.json({
-		load: os.loadavg(),
-		procUptime: process.uptime(),
-		sysUptime: os.uptime(),
-		memPercent: 100 - ((os.freemem() / os.totalmem()) * 100),
-		sessions: await Session.count(),
-	})
-})
+router.get(
+	"/",
+	route({ right: "OPERATOR" }),
+	async (req: Request, res: Response) => {
+		return res.json({
+			load: os.loadavg(),
+			procUptime: process.uptime(),
+			sysUptime: os.uptime(),
+			memPercent: 100 - (os.freemem() / os.totalmem()) * 100,
+			sessions: await Session.count(),
+		});
+	},
+);
 
-export default router;
\ No newline at end of file
+export default router;
diff --git a/src/api/routes/auth/location-metadata.ts b/src/api/routes/auth/location-metadata.ts
index f4c2bd16..0ae946ed 100644
--- a/src/api/routes/auth/location-metadata.ts
+++ b/src/api/routes/auth/location-metadata.ts
@@ -3,11 +3,15 @@ import { route } from "@fosscord/api";
 import { getIpAdress, IPAnalysis } from "@fosscord/api";
 const router = Router();
 
-router.get("/",route({}), async (req: Request, res: Response) => {
-    //TODO
-    //Note: It's most likely related to legal. At the moment Discord hasn't finished this too
-    const country_code = (await IPAnalysis(getIpAdress(req))).country_code;
-	res.json({ consent_required: false, country_code: country_code, promotional_email_opt_in: { required: true, pre_checked: false}});
+router.get("/", route({}), async (req: Request, res: Response) => {
+	//TODO
+	//Note: It's most likely related to legal. At the moment Discord hasn't finished this too
+	const country_code = (await IPAnalysis(getIpAdress(req))).country_code;
+	res.json({
+		consent_required: false,
+		country_code: country_code,
+		promotional_email_opt_in: { required: true, pre_checked: false },
+	});
 });
 
 export default router;
diff --git a/src/api/routes/auth/login.ts b/src/api/routes/auth/login.ts
index 9bed5aab..9ea2606c 100644
--- a/src/api/routes/auth/login.ts
+++ b/src/api/routes/auth/login.ts
@@ -1,84 +1,127 @@
 import { Request, Response, Router } from "express";
 import { route, getIpAdress, verifyCaptcha } from "@fosscord/api";
 import bcrypt from "bcrypt";
-import { Config, User, generateToken, adjustEmail, FieldErrors, LoginSchema } from "@fosscord/util";
+import {
+	Config,
+	User,
+	generateToken,
+	adjustEmail,
+	FieldErrors,
+	LoginSchema,
+} from "@fosscord/util";
 import crypto from "crypto";
 
 const router: Router = Router();
 export default router;
 
-router.post("/", route({ body: "LoginSchema" }), async (req: Request, res: Response) => {
-	const { login, password, captcha_key, undelete } = req.body as LoginSchema;
-	const email = adjustEmail(login);
-	console.log("login", email);
+router.post(
+	"/",
+	route({ body: "LoginSchema" }),
+	async (req: Request, res: Response) => {
+		const { login, password, captcha_key, undelete } =
+			req.body as LoginSchema;
+		const email = adjustEmail(login);
+		console.log("login", email);
+
+		const config = Config.get();
+
+		if (config.login.requireCaptcha && config.security.captcha.enabled) {
+			const { sitekey, service } = config.security.captcha;
+			if (!captcha_key) {
+				return res.status(400).json({
+					captcha_key: ["captcha-required"],
+					captcha_sitekey: sitekey,
+					captcha_service: service,
+				});
+			}
+
+			const ip = getIpAdress(req);
+			const verify = await verifyCaptcha(captcha_key, ip);
+			if (!verify.success) {
+				return res.status(400).json({
+					captcha_key: verify["error-codes"],
+					captcha_sitekey: sitekey,
+					captcha_service: service,
+				});
+			}
+		}
 
-	const config = Config.get();
+		const user = await User.findOneOrFail({
+			where: [{ phone: login }, { email: login }],
+			select: [
+				"data",
+				"id",
+				"disabled",
+				"deleted",
+				"settings",
+				"totp_secret",
+				"mfa_enabled",
+			],
+		}).catch((e) => {
+			throw FieldErrors({
+				login: {
+					message: req.t("auth:login.INVALID_LOGIN"),
+					code: "INVALID_LOGIN",
+				},
+			});
+		});
+
+		if (undelete) {
+			// undelete refers to un'disable' here
+			if (user.disabled)
+				await User.update({ id: user.id }, { disabled: false });
+			if (user.deleted)
+				await User.update({ id: user.id }, { deleted: false });
+		} else {
+			if (user.deleted)
+				return res.status(400).json({
+					message: "This account is scheduled for deletion.",
+					code: 20011,
+				});
+			if (user.disabled)
+				return res.status(400).json({
+					message: req.t("auth:login.ACCOUNT_DISABLED"),
+					code: 20013,
+				});
+		}
 
-	if (config.login.requireCaptcha && config.security.captcha.enabled) {
-		const { sitekey, service } = config.security.captcha;
-		if (!captcha_key) {
-			return res.status(400).json({
-				captcha_key: ["captcha-required"],
-				captcha_sitekey: sitekey,
-				captcha_service: service
+		// the salt is saved in the password refer to bcrypt docs
+		const same_password = await bcrypt.compare(
+			password,
+			user.data.hash || "",
+		);
+		if (!same_password) {
+			throw FieldErrors({
+				password: {
+					message: req.t("auth:login.INVALID_PASSWORD"),
+					code: "INVALID_PASSWORD",
+				},
 			});
 		}
 
-		const ip = getIpAdress(req);
-		const verify = await verifyCaptcha(captcha_key, ip);
-		if (!verify.success) {
-			return res.status(400).json({
-				captcha_key: verify["error-codes"],
-				captcha_sitekey: sitekey,
-				captcha_service: service
+		if (user.mfa_enabled) {
+			// TODO: This is not a discord.com ticket. I'm not sure what it is but I'm lazy
+			const ticket = crypto.randomBytes(40).toString("hex");
+
+			await User.update({ id: user.id }, { totp_last_ticket: ticket });
+
+			return res.json({
+				ticket: ticket,
+				mfa: true,
+				sms: false, // TODO
+				token: null,
 			});
 		}
-	}
-
-	const user = await User.findOneOrFail({
-		where: [{ phone: login }, { email: login }],
-		select: ["data", "id", "disabled", "deleted", "settings", "totp_secret", "mfa_enabled"]
-	}).catch((e) => {
-		throw FieldErrors({ login: { message: req.t("auth:login.INVALID_LOGIN"), code: "INVALID_LOGIN" } });
-	});
-
-	if (undelete) {
-		// undelete refers to un'disable' here
-		if (user.disabled) await User.update({ id: user.id }, { disabled: false });
-		if (user.deleted) await User.update({ id: user.id }, { deleted: false });
-	} else {
-		if (user.deleted) return res.status(400).json({ message: "This account is scheduled for deletion.", code: 20011 });
-		if (user.disabled) return res.status(400).json({ message: req.t("auth:login.ACCOUNT_DISABLED"), code: 20013 });
-	}
-
-	// the salt is saved in the password refer to bcrypt docs
-	const same_password = await bcrypt.compare(password, user.data.hash || "");
-	if (!same_password) {
-		throw FieldErrors({ password: { message: req.t("auth:login.INVALID_PASSWORD"), code: "INVALID_PASSWORD" } });
-	}
-
-	if (user.mfa_enabled) {
-		// TODO: This is not a discord.com ticket. I'm not sure what it is but I'm lazy
-		const ticket = crypto.randomBytes(40).toString("hex");
-
-		await User.update({ id: user.id }, { totp_last_ticket: ticket });
-
-		return res.json({
-			ticket: ticket,
-			mfa: true,
-			sms: false,	// TODO
-			token: null,
-		})
-	}
-
-	const token = await generateToken(user.id);
-
-	// Notice this will have a different token structure, than discord
-	// Discord header is just the user id as string, which is not possible with npm-jsonwebtoken package
-	// https://user-images.githubusercontent.com/6506416/81051916-dd8c9900-8ec2-11ea-8794-daf12d6f31f0.png
-
-	res.json({ token, settings: user.settings });
-});
+
+		const token = await generateToken(user.id);
+
+		// Notice this will have a different token structure, than discord
+		// Discord header is just the user id as string, which is not possible with npm-jsonwebtoken package
+		// https://user-images.githubusercontent.com/6506416/81051916-dd8c9900-8ec2-11ea-8794-daf12d6f31f0.png
+
+		res.json({ token, settings: user.settings });
+	},
+);
 
 /**
  * POST /auth/login
diff --git a/src/api/routes/auth/logout.ts b/src/api/routes/auth/logout.ts
index e806fed9..e1bdbea3 100644
--- a/src/api/routes/auth/logout.ts
+++ b/src/api/routes/auth/logout.ts
@@ -10,7 +10,8 @@ router.post("/", route({}), async (req: Request, res: Response) => {
 	} else {
 		delete req.body.provider;
 		delete req.body.voip_provider;
-		if (Object.keys(req.body).length != 0) console.log(`[LOGOUT]: Extra fields sent in logout!`, req.body);
+		if (Object.keys(req.body).length != 0)
+			console.log(`[LOGOUT]: Extra fields sent in logout!`, req.body);
 	}
 	res.status(204).send();
-});
\ No newline at end of file
+});
diff --git a/src/api/routes/auth/mfa/totp.ts b/src/api/routes/auth/mfa/totp.ts
index 96a48b66..83cf7648 100644
--- a/src/api/routes/auth/mfa/totp.ts
+++ b/src/api/routes/auth/mfa/totp.ts
@@ -5,45 +5,48 @@ import { verifyToken } from "node-2fa";
 import { HTTPError } from "lambert-server";
 const router = Router();
 
-router.post("/", route({ body: "TotpSchema" }), async (req: Request, res: Response) => {
-	const { code, ticket, gift_code_sku_id, login_source } = req.body as TotpSchema;
+router.post(
+	"/",
+	route({ body: "TotpSchema" }),
+	async (req: Request, res: Response) => {
+		const { code, ticket, gift_code_sku_id, login_source } =
+			req.body as TotpSchema;
 
-	const user = await User.findOneOrFail({
-		where: {
-			totp_last_ticket: ticket,
-		},
-		select: [
-			"id",
-			"totp_secret",
-			"settings",
-		],
-	});
+		const user = await User.findOneOrFail({
+			where: {
+				totp_last_ticket: ticket,
+			},
+			select: ["id", "totp_secret", "settings"],
+		});
 
-	const backup = await BackupCode.findOne({
-		where: {
-			code: code,
-			expired: false,
-			consumed: false,
-			user: { id: user.id }
-		}
-	});
+		const backup = await BackupCode.findOne({
+			where: {
+				code: code,
+				expired: false,
+				consumed: false,
+				user: { id: user.id },
+			},
+		});
 
-	if (!backup) {
-		const ret = verifyToken(user.totp_secret!, code);
-		if (!ret || ret.delta != 0)
-			throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
-	}
-	else {
-		backup.consumed = true;
-		await backup.save();
-	}
+		if (!backup) {
+			const ret = verifyToken(user.totp_secret!, code);
+			if (!ret || ret.delta != 0)
+				throw new HTTPError(
+					req.t("auth:login.INVALID_TOTP_CODE"),
+					60008,
+				);
+		} else {
+			backup.consumed = true;
+			await backup.save();
+		}
 
-	await User.update({ id: user.id }, { totp_last_ticket: "" });
+		await User.update({ id: user.id }, { totp_last_ticket: "" });
 
-	return res.json({
-		token: await generateToken(user.id),
-		user_settings: user.settings,
-	});
-});
+		return res.json({
+			token: await generateToken(user.id),
+			user_settings: user.settings,
+		});
+	},
+);
 
 export default router;
diff --git a/src/api/routes/auth/register.ts b/src/api/routes/auth/register.ts
index 84f8f838..3479c4a0 100644
--- a/src/api/routes/auth/register.ts
+++ b/src/api/routes/auth/register.ts
@@ -1,156 +1,215 @@
 import { Request, Response, Router } from "express";
-import { Config, generateToken, Invite, FieldErrors, User, adjustEmail, RegisterSchema } from "@fosscord/util";
-import { route, getIpAdress, IPAnalysis, isProxy, verifyCaptcha } from "@fosscord/api";
+import {
+	Config,
+	generateToken,
+	Invite,
+	FieldErrors,
+	User,
+	adjustEmail,
+	RegisterSchema,
+} from "@fosscord/util";
+import {
+	route,
+	getIpAdress,
+	IPAnalysis,
+	isProxy,
+	verifyCaptcha,
+} from "@fosscord/api";
 import bcrypt from "bcrypt";
 import { HTTPError } from "lambert-server";
 
 const router: Router = Router();
 
-router.post("/", route({ body: "RegisterSchema" }), async (req: Request, res: Response) => {
-	const body = req.body as RegisterSchema;
-	const { register, security } = Config.get();
-	const ip = getIpAdress(req);
-
-	// email will be slightly modified version of the user supplied email -> e.g. protection against GMail Trick
-	let email = adjustEmail(body.email);
-
-	// check if registration is allowed
-	if (!register.allowNewRegistration) {
-		throw FieldErrors({
-			email: { code: "REGISTRATION_DISABLED", message: req.t("auth:register.REGISTRATION_DISABLED") }
-		});
-	}
-
-	// check if the user agreed to the Terms of Service
-	if (!body.consent) {
-		throw FieldErrors({
-			consent: { code: "CONSENT_REQUIRED", message: req.t("auth:register.CONSENT_REQUIRED") }
-		});
-	}
-
-	if (register.disabled) {
-		throw FieldErrors({
-			email: {
-				code: "DISABLED",
-				message: "registration is disabled on this instance"
-			}
-		});
-	}
-
-	if (register.requireCaptcha && security.captcha.enabled) {
-		const { sitekey, service } = security.captcha;
-		if (!body.captcha_key) {
-			return res?.status(400).json({
-				captcha_key: ["captcha-required"],
-				captcha_sitekey: sitekey,
-				captcha_service: service
+router.post(
+	"/",
+	route({ body: "RegisterSchema" }),
+	async (req: Request, res: Response) => {
+		const body = req.body as RegisterSchema;
+		const { register, security } = Config.get();
+		const ip = getIpAdress(req);
+
+		// email will be slightly modified version of the user supplied email -> e.g. protection against GMail Trick
+		let email = adjustEmail(body.email);
+
+		// check if registration is allowed
+		if (!register.allowNewRegistration) {
+			throw FieldErrors({
+				email: {
+					code: "REGISTRATION_DISABLED",
+					message: req.t("auth:register.REGISTRATION_DISABLED"),
+				},
 			});
 		}
 
-		const verify = await verifyCaptcha(body.captcha_key, ip);
-		if (!verify.success) {
-			return res.status(400).json({
-				captcha_key: verify["error-codes"],
-				captcha_sitekey: sitekey,
-				captcha_service: service
+		// check if the user agreed to the Terms of Service
+		if (!body.consent) {
+			throw FieldErrors({
+				consent: {
+					code: "CONSENT_REQUIRED",
+					message: req.t("auth:register.CONSENT_REQUIRED"),
+				},
 			});
 		}
-	}
-
-	if (!register.allowMultipleAccounts) {
-		// TODO: check if fingerprint was eligible generated
-		const exists = await User.findOne({ where: { fingerprints: body.fingerprint }, select: ["id"] });
 
-		if (exists) {
+		if (register.disabled) {
 			throw FieldErrors({
 				email: {
-					code: "EMAIL_ALREADY_REGISTERED",
-					message: req.t("auth:register.EMAIL_ALREADY_REGISTERED")
-				}
+					code: "DISABLED",
+					message: "registration is disabled on this instance",
+				},
 			});
 		}
-	}
 
-	if (register.blockProxies) {
-		if (isProxy(await IPAnalysis(ip))) {
-			console.log(`proxy ${ip} blocked from registration`);
-			throw new HTTPError("Your IP is blocked from registration");
+		if (register.requireCaptcha && security.captcha.enabled) {
+			const { sitekey, service } = security.captcha;
+			if (!body.captcha_key) {
+				return res?.status(400).json({
+					captcha_key: ["captcha-required"],
+					captcha_sitekey: sitekey,
+					captcha_service: service,
+				});
+			}
+
+			const verify = await verifyCaptcha(body.captcha_key, ip);
+			if (!verify.success) {
+				return res.status(400).json({
+					captcha_key: verify["error-codes"],
+					captcha_sitekey: sitekey,
+					captcha_service: service,
+				});
+			}
 		}
-	}
 
-	// TODO: gift_code_sku_id?
-	// TODO: check password strength
+		if (!register.allowMultipleAccounts) {
+			// TODO: check if fingerprint was eligible generated
+			const exists = await User.findOne({
+				where: { fingerprints: body.fingerprint },
+				select: ["id"],
+			});
+
+			if (exists) {
+				throw FieldErrors({
+					email: {
+						code: "EMAIL_ALREADY_REGISTERED",
+						message: req.t(
+							"auth:register.EMAIL_ALREADY_REGISTERED",
+						),
+					},
+				});
+			}
+		}
 
-	if (email) {
-		// replace all dots and chars after +, if its a gmail.com email
-		if (!email) {
-			throw FieldErrors({ email: { code: "INVALID_EMAIL", message: req?.t("auth:register.INVALID_EMAIL") } });
+		if (register.blockProxies) {
+			if (isProxy(await IPAnalysis(ip))) {
+				console.log(`proxy ${ip} blocked from registration`);
+				throw new HTTPError("Your IP is blocked from registration");
+			}
 		}
 
-		// check if there is already an account with this email
-		const exists = await User.findOne({ where: { email: email } });
+		// TODO: gift_code_sku_id?
+		// TODO: check password strength
+
+		if (email) {
+			// replace all dots and chars after +, if its a gmail.com email
+			if (!email) {
+				throw FieldErrors({
+					email: {
+						code: "INVALID_EMAIL",
+						message: req?.t("auth:register.INVALID_EMAIL"),
+					},
+				});
+			}
 
-		if (exists) {
+			// check if there is already an account with this email
+			const exists = await User.findOne({ where: { email: email } });
+
+			if (exists) {
+				throw FieldErrors({
+					email: {
+						code: "EMAIL_ALREADY_REGISTERED",
+						message: req.t(
+							"auth:register.EMAIL_ALREADY_REGISTERED",
+						),
+					},
+				});
+			}
+		} else if (register.email.required) {
 			throw FieldErrors({
 				email: {
-					code: "EMAIL_ALREADY_REGISTERED",
-					message: req.t("auth:register.EMAIL_ALREADY_REGISTERED")
-				}
+					code: "BASE_TYPE_REQUIRED",
+					message: req.t("common:field.BASE_TYPE_REQUIRED"),
+				},
 			});
 		}
-	} else if (register.email.required) {
-		throw FieldErrors({
-			email: { code: "BASE_TYPE_REQUIRED", message: req.t("common:field.BASE_TYPE_REQUIRED") }
-		});
-	}
-
-	if (register.dateOfBirth.required && !body.date_of_birth) {
-		throw FieldErrors({
-			date_of_birth: { code: "BASE_TYPE_REQUIRED", message: req.t("common:field.BASE_TYPE_REQUIRED") }
-		});
-	} else if (register.dateOfBirth.required && register.dateOfBirth.minimum) {
-		const minimum = new Date();
-		minimum.setFullYear(minimum.getFullYear() - register.dateOfBirth.minimum);
-		body.date_of_birth = new Date(body.date_of_birth as Date);
-
-		// higher is younger
-		if (body.date_of_birth > minimum) {
+
+		if (register.dateOfBirth.required && !body.date_of_birth) {
 			throw FieldErrors({
 				date_of_birth: {
-					code: "DATE_OF_BIRTH_UNDERAGE",
-					message: req.t("auth:register.DATE_OF_BIRTH_UNDERAGE", { years: register.dateOfBirth.minimum })
-				}
+					code: "BASE_TYPE_REQUIRED",
+					message: req.t("common:field.BASE_TYPE_REQUIRED"),
+				},
+			});
+		} else if (
+			register.dateOfBirth.required &&
+			register.dateOfBirth.minimum
+		) {
+			const minimum = new Date();
+			minimum.setFullYear(
+				minimum.getFullYear() - register.dateOfBirth.minimum,
+			);
+			body.date_of_birth = new Date(body.date_of_birth as Date);
+
+			// higher is younger
+			if (body.date_of_birth > minimum) {
+				throw FieldErrors({
+					date_of_birth: {
+						code: "DATE_OF_BIRTH_UNDERAGE",
+						message: req.t("auth:register.DATE_OF_BIRTH_UNDERAGE", {
+							years: register.dateOfBirth.minimum,
+						}),
+					},
+				});
+			}
+		}
+
+		if (body.password) {
+			// the salt is saved in the password refer to bcrypt docs
+			body.password = await bcrypt.hash(body.password, 12);
+		} else if (register.password.required) {
+			throw FieldErrors({
+				password: {
+					code: "BASE_TYPE_REQUIRED",
+					message: req.t("common:field.BASE_TYPE_REQUIRED"),
+				},
+			});
+		}
+
+		if (
+			!body.invite &&
+			(register.requireInvite ||
+				(register.guestsRequireInvite && !register.email))
+		) {
+			// require invite to register -> e.g. for organizations to send invites to their employees
+			throw FieldErrors({
+				email: {
+					code: "INVITE_ONLY",
+					message: req.t("auth:register.INVITE_ONLY"),
+				},
 			});
 		}
-	}
-
-	if (body.password) {
-		// the salt is saved in the password refer to bcrypt docs
-		body.password = await bcrypt.hash(body.password, 12);
-	} else if (register.password.required) {
-		throw FieldErrors({
-			password: { code: "BASE_TYPE_REQUIRED", message: req.t("common:field.BASE_TYPE_REQUIRED") }
-		});
-	}
-
-	if (!body.invite && (register.requireInvite || (register.guestsRequireInvite && !register.email))) {
-		// require invite to register -> e.g. for organizations to send invites to their employees
-		throw FieldErrors({
-			email: { code: "INVITE_ONLY", message: req.t("auth:register.INVITE_ONLY") }
-		});
-	}
-
-	const user = await User.register({ ...body, req });
-
-	if (body.invite) {
-		// await to fail if the invite doesn't exist (necessary for requireInvite to work properly) (username only signups are possible)
-		await Invite.joinGuild(user.id, body.invite);
-	}
-
-	console.log("register", body.email, body.username, ip);
-
-	return res.json({ token: await generateToken(user.id) });
-});
+
+		const user = await User.register({ ...body, req });
+
+		if (body.invite) {
+			// await to fail if the invite doesn't exist (necessary for requireInvite to work properly) (username only signups are possible)
+			await Invite.joinGuild(user.id, body.invite);
+		}
+
+		console.log("register", body.email, body.username, ip);
+
+		return res.json({ token: await generateToken(user.id) });
+	},
+);
 
 export default router;
 
diff --git a/src/api/routes/auth/verify/view-backup-codes-challenge.ts b/src/api/routes/auth/verify/view-backup-codes-challenge.ts
index 24de8ec5..65f0a57c 100644
--- a/src/api/routes/auth/verify/view-backup-codes-challenge.ts
+++ b/src/api/routes/auth/verify/view-backup-codes-challenge.ts
@@ -4,19 +4,31 @@ import { FieldErrors, User, BackupCodesChallengeSchema } from "@fosscord/util";
 import bcrypt from "bcrypt";
 const router = Router();
 
-router.post("/", route({ body: "BackupCodesChallengeSchema" }), async (req: Request, res: Response) => {
-	const { password } = req.body as BackupCodesChallengeSchema;
+router.post(
+	"/",
+	route({ body: "BackupCodesChallengeSchema" }),
+	async (req: Request, res: Response) => {
+		const { password } = req.body as BackupCodesChallengeSchema;
 
-	const user = await User.findOneOrFail({ where: { id: req.user_id }, select: ["data"] });
+		const user = await User.findOneOrFail({
+			where: { id: req.user_id },
+			select: ["data"],
+		});
 
-	if (!await bcrypt.compare(password, user.data.hash || "")) {
-		throw FieldErrors({ password: { message: req.t("auth:login.INVALID_PASSWORD"), code: "INVALID_PASSWORD" } });
-	}
+		if (!(await bcrypt.compare(password, user.data.hash || ""))) {
+			throw FieldErrors({
+				password: {
+					message: req.t("auth:login.INVALID_PASSWORD"),
+					code: "INVALID_PASSWORD",
+				},
+			});
+		}
 
-	return res.json({
-		nonce: "NoncePlaceholder",
-		regenerate_nonce: "RegenNoncePlaceholder",
-	});
-});
+		return res.json({
+			nonce: "NoncePlaceholder",
+			regenerate_nonce: "RegenNoncePlaceholder",
+		});
+	},
+);
 
 export default router;
diff --git a/src/api/routes/channels/#channel_id/index.ts b/src/api/routes/channels/#channel_id/index.ts
index 8dbefe1b..a164fff6 100644
--- a/src/api/routes/channels/#channel_id/index.ts
+++ b/src/api/routes/channels/#channel_id/index.ts
@@ -6,7 +6,7 @@ import {
 	emitEvent,
 	Recipient,
 	handleFile,
-	ChannelModifySchema
+	ChannelModifySchema,
 } from "@fosscord/util";
 import { Request, Response, Router } from "express";
 import { route } from "@fosscord/api";
@@ -15,56 +15,89 @@ const router: Router = Router();
 // TODO: delete channel
 // TODO: Get channel
 
-router.get("/", route({ permission: "VIEW_CHANNEL" }), async (req: Request, res: Response) => {
-	const { channel_id } = req.params;
+router.get(
+	"/",
+	route({ permission: "VIEW_CHANNEL" }),
+	async (req: Request, res: Response) => {
+		const { channel_id } = req.params;
 
-	const channel = await Channel.findOneOrFail({ where: { id: channel_id } });
+		const channel = await Channel.findOneOrFail({
+			where: { id: channel_id },
+		});
 
-	return res.send(channel);
-});
+		return res.send(channel);
+	},
+);
 
-router.delete("/", route({ permission: "MANAGE_CHANNELS" }), async (req: Request, res: Response) => {
-	const { channel_id } = req.params;
+router.delete(
+	"/",
+	route({ permission: "MANAGE_CHANNELS" }),
+	async (req: Request, res: Response) => {
+		const { channel_id } = req.params;
 
-	const channel = await Channel.findOneOrFail({ where: { id: channel_id }, relations: ["recipients"] });
+		const channel = await Channel.findOneOrFail({
+			where: { id: channel_id },
+			relations: ["recipients"],
+		});
 
-	if (channel.type === ChannelType.DM) {
-		const recipient = await Recipient.findOneOrFail({ where: { channel_id: channel_id, user_id: req.user_id } });
-		recipient.closed = true;
-		await Promise.all([
-			recipient.save(),
-			emitEvent({ event: "CHANNEL_DELETE", data: channel, user_id: req.user_id } as ChannelDeleteEvent)
-		]);
-	} else if (channel.type === ChannelType.GROUP_DM) {
-		await Channel.removeRecipientFromChannel(channel, req.user_id);
-	} else {
-		await Promise.all([
-			Channel.delete({ id: channel_id }),
-			emitEvent({ event: "CHANNEL_DELETE", data: channel, channel_id } as ChannelDeleteEvent)
-		]);
-	}
+		if (channel.type === ChannelType.DM) {
+			const recipient = await Recipient.findOneOrFail({
+				where: { channel_id: channel_id, user_id: req.user_id },
+			});
+			recipient.closed = true;
+			await Promise.all([
+				recipient.save(),
+				emitEvent({
+					event: "CHANNEL_DELETE",
+					data: channel,
+					user_id: req.user_id,
+				} as ChannelDeleteEvent),
+			]);
+		} else if (channel.type === ChannelType.GROUP_DM) {
+			await Channel.removeRecipientFromChannel(channel, req.user_id);
+		} else {
+			await Promise.all([
+				Channel.delete({ id: channel_id }),
+				emitEvent({
+					event: "CHANNEL_DELETE",
+					data: channel,
+					channel_id,
+				} as ChannelDeleteEvent),
+			]);
+		}
 
-	res.send(channel);
-});
+		res.send(channel);
+	},
+);
 
-router.patch("/", route({ body: "ChannelModifySchema", permission: "MANAGE_CHANNELS" }), async (req: Request, res: Response) => {
-	var payload = req.body as ChannelModifySchema;
-	const { channel_id } = req.params;
-	if (payload.icon) payload.icon = await handleFile(`/channel-icons/${channel_id}`, payload.icon);
+router.patch(
+	"/",
+	route({ body: "ChannelModifySchema", permission: "MANAGE_CHANNELS" }),
+	async (req: Request, res: Response) => {
+		var payload = req.body as ChannelModifySchema;
+		const { channel_id } = req.params;
+		if (payload.icon)
+			payload.icon = await handleFile(
+				`/channel-icons/${channel_id}`,
+				payload.icon,
+			);
 
-	const channel = await Channel.findOneOrFail({ where: { id: channel_id } });
-	channel.assign(payload);
+		const channel = await Channel.findOneOrFail({
+			where: { id: channel_id },
+		});
+		channel.assign(payload);
 
-	await Promise.all([
-		channel.save(),
-		emitEvent({
-			event: "CHANNEL_UPDATE",
-			data: channel,
-			channel_id
-		} as ChannelUpdateEvent)
-	]);
+		await Promise.all([
+			channel.save(),
+			emitEvent({
+				event: "CHANNEL_UPDATE",
+				data: channel,
+				channel_id,
+			} as ChannelUpdateEvent),
+		]);
 
-	res.send(channel);
-});
+		res.send(channel);
+	},
+);
 
 export default router;
diff --git a/src/api/routes/channels/#channel_id/invites.ts b/src/api/routes/channels/#channel_id/invites.ts
index 246a2c69..afaabf47 100644
--- a/src/api/routes/channels/#channel_id/invites.ts
+++ b/src/api/routes/channels/#channel_id/invites.ts
@@ -2,16 +2,33 @@ import { Router, Request, Response } from "express";
 import { HTTPError } from "lambert-server";
 import { route } from "@fosscord/api";
 import { random } from "@fosscord/api";
-import { Channel, Invite, InviteCreateEvent, emitEvent, User, Guild, PublicInviteRelation } from "@fosscord/util";
+import {
+	Channel,
+	Invite,
+	InviteCreateEvent,
+	emitEvent,
+	User,
+	Guild,
+	PublicInviteRelation,
+} from "@fosscord/util";
 import { isTextChannel } from "./messages";
 
 const router: Router = Router();
 
-router.post("/", route({ body: "InviteCreateSchema", permission: "CREATE_INSTANT_INVITE", right: "CREATE_INVITES" }),
+router.post(
+	"/",
+	route({
+		body: "InviteCreateSchema",
+		permission: "CREATE_INSTANT_INVITE",
+		right: "CREATE_INVITES",
+	}),
 	async (req: Request, res: Response) => {
 		const { user_id } = req;
 		const { channel_id } = req.params;
-		const channel = await Channel.findOneOrFail({ where: { id: channel_id }, select: ["id", "name", "type", "guild_id"] });
+		const channel = await Channel.findOneOrFail({
+			where: { id: channel_id },
+			select: ["id", "name", "type", "guild_id"],
+		});
 		isTextChannel(channel.type);
 
 		if (!channel.guild_id) {
@@ -31,30 +48,44 @@ router.post("/", route({ body: "InviteCreateSchema", permission: "CREATE_INSTANT
 			created_at: new Date(),
 			guild_id,
 			channel_id: channel_id,
-			inviter_id: user_id
+			inviter_id: user_id,
 		}).save();
 		const data = invite.toJSON();
 		data.inviter = await User.getPublicUser(req.user_id);
 		data.guild = await Guild.findOne({ where: { id: guild_id } });
 		data.channel = channel;
 
-		await emitEvent({ event: "INVITE_CREATE", data, guild_id } as InviteCreateEvent);
+		await emitEvent({
+			event: "INVITE_CREATE",
+			data,
+			guild_id,
+		} as InviteCreateEvent);
 		res.status(201).send(data);
-	});
+	},
+);
 
-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 } });
+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 },
+		});
 
-	if (!channel.guild_id) {
-		throw new HTTPError("This channel doesn't exist", 404);
-	}
-	const { guild_id } = channel;
+		if (!channel.guild_id) {
+			throw new HTTPError("This channel doesn't exist", 404);
+		}
+		const { guild_id } = channel;
 
-	const invites = await Invite.find({ where: { guild_id }, relations: PublicInviteRelation });
+		const invites = await Invite.find({
+			where: { guild_id },
+			relations: PublicInviteRelation,
+		});
 
-	res.status(200).send(invites);
-});
+		res.status(200).send(invites);
+	},
+);
 
 export default router;
diff --git a/src/api/routes/channels/#channel_id/messages/#message_id/ack.ts b/src/api/routes/channels/#channel_id/messages/#message_id/ack.ts
index bedd453c..1a30143f 100644
--- a/src/api/routes/channels/#channel_id/messages/#message_id/ack.ts
+++ b/src/api/routes/channels/#channel_id/messages/#message_id/ack.ts
@@ -1,4 +1,9 @@
-import { emitEvent, getPermission, MessageAckEvent, ReadState } from "@fosscord/util";
+import {
+	emitEvent,
+	getPermission,
+	MessageAckEvent,
+	ReadState,
+} from "@fosscord/util";
 import { Request, Response, Router } from "express";
 import { route } from "@fosscord/api";
 
@@ -8,29 +13,40 @@ const router = Router();
 // TODO: send read state event to all channel members
 // TODO: advance-only notification cursor
 
-router.post("/", route({ body: "MessageAcknowledgeSchema" }), async (req: Request, res: Response) => {
-	const { channel_id, message_id } = req.params;
+router.post(
+	"/",
+	route({ body: "MessageAcknowledgeSchema" }),
+	async (req: Request, res: Response) => {
+		const { channel_id, message_id } = req.params;
 
-	const permission = await getPermission(req.user_id, undefined, channel_id);
-	permission.hasThrow("VIEW_CHANNEL");
-
-	let read_state = await ReadState.findOne({ where: { user_id: req.user_id, channel_id } });
-	if (!read_state) read_state = ReadState.create({ user_id: req.user_id, channel_id });
-	read_state.last_message_id = message_id;
-
-	await read_state.save();
-
-	await emitEvent({
-		event: "MESSAGE_ACK",
-		user_id: req.user_id,
-		data: {
+		const permission = await getPermission(
+			req.user_id,
+			undefined,
 			channel_id,
-			message_id,
-			version: 3763
-		}
-	} as MessageAckEvent);
-
-	res.json({ token: null });
-});
+		);
+		permission.hasThrow("VIEW_CHANNEL");
+
+		let read_state = await ReadState.findOne({
+			where: { user_id: req.user_id, channel_id },
+		});
+		if (!read_state)
+			read_state = ReadState.create({ user_id: req.user_id, channel_id });
+		read_state.last_message_id = message_id;
+
+		await read_state.save();
+
+		await emitEvent({
+			event: "MESSAGE_ACK",
+			user_id: req.user_id,
+			data: {
+				channel_id,
+				message_id,
+				version: 3763,
+			},
+		} as MessageAckEvent);
+
+		res.json({ token: null });
+	},
+);
 
 export default router;
diff --git a/src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts b/src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts
index b2cb6763..d8b55ccd 100644
--- a/src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts
+++ b/src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts
@@ -3,26 +3,36 @@ import { route } from "@fosscord/api";
 
 const router = Router();
 
-router.post("/", route({ permission: "MANAGE_MESSAGES" }), (req: Request, res: Response) => {
-	// TODO:
-	res.json({
-		id: "",
-		type: 0,
-		content: "",
-		channel_id: "",
-		author: { id: "", username: "", avatar: "", discriminator: "", public_flags: 64 },
-		attachments: [],
-		embeds: [],
-		mentions: [],
-		mention_roles: [],
-		pinned: false,
-		mention_everyone: false,
-		tts: false,
-		timestamp: "",
-		edited_timestamp: null,
-		flags: 1,
-		components: []
-	}).status(200);
-});
+router.post(
+	"/",
+	route({ permission: "MANAGE_MESSAGES" }),
+	(req: Request, res: Response) => {
+		// TODO:
+		res.json({
+			id: "",
+			type: 0,
+			content: "",
+			channel_id: "",
+			author: {
+				id: "",
+				username: "",
+				avatar: "",
+				discriminator: "",
+				public_flags: 64,
+			},
+			attachments: [],
+			embeds: [],
+			mentions: [],
+			mention_roles: [],
+			pinned: false,
+			mention_everyone: false,
+			tts: false,
+			timestamp: "",
+			edited_timestamp: null,
+			flags: 1,
+			components: [],
+		}).status(200);
+	},
+);
 
 export default router;
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 46b0d6bd..3abfebe8 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
@@ -26,55 +26,69 @@ const messageUpload = multer({
 	limits: {
 		fileSize: 1024 * 1024 * 100,
 		fields: 10,
-		files: 1
+		files: 1,
 	},
-	storage: multer.memoryStorage()
+	storage: multer.memoryStorage(),
 }); // max upload 50 mb
 
-router.patch("/", route({ body: "MessageCreateSchema", permission: "SEND_MESSAGES", right: "SEND_MESSAGES" }), async (req: Request, res: Response) => {
-	const { message_id, channel_id } = req.params;
-	var body = req.body as MessageCreateSchema;
+router.patch(
+	"/",
+	route({
+		body: "MessageCreateSchema",
+		permission: "SEND_MESSAGES",
+		right: "SEND_MESSAGES",
+	}),
+	async (req: Request, res: Response) => {
+		const { message_id, channel_id } = req.params;
+		var body = req.body as MessageCreateSchema;
 
-	const message = await Message.findOneOrFail({ where: { id: message_id, channel_id }, relations: ["attachments"] });
+		const message = await Message.findOneOrFail({
+			where: { id: message_id, channel_id },
+			relations: ["attachments"],
+		});
 
-	const permissions = await getPermission(req.user_id, undefined, channel_id);
+		const permissions = await getPermission(
+			req.user_id,
+			undefined,
+			channel_id,
+		);
 
-	const rights = await getRights(req.user_id);
+		const rights = await getRights(req.user_id);
 
-	if ((req.user_id !== message.author_id)) {
-		if (!rights.has("MANAGE_MESSAGES")) {
-			permissions.hasThrow("MANAGE_MESSAGES");
-			body = { flags: body.flags };
-			// guild admins can only suppress embeds of other messages, no such restriction imposed to instance-wide admins
-		}
-	} else rights.hasThrow("SELF_EDIT_MESSAGES");
-
-	const new_message = await handleMessage({
-		...message,
-		// TODO: should message_reference be overridable?
-		// @ts-ignore
-		message_reference: message.message_reference,
-		...body,
-		author_id: message.author_id,
-		channel_id,
-		id: message_id,
-		edited_timestamp: new Date()
-	});
-
-	await Promise.all([
-		new_message!.save(),
-		await emitEvent({
-			event: "MESSAGE_UPDATE",
+		if (req.user_id !== message.author_id) {
+			if (!rights.has("MANAGE_MESSAGES")) {
+				permissions.hasThrow("MANAGE_MESSAGES");
+				body = { flags: body.flags };
+				// guild admins can only suppress embeds of other messages, no such restriction imposed to instance-wide admins
+			}
+		} else rights.hasThrow("SELF_EDIT_MESSAGES");
+
+		const new_message = await handleMessage({
+			...message,
+			// TODO: should message_reference be overridable?
+			// @ts-ignore
+			message_reference: message.message_reference,
+			...body,
+			author_id: message.author_id,
 			channel_id,
-			data: { ...new_message, nonce: undefined }
-		} as MessageUpdateEvent)
-	]);
+			id: message_id,
+			edited_timestamp: new Date(),
+		});
 
-	postHandleMessage(message);
+		await Promise.all([
+			new_message!.save(),
+			await emitEvent({
+				event: "MESSAGE_UPDATE",
+				channel_id,
+				data: { ...new_message, nonce: undefined },
+			} as MessageUpdateEvent),
+		]);
 
-	return res.json(message);
-});
+		postHandleMessage(message);
 
+		return res.json(message);
+	},
+);
 
 // Backfill message with specific timestamp
 router.put(
@@ -87,7 +101,11 @@ router.put(
 
 		next();
 	},
-	route({ body: "MessageCreateSchema", permission: "SEND_MESSAGES", right: "SEND_BACKDATED_EVENTS" }),
+	route({
+		body: "MessageCreateSchema",
+		permission: "SEND_MESSAGES",
+		right: "SEND_BACKDATED_EVENTS",
+	}),
 	async (req: Request, res: Response) => {
 		const { channel_id, message_id } = req.params;
 		var body = req.body as MessageCreateSchema;
@@ -107,20 +125,30 @@ router.put(
 			throw FosscordApiErrors.CANNOT_BACKFILL_TO_THE_FUTURE;
 		}
 
-		const exists = await Message.findOne({ where: { id: message_id, channel_id: channel_id } });
+		const exists = await Message.findOne({
+			where: { id: message_id, channel_id: channel_id },
+		});
 		if (exists) {
 			throw FosscordApiErrors.CANNOT_REPLACE_BY_BACKFILL;
 		}
 
 		if (req.file) {
 			try {
-				const file = await uploadFile(`/attachments/${req.params.channel_id}`, req.file);
-				attachments.push(Attachment.create({ ...file, proxy_url: file.url }));
+				const file = await uploadFile(
+					`/attachments/${req.params.channel_id}`,
+					req.file,
+				);
+				attachments.push(
+					Attachment.create({ ...file, proxy_url: file.url }),
+				);
 			} catch (error) {
 				return res.status(400).json(error);
 			}
 		}
-		const channel = await Channel.findOneOrFail({ where: { id: channel_id }, relations: ["recipients", "recipients.user"] });
+		const channel = await Channel.findOneOrFail({
+			where: { id: channel_id },
+			relations: ["recipients", "recipients.user"],
+		});
 
 		const embeds = body.embeds || [];
 		if (body.embed) embeds.push(body.embed);
@@ -142,27 +170,43 @@ router.put(
 
 		await Promise.all([
 			message.save(),
-			emitEvent({ event: "MESSAGE_CREATE", channel_id: channel_id, data: message } as MessageCreateEvent),
-			channel.save()
+			emitEvent({
+				event: "MESSAGE_CREATE",
+				channel_id: channel_id,
+				data: message,
+			} as MessageCreateEvent),
+			channel.save(),
 		]);
 
-		postHandleMessage(message).catch((e) => { }); // no await as it shouldnt block the message send function and silently catch error
+		postHandleMessage(message).catch((e) => {}); // no await as it shouldnt block the message send function and silently catch error
 
 		return res.json(message);
-	}
+	},
 );
 
-router.get("/", route({ permission: "VIEW_CHANNEL" }), async (req: Request, res: Response) => {
-	const { message_id, channel_id } = req.params;
+router.get(
+	"/",
+	route({ permission: "VIEW_CHANNEL" }),
+	async (req: Request, res: Response) => {
+		const { message_id, channel_id } = req.params;
 
-	const message = await Message.findOneOrFail({ where: { id: message_id, channel_id }, relations: ["attachments"] });
+		const message = await Message.findOneOrFail({
+			where: { id: message_id, channel_id },
+			relations: ["attachments"],
+		});
 
-	const permissions = await getPermission(req.user_id, undefined, channel_id);
+		const permissions = await getPermission(
+			req.user_id,
+			undefined,
+			channel_id,
+		);
 
-	if (message.author_id !== req.user_id) permissions.hasThrow("READ_MESSAGE_HISTORY");
+		if (message.author_id !== req.user_id)
+			permissions.hasThrow("READ_MESSAGE_HISTORY");
 
-	return res.json(message);
-});
+		return res.json(message);
+	},
+);
 
 router.delete("/", route({}), async (req: Request, res: Response) => {
 	const { message_id, channel_id } = req.params;
@@ -172,9 +216,13 @@ router.delete("/", route({}), async (req: Request, res: Response) => {
 
 	const rights = await getRights(req.user_id);
 
-	if ((message.author_id !== req.user_id)) {
+	if (message.author_id !== req.user_id) {
 		if (!rights.has("MANAGE_MESSAGES")) {
-			const permission = await getPermission(req.user_id, channel.guild_id, channel_id);
+			const permission = await getPermission(
+				req.user_id,
+				channel.guild_id,
+				channel_id,
+			);
 			permission.hasThrow("MANAGE_MESSAGES");
 		}
 	} else rights.hasThrow("SELF_DELETE_MESSAGES");
@@ -187,8 +235,8 @@ router.delete("/", route({}), async (req: Request, res: Response) => {
 		data: {
 			id: message_id,
 			channel_id,
-			guild_id: channel.guild_id
-		}
+			guild_id: channel.guild_id,
+		},
 	} as MessageDeleteEvent);
 
 	res.sendStatus(204);
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 c3cca05d..9f774682 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
@@ -11,7 +11,7 @@ import {
 	MessageReactionRemoveEvent,
 	PartialEmoji,
 	PublicUserProjection,
-	User
+	User,
 } from "@fosscord/util";
 import { route } from "@fosscord/api";
 import { Router, Response, Request } from "express";
@@ -27,159 +27,224 @@ function getEmoji(emoji: string): PartialEmoji {
 	if (parts)
 		return {
 			name: parts[0],
-			id: parts[1]
+			id: parts[1],
 		};
 
 	return {
 		id: undefined,
-		name: emoji
+		name: emoji,
 	};
 }
 
-router.delete("/", route({ permission: "MANAGE_MESSAGES" }), async (req: Request, res: Response) => {
-	const { message_id, channel_id } = req.params;
+router.delete(
+	"/",
+	route({ permission: "MANAGE_MESSAGES" }),
+	async (req: Request, res: Response) => {
+		const { message_id, channel_id } = req.params;
 
-	const channel = await Channel.findOneOrFail({ where: { id: channel_id } });
+		const channel = await Channel.findOneOrFail({
+			where: { id: channel_id },
+		});
 
-	await Message.update({ id: message_id, channel_id }, { reactions: [] });
+		await Message.update({ id: message_id, channel_id }, { reactions: [] });
 
-	await emitEvent({
-		event: "MESSAGE_REACTION_REMOVE_ALL",
-		channel_id,
-		data: {
+		await emitEvent({
+			event: "MESSAGE_REACTION_REMOVE_ALL",
 			channel_id,
-			message_id,
-			guild_id: channel.guild_id
+			data: {
+				channel_id,
+				message_id,
+				guild_id: channel.guild_id,
+			},
+		} as MessageReactionRemoveAllEvent);
+
+		res.sendStatus(204);
+	},
+);
+
+router.delete(
+	"/:emoji",
+	route({ permission: "MANAGE_MESSAGES" }),
+	async (req: Request, res: Response) => {
+		const { message_id, channel_id } = req.params;
+		const emoji = getEmoji(req.params.emoji);
+
+		const message = await Message.findOneOrFail({
+			where: { id: message_id, channel_id },
+		});
+
+		const already_added = message.reactions.find(
+			(x) =>
+				(x.emoji.id === emoji.id && emoji.id) ||
+				x.emoji.name === emoji.name,
+		);
+		if (!already_added) throw new HTTPError("Reaction not found", 404);
+		message.reactions.remove(already_added);
+
+		await Promise.all([
+			message.save(),
+			emitEvent({
+				event: "MESSAGE_REACTION_REMOVE_EMOJI",
+				channel_id,
+				data: {
+					channel_id,
+					message_id,
+					guild_id: message.guild_id,
+					emoji,
+				},
+			} as MessageReactionRemoveEmojiEvent),
+		]);
+
+		res.sendStatus(204);
+	},
+);
+
+router.get(
+	"/:emoji",
+	route({ permission: "VIEW_CHANNEL" }),
+	async (req: Request, res: Response) => {
+		const { message_id, channel_id } = req.params;
+		const emoji = getEmoji(req.params.emoji);
+
+		const message = await Message.findOneOrFail({
+			where: { id: message_id, channel_id },
+		});
+		const reaction = message.reactions.find(
+			(x) =>
+				(x.emoji.id === emoji.id && emoji.id) ||
+				x.emoji.name === emoji.name,
+		);
+		if (!reaction) throw new HTTPError("Reaction not found", 404);
+
+		const users = await User.find({
+			where: {
+				id: In(reaction.user_ids),
+			},
+			select: PublicUserProjection,
+		});
+
+		res.json(users);
+	},
+);
+
+router.put(
+	"/:emoji/:user_id",
+	route({ permission: "READ_MESSAGE_HISTORY", right: "SELF_ADD_REACTIONS" }),
+	async (req: Request, res: Response) => {
+		const { message_id, channel_id, user_id } = req.params;
+		if (user_id !== "@me") throw new HTTPError("Invalid user");
+		const emoji = getEmoji(req.params.emoji);
+
+		const channel = await Channel.findOneOrFail({
+			where: { id: channel_id },
+		});
+		const message = await Message.findOneOrFail({
+			where: { id: message_id, channel_id },
+		});
+		const already_added = message.reactions.find(
+			(x) =>
+				(x.emoji.id === emoji.id && emoji.id) ||
+				x.emoji.name === emoji.name,
+		);
+
+		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");
+			emoji.animated = external_emoji.animated;
+			emoji.name = external_emoji.name;
 		}
-	} as MessageReactionRemoveAllEvent);
-
-	res.sendStatus(204);
-});
 
-router.delete("/:emoji", route({ permission: "MANAGE_MESSAGES" }), async (req: Request, res: Response) => {
-	const { message_id, channel_id } = req.params;
-	const emoji = getEmoji(req.params.emoji);
-
-	const message = await Message.findOneOrFail({ where: { id: message_id, channel_id } });
-
-	const already_added = message.reactions.find((x) => (x.emoji.id === emoji.id && emoji.id) || x.emoji.name === emoji.name);
-	if (!already_added) throw new HTTPError("Reaction not found", 404);
-	message.reactions.remove(already_added);
-
-	await Promise.all([
-		message.save(),
-		emitEvent({
-			event: "MESSAGE_REACTION_REMOVE_EMOJI",
+		if (already_added) {
+			if (already_added.user_ids.includes(req.user_id))
+				return res.sendStatus(204); // Do not throw an error ¯\_(ツ)_/¯ as discord also doesn't throw any error
+			already_added.count++;
+		} else
+			message.reactions.push({
+				count: 1,
+				emoji,
+				user_ids: [req.user_id],
+			});
+
+		await message.save();
+
+		const member =
+			channel.guild_id &&
+			(await Member.findOneOrFail({ where: { id: req.user_id } }));
+
+		await emitEvent({
+			event: "MESSAGE_REACTION_ADD",
 			channel_id,
 			data: {
+				user_id: req.user_id,
 				channel_id,
 				message_id,
-				guild_id: message.guild_id,
-				emoji
-			}
-		} as MessageReactionRemoveEmojiEvent)
-	]);
-
-	res.sendStatus(204);
-});
-
-router.get("/:emoji", route({ permission: "VIEW_CHANNEL" }), async (req: Request, res: Response) => {
-	const { message_id, channel_id } = req.params;
-	const emoji = getEmoji(req.params.emoji);
-
-	const message = await Message.findOneOrFail({ where: { id: message_id, channel_id } });
-	const reaction = message.reactions.find((x) => (x.emoji.id === emoji.id && emoji.id) || x.emoji.name === emoji.name);
-	if (!reaction) throw new HTTPError("Reaction not found", 404);
-
-	const users = await User.find({
-		where: {
-			id: In(reaction.user_ids)
-		},
-		select: PublicUserProjection
-	});
-
-	res.json(users);
-});
-
-router.put("/:emoji/:user_id", route({ permission: "READ_MESSAGE_HISTORY", right: "SELF_ADD_REACTIONS" }), async (req: Request, res: Response) => {
-	const { message_id, channel_id, user_id } = req.params;
-	if (user_id !== "@me") throw new HTTPError("Invalid user");
-	const emoji = getEmoji(req.params.emoji);
-
-	const channel = await Channel.findOneOrFail({ where: { id: channel_id } });
-	const message = await Message.findOneOrFail({ where: { id: message_id, channel_id } });
-	const already_added = message.reactions.find((x) => (x.emoji.id === emoji.id && emoji.id) || x.emoji.name === emoji.name);
-
-	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");
-		emoji.animated = external_emoji.animated;
-		emoji.name = external_emoji.name;
-	}
-
-	if (already_added) {
-		if (already_added.user_ids.includes(req.user_id)) return res.sendStatus(204); // Do not throw an error ¯\_(ツ)_/¯ as discord also doesn't throw any error
-		already_added.count++;
-	} else message.reactions.push({ count: 1, emoji, user_ids: [req.user_id] });
-
-	await message.save();
-
-	const member = channel.guild_id && (await Member.findOneOrFail({ where: { id: req.user_id } }));
-
-	await emitEvent({
-		event: "MESSAGE_REACTION_ADD",
-		channel_id,
-		data: {
-			user_id: req.user_id,
-			channel_id,
-			message_id,
-			guild_id: channel.guild_id,
-			emoji,
-			member
+				guild_id: channel.guild_id,
+				emoji,
+				member,
+			},
+		} as MessageReactionAddEvent);
+
+		res.sendStatus(204);
+	},
+);
+
+router.delete(
+	"/:emoji/:user_id",
+	route({}),
+	async (req: Request, res: Response) => {
+		var { message_id, channel_id, user_id } = req.params;
+
+		const emoji = getEmoji(req.params.emoji);
+
+		const channel = await Channel.findOneOrFail({
+			where: { id: channel_id },
+		});
+		const message = await Message.findOneOrFail({
+			where: { id: message_id, channel_id },
+		});
+
+		if (user_id === "@me") user_id = req.user_id;
+		else {
+			const permissions = await getPermission(
+				req.user_id,
+				undefined,
+				channel_id,
+			);
+			permissions.hasThrow("MANAGE_MESSAGES");
 		}
-	} as MessageReactionAddEvent);
 
-	res.sendStatus(204);
-});
+		const already_added = message.reactions.find(
+			(x) =>
+				(x.emoji.id === emoji.id && emoji.id) ||
+				x.emoji.name === emoji.name,
+		);
+		if (!already_added || !already_added.user_ids.includes(user_id))
+			throw new HTTPError("Reaction not found", 404);
 
-router.delete("/:emoji/:user_id", route({}), async (req: Request, res: Response) => {
-	var { message_id, channel_id, user_id } = req.params;
+		already_added.count--;
 
-	const emoji = getEmoji(req.params.emoji);
+		if (already_added.count <= 0) message.reactions.remove(already_added);
 
-	const channel = await Channel.findOneOrFail({ where: { id: channel_id } });
-	const message = await Message.findOneOrFail({ where: { id: message_id, channel_id } });
+		await message.save();
 
-	if (user_id === "@me") user_id = req.user_id;
-	else {
-		const permissions = await getPermission(req.user_id, undefined, channel_id);
-		permissions.hasThrow("MANAGE_MESSAGES");
-	}
-
-	const already_added = message.reactions.find((x) => (x.emoji.id === emoji.id && emoji.id) || x.emoji.name === emoji.name);
-	if (!already_added || !already_added.user_ids.includes(user_id)) throw new HTTPError("Reaction not found", 404);
-
-	already_added.count--;
-
-	if (already_added.count <= 0) message.reactions.remove(already_added);
-
-	await message.save();
-
-	await emitEvent({
-		event: "MESSAGE_REACTION_REMOVE",
-		channel_id,
-		data: {
-			user_id: req.user_id,
+		await emitEvent({
+			event: "MESSAGE_REACTION_REMOVE",
 			channel_id,
-			message_id,
-			guild_id: channel.guild_id,
-			emoji
-		}
-	} as MessageReactionRemoveEvent);
-
-	res.sendStatus(204);
-});
+			data: {
+				user_id: req.user_id,
+				channel_id,
+				message_id,
+				guild_id: channel.guild_id,
+				emoji,
+			},
+		} as MessageReactionRemoveEvent);
+
+		res.sendStatus(204);
+	},
+);
 
 export default router;
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 6493c16a..553ab17e 100644
--- a/src/api/routes/channels/#channel_id/messages/bulk-delete.ts
+++ b/src/api/routes/channels/#channel_id/messages/bulk-delete.ts
@@ -1,5 +1,13 @@
 import { Router, Response, Request } from "express";
-import { Channel, Config, emitEvent, getPermission, getRights, MessageDeleteBulkEvent, Message } from "@fosscord/util";
+import {
+	Channel,
+	Config,
+	emitEvent,
+	getPermission,
+	getRights,
+	MessageDeleteBulkEvent,
+	Message,
+} from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { route } from "@fosscord/api";
 
@@ -10,33 +18,48 @@ export default router;
 // should users be able to bulk delete messages or only bots? ANSWER: all users
 // should this request fail, if you provide messages older than 14 days/invalid ids? ANSWER: NO
 // https://discord.com/developers/docs/resources/channel#bulk-delete-messages
-router.post("/", route({ body: "BulkDeleteSchema" }), async (req: Request, res: Response) => {
-	const { channel_id } = req.params;
-	const channel = await Channel.findOneOrFail({ where: { id: channel_id } });
-	if (!channel.guild_id) throw new HTTPError("Can't bulk delete dm channel messages", 400);
-
-	const rights = await getRights(req.user_id);
-	rights.hasThrow("SELF_DELETE_MESSAGES");
-	
-	let superuser = rights.has("MANAGE_MESSAGES");
-	const permission = await getPermission(req.user_id, channel?.guild_id, channel_id);
-		
-	const { maxBulkDelete } = Config.get().limits.message;
-
-	const { messages } = req.body as { messages: string[] };
-	if (messages.length === 0) throw new HTTPError("You must specify messages to bulk delete");
-	if (!superuser) {
-		permission.hasThrow("MANAGE_MESSAGES");
-		if (messages.length > maxBulkDelete) throw new HTTPError(`You cannot delete more than ${maxBulkDelete} messages`);
-	}
-
-	await Message.delete(messages);
-
-	await emitEvent({
-		event: "MESSAGE_DELETE_BULK",
-		channel_id,
-		data: { ids: messages, channel_id, guild_id: channel.guild_id }
-	} as MessageDeleteBulkEvent);
-
-	res.sendStatus(204);
-});
+router.post(
+	"/",
+	route({ body: "BulkDeleteSchema" }),
+	async (req: Request, res: Response) => {
+		const { channel_id } = req.params;
+		const channel = await Channel.findOneOrFail({
+			where: { id: channel_id },
+		});
+		if (!channel.guild_id)
+			throw new HTTPError("Can't bulk delete dm channel messages", 400);
+
+		const rights = await getRights(req.user_id);
+		rights.hasThrow("SELF_DELETE_MESSAGES");
+
+		let superuser = rights.has("MANAGE_MESSAGES");
+		const permission = await getPermission(
+			req.user_id,
+			channel?.guild_id,
+			channel_id,
+		);
+
+		const { maxBulkDelete } = Config.get().limits.message;
+
+		const { messages } = req.body as { messages: string[] };
+		if (messages.length === 0)
+			throw new HTTPError("You must specify messages to bulk delete");
+		if (!superuser) {
+			permission.hasThrow("MANAGE_MESSAGES");
+			if (messages.length > maxBulkDelete)
+				throw new HTTPError(
+					`You cannot delete more than ${maxBulkDelete} messages`,
+				);
+		}
+
+		await Message.delete(messages);
+
+		await emitEvent({
+			event: "MESSAGE_DELETE_BULK",
+			channel_id,
+			data: { ids: messages, channel_id, guild_id: channel.guild_id },
+		} as MessageDeleteBulkEvent);
+
+		res.sendStatus(204);
+	},
+);
diff --git a/src/api/routes/channels/#channel_id/messages/index.ts b/src/api/routes/channels/#channel_id/messages/index.ts
index bee93e80..631074c6 100644
--- a/src/api/routes/channels/#channel_id/messages/index.ts
+++ b/src/api/routes/channels/#channel_id/messages/index.ts
@@ -61,36 +61,50 @@ router.get("/", async (req: Request, res: Response) => {
 	const before = req.query.before ? `${req.query.before}` : undefined;
 	const after = req.query.after ? `${req.query.after}` : undefined;
 	const limit = Number(req.query.limit) || 50;
-	if (limit < 1 || limit > 100) throw new HTTPError("limit must be between 1 and 100", 422);
+	if (limit < 1 || limit > 100)
+		throw new HTTPError("limit must be between 1 and 100", 422);
 
 	var halfLimit = Math.floor(limit / 2);
 
-	const permissions = await getPermission(req.user_id, channel.guild_id, channel_id);
+	const permissions = await getPermission(
+		req.user_id,
+		channel.guild_id,
+		channel_id,
+	);
 	permissions.hasThrow("VIEW_CHANNEL");
 	if (!permissions.has("READ_MESSAGE_HISTORY")) return res.json([]);
 
-	var query: FindManyOptions<Message> & { where: { id?: any; }; } = {
+	var query: FindManyOptions<Message> & { where: { id?: any } } = {
 		order: { timestamp: "DESC" },
 		take: limit,
 		where: { channel_id },
-		relations: ["author", "webhook", "application", "mentions", "mention_roles", "mention_channels", "sticker_items", "attachments"]
+		relations: [
+			"author",
+			"webhook",
+			"application",
+			"mentions",
+			"mention_roles",
+			"mention_channels",
+			"sticker_items",
+			"attachments",
+		],
 	};
 
 	if (after) {
-		if (BigInt(after) > BigInt(Snowflake.generate())) return res.status(422);
+		if (BigInt(after) > BigInt(Snowflake.generate()))
+			return res.status(422);
 		query.where.id = MoreThan(after);
-	}
-	else if (before) {
-		if (BigInt(before) < BigInt(req.params.channel_id)) return res.status(422);
+	} else if (before) {
+		if (BigInt(before) < BigInt(req.params.channel_id))
+			return res.status(422);
 		query.where.id = LessThan(before);
-	}
-	else if (around) {
+	} else if (around) {
 		query.where.id = [
 			MoreThan((BigInt(around) - BigInt(halfLimit)).toString()),
-			LessThan((BigInt(around) + BigInt(halfLimit)).toString())
+			LessThan((BigInt(around) + BigInt(halfLimit)).toString()),
 		];
 
-		return res.json([]);	// TODO: fix around
+		return res.json([]); // TODO: fix around
 	}
 
 	const messages = await Message.find(query);
@@ -105,11 +119,22 @@ router.get("/", async (req: Request, res: Response) => {
 				delete x.user_ids;
 			});
 			// @ts-ignore
-			if (!x.author) x.author = { id: "4", discriminator: "0000", username: "Fosscord Ghost", public_flags: "0", avatar: null };
+			if (!x.author)
+				x.author = {
+					id: "4",
+					discriminator: "0000",
+					username: "Fosscord Ghost",
+					public_flags: "0",
+					avatar: null,
+				};
 			x.attachments?.forEach((y: any) => {
 				// dynamically set attachment proxy_url in case the endpoint changed
-				const uri = y.proxy_url.startsWith("http") ? y.proxy_url : `https://example.org${y.proxy_url}`;
-				y.proxy_url = `${endpoint == null ? "" : endpoint}${new URL(uri).pathname}`;
+				const uri = y.proxy_url.startsWith("http")
+					? y.proxy_url
+					: `https://example.org${y.proxy_url}`;
+				y.proxy_url = `${endpoint == null ? "" : endpoint}${
+					new URL(uri).pathname
+				}`;
 			});
 
 			/**
@@ -123,7 +148,7 @@ router.get("/", async (req: Request, res: Response) => {
 			// }
 
 			return x;
-		})
+		}),
 	);
 });
 
@@ -134,7 +159,7 @@ const messageUpload = multer({
 		fields: 10,
 		// files: 1
 	},
-	storage: multer.memoryStorage()
+	storage: multer.memoryStorage(),
 }); // max upload 50 mb
 /**
  TODO: dynamically change limit of MessageCreateSchema with config
@@ -155,24 +180,38 @@ router.post(
 
 		next();
 	},
-	route({ body: "MessageCreateSchema", permission: "SEND_MESSAGES", right: "SEND_MESSAGES" }),
+	route({
+		body: "MessageCreateSchema",
+		permission: "SEND_MESSAGES",
+		right: "SEND_MESSAGES",
+	}),
 	async (req: Request, res: Response) => {
 		const { channel_id } = req.params;
 		var body = req.body as MessageCreateSchema;
 		const attachments: Attachment[] = [];
 
-		const channel = await Channel.findOneOrFail({ where: { id: channel_id }, relations: ["recipients", "recipients.user"] });
+		const channel = await Channel.findOneOrFail({
+			where: { id: channel_id },
+			relations: ["recipients", "recipients.user"],
+		});
 		if (!channel.isWritable()) {
-			throw new HTTPError(`Cannot send messages to channel of type ${channel.type}`, 400);
+			throw new HTTPError(
+				`Cannot send messages to channel of type ${channel.type}`,
+				400,
+			);
 		}
 
-		const files = req.files as Express.Multer.File[] ?? [];
+		const files = (req.files as Express.Multer.File[]) ?? [];
 		for (var currFile of files) {
 			try {
-				const file = await uploadFile(`/attachments/${channel.id}`, currFile);
-				attachments.push(Attachment.create({ ...file, proxy_url: file.url }));
-			}
-			catch (error) {
+				const file = await uploadFile(
+					`/attachments/${channel.id}`,
+					currFile,
+				);
+				attachments.push(
+					Attachment.create({ ...file, proxy_url: file.url }),
+				);
+			} catch (error) {
 				return res.status(400).json(error);
 			}
 		}
@@ -188,7 +227,7 @@ router.post(
 			channel_id,
 			attachments,
 			edited_timestamp: undefined,
-			timestamp: new Date()
+			timestamp: new Date(),
 		});
 
 		channel.last_message_id = message.id;
@@ -205,32 +244,47 @@ router.post(
 							recipient.save(),
 							emitEvent({
 								event: "CHANNEL_CREATE",
-								data: channel_dto.excludedRecipients([recipient.user_id]),
-								user_id: recipient.user_id
-							})
+								data: channel_dto.excludedRecipients([
+									recipient.user_id,
+								]),
+								user_id: recipient.user_id,
+							}),
 						]);
 					}
-				})
+				}),
 			);
 		}
 
-		const member = await Member.findOneOrFail({ where: { id: req.user_id }, relations: ["roles"] });
-		member.roles = member.roles.filter((role: Role) => {
-			return role.id !== role.guild_id;
-		}).map((role: Role) => {
-			return role.id;
-		}) as any;
+		const member = await Member.findOneOrFail({
+			where: { id: req.user_id },
+			relations: ["roles"],
+		});
+		member.roles = member.roles
+			.filter((role: Role) => {
+				return role.id !== role.guild_id;
+			})
+			.map((role: Role) => {
+				return role.id;
+			}) as any;
 
 		await Promise.all([
 			message.save(),
-			emitEvent({ event: "MESSAGE_CREATE", channel_id: channel_id, data: message } as MessageCreateEvent),
-			message.guild_id ? Member.update({ id: req.user_id, guild_id: message.guild_id }, { last_message_id: message.id }) : null,
-			channel.save()
+			emitEvent({
+				event: "MESSAGE_CREATE",
+				channel_id: channel_id,
+				data: message,
+			} as MessageCreateEvent),
+			message.guild_id
+				? Member.update(
+						{ id: req.user_id, guild_id: message.guild_id },
+						{ last_message_id: message.id },
+				  )
+				: null,
+			channel.save(),
 		]);
 
-		postHandleMessage(message).catch((e) => { }); // no await as it shouldnt block the message send function and silently catch error
+		postHandleMessage(message).catch((e) => {}); // no await as it shouldnt block the message send function and silently catch error
 
 		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 e74a0255..89be843f 100644
--- a/src/api/routes/channels/#channel_id/permissions.ts
+++ b/src/api/routes/channels/#channel_id/permissions.ts
@@ -6,7 +6,7 @@ import {
 	emitEvent,
 	getPermission,
 	Member,
-	Role
+	Role,
 } from "@fosscord/util";
 import { Router, Response, Request } from "express";
 import { HTTPError } from "lambert-server";
@@ -16,69 +16,90 @@ const router: Router = Router();
 
 // TODO: Only permissions your bot has in the guild or channel can be allowed/denied (unless your bot has a MANAGE_ROLES overwrite in the channel)
 
-export interface ChannelPermissionOverwriteSchema extends ChannelPermissionOverwrite { }
+export interface ChannelPermissionOverwriteSchema
+	extends ChannelPermissionOverwrite {}
 
 router.put(
 	"/:overwrite_id",
-	route({ body: "ChannelPermissionOverwriteSchema", permission: "MANAGE_ROLES" }),
+	route({
+		body: "ChannelPermissionOverwriteSchema",
+		permission: "MANAGE_ROLES",
+	}),
 	async (req: Request, res: Response) => {
 		const { channel_id, overwrite_id } = req.params;
 		const body = req.body as ChannelPermissionOverwriteSchema;
 
-		var channel = await Channel.findOneOrFail({ where: { id: channel_id } });
+		var channel = await Channel.findOneOrFail({
+			where: { id: channel_id },
+		});
 		if (!channel.guild_id) throw new HTTPError("Channel not found", 404);
 
 		if (body.type === 0) {
-			if (!(await Role.count({ where: { id: overwrite_id } }))) throw new HTTPError("role not found", 404);
+			if (!(await Role.count({ where: { id: overwrite_id } })))
+				throw new HTTPError("role not found", 404);
 		} else if (body.type === 1) {
-			if (!(await Member.count({ where: { id: overwrite_id } }))) throw new HTTPError("user not found", 404);
+			if (!(await Member.count({ where: { id: overwrite_id } })))
+				throw new HTTPError("user not found", 404);
 		} else throw new HTTPError("type not supported", 501);
 
-		// @ts-ignore
-		var overwrite: ChannelPermissionOverwrite = channel.permission_overwrites.find((x) => x.id === overwrite_id);
+		//@ts-ignore
+		var overwrite: ChannelPermissionOverwrite =
+			channel.permission_overwrites?.find((x) => x.id === overwrite_id);
 		if (!overwrite) {
 			// @ts-ignore
 			overwrite = {
 				id: overwrite_id,
-				type: body.type
+				type: body.type,
 			};
 			channel.permission_overwrites!.push(overwrite);
 		}
-		overwrite.allow = String(req.permission!.bitfield & (BigInt(body.allow) || BigInt("0")));
-		overwrite.deny = String(req.permission!.bitfield & (BigInt(body.deny) || BigInt("0")));
+		overwrite.allow = String(
+			req.permission!.bitfield & (BigInt(body.allow) || BigInt("0")),
+		);
+		overwrite.deny = String(
+			req.permission!.bitfield & (BigInt(body.deny) || BigInt("0")),
+		);
 
 		await Promise.all([
 			channel.save(),
 			emitEvent({
 				event: "CHANNEL_UPDATE",
 				channel_id,
-				data: channel
-			} as ChannelUpdateEvent)
+				data: channel,
+			} as ChannelUpdateEvent),
 		]);
 
 		return res.sendStatus(204);
-	}
+	},
 );
 
 // TODO: check permission hierarchy
-router.delete("/:overwrite_id", route({ permission: "MANAGE_ROLES" }), async (req: Request, res: Response) => {
-	const { channel_id, overwrite_id } = req.params;
+router.delete(
+	"/:overwrite_id",
+	route({ permission: "MANAGE_ROLES" }),
+	async (req: Request, res: Response) => {
+		const { channel_id, overwrite_id } = req.params;
 
-	const channel = await Channel.findOneOrFail({ where: { id: channel_id } });
-	if (!channel.guild_id) throw new HTTPError("Channel not found", 404);
+		const channel = await Channel.findOneOrFail({
+			where: { id: channel_id },
+		});
+		if (!channel.guild_id) throw new HTTPError("Channel not found", 404);
 
-	channel.permission_overwrites = channel.permission_overwrites!.filter((x) => x.id === overwrite_id);
+		channel.permission_overwrites = channel.permission_overwrites!.filter(
+			(x) => x.id === overwrite_id,
+		);
 
-	await Promise.all([
-		channel.save(),
-		emitEvent({
-			event: "CHANNEL_UPDATE",
-			channel_id,
-			data: channel
-		} as ChannelUpdateEvent)
-	]);
+		await Promise.all([
+			channel.save(),
+			emitEvent({
+				event: "CHANNEL_UPDATE",
+				channel_id,
+				data: channel,
+			} as ChannelUpdateEvent),
+		]);
 
-	return res.sendStatus(204);
-});
+		return res.sendStatus(204);
+	},
+);
 
 export default router;
diff --git a/src/api/routes/channels/#channel_id/pins.ts b/src/api/routes/channels/#channel_id/pins.ts
index 30507c71..d3f6960a 100644
--- a/src/api/routes/channels/#channel_id/pins.ts
+++ b/src/api/routes/channels/#channel_id/pins.ts
@@ -6,7 +6,7 @@ import {
 	getPermission,
 	Message,
 	MessageUpdateEvent,
-	DiscordApiErrors
+	DiscordApiErrors,
 } from "@fosscord/util";
 import { Router, Request, Response } from "express";
 import { HTTPError } from "lambert-server";
@@ -14,77 +14,100 @@ import { route } from "@fosscord/api";
 
 const router: Router = Router();
 
-router.put("/:message_id", route({ permission: "VIEW_CHANNEL" }), async (req: Request, res: Response) => {
-	const { channel_id, message_id } = req.params;
-
-	const message = await Message.findOneOrFail({ where: { id: message_id } });
-
-	// * in dm channels anyone can pin messages -> only check for guilds
-	if (message.guild_id) req.permission!.hasThrow("MANAGE_MESSAGES");
-
-	const pinned_count = await Message.count({ where: { channel: { id: channel_id }, pinned: true } });
-	const { maxPins } = Config.get().limits.channel;
-	if (pinned_count >= maxPins) throw DiscordApiErrors.MAXIMUM_PINS.withParams(maxPins);
-
-	await Promise.all([
-		Message.update({ id: message_id }, { pinned: true }),
-		emitEvent({
-			event: "MESSAGE_UPDATE",
-			channel_id,
-			data: message
-		} as MessageUpdateEvent),
-		emitEvent({
-			event: "CHANNEL_PINS_UPDATE",
-			channel_id,
-			data: {
+router.put(
+	"/:message_id",
+	route({ permission: "VIEW_CHANNEL" }),
+	async (req: Request, res: Response) => {
+		const { channel_id, message_id } = req.params;
+
+		const message = await Message.findOneOrFail({
+			where: { id: message_id },
+		});
+
+		// * in dm channels anyone can pin messages -> only check for guilds
+		if (message.guild_id) req.permission!.hasThrow("MANAGE_MESSAGES");
+
+		const pinned_count = await Message.count({
+			where: { channel: { id: channel_id }, pinned: true },
+		});
+		const { maxPins } = Config.get().limits.channel;
+		if (pinned_count >= maxPins)
+			throw DiscordApiErrors.MAXIMUM_PINS.withParams(maxPins);
+
+		await Promise.all([
+			Message.update({ id: message_id }, { pinned: true }),
+			emitEvent({
+				event: "MESSAGE_UPDATE",
 				channel_id,
-				guild_id: message.guild_id,
-				last_pin_timestamp: undefined
-			}
-		} as ChannelPinsUpdateEvent)
-	]);
-
-	res.sendStatus(204);
-});
-
-router.delete("/:message_id", route({ permission: "VIEW_CHANNEL" }), async (req: Request, res: Response) => {
-	const { channel_id, message_id } = req.params;
-
-	const channel = await Channel.findOneOrFail({ where: { id: channel_id } });
-	if (channel.guild_id) req.permission!.hasThrow("MANAGE_MESSAGES");
-
-	const message = await Message.findOneOrFail({ where: { id: message_id } });
-	message.pinned = false;
-
-	await Promise.all([
-		message.save(),
-
-		emitEvent({
-			event: "MESSAGE_UPDATE",
-			channel_id,
-			data: message
-		} as MessageUpdateEvent),
-
-		emitEvent({
-			event: "CHANNEL_PINS_UPDATE",
-			channel_id,
-			data: {
+				data: message,
+			} as MessageUpdateEvent),
+			emitEvent({
+				event: "CHANNEL_PINS_UPDATE",
 				channel_id,
-				guild_id: channel.guild_id,
-				last_pin_timestamp: undefined
-			}
-		} as ChannelPinsUpdateEvent)
-	]);
-
-	res.sendStatus(204);
-});
-
-router.get("/", route({ permission: ["READ_MESSAGE_HISTORY"] }), async (req: Request, res: Response) => {
-	const { channel_id } = req.params;
-
-	let pins = await Message.find({ where: { channel_id: channel_id, pinned: true } });
+				data: {
+					channel_id,
+					guild_id: message.guild_id,
+					last_pin_timestamp: undefined,
+				},
+			} as ChannelPinsUpdateEvent),
+		]);
+
+		res.sendStatus(204);
+	},
+);
+
+router.delete(
+	"/:message_id",
+	route({ permission: "VIEW_CHANNEL" }),
+	async (req: Request, res: Response) => {
+		const { channel_id, message_id } = req.params;
+
+		const channel = await Channel.findOneOrFail({
+			where: { id: channel_id },
+		});
+		if (channel.guild_id) req.permission!.hasThrow("MANAGE_MESSAGES");
+
+		const message = await Message.findOneOrFail({
+			where: { id: message_id },
+		});
+		message.pinned = false;
+
+		await Promise.all([
+			message.save(),
+
+			emitEvent({
+				event: "MESSAGE_UPDATE",
+				channel_id,
+				data: message,
+			} as MessageUpdateEvent),
 
-	res.send(pins);
-});
+			emitEvent({
+				event: "CHANNEL_PINS_UPDATE",
+				channel_id,
+				data: {
+					channel_id,
+					guild_id: channel.guild_id,
+					last_pin_timestamp: undefined,
+				},
+			} as ChannelPinsUpdateEvent),
+		]);
+
+		res.sendStatus(204);
+	},
+);
+
+router.get(
+	"/",
+	route({ permission: ["READ_MESSAGE_HISTORY"] }),
+	async (req: Request, res: Response) => {
+		const { channel_id } = req.params;
+
+		let pins = await Message.find({
+			where: { channel_id: channel_id, pinned: true },
+		});
+
+		res.send(pins);
+	},
+);
 
 export default router;
diff --git a/src/api/routes/channels/#channel_id/purge.ts b/src/api/routes/channels/#channel_id/purge.ts
index 9fe6b658..a9f88662 100644
--- a/src/api/routes/channels/#channel_id/purge.ts
+++ b/src/api/routes/channels/#channel_id/purge.ts
@@ -21,52 +21,79 @@ export default router;
 /**
 TODO: apply the delete bit by bit to prevent client and database stress
 **/
-router.post("/", route({ /*body: "PurgeSchema",*/ }), async (req: Request, res: Response) => {
-	const { channel_id } = req.params;
-	const channel = await Channel.findOneOrFail({ where: { id: channel_id } });
+router.post(
+	"/",
+	route({
+		/*body: "PurgeSchema",*/
+	}),
+	async (req: Request, res: Response) => {
+		const { channel_id } = req.params;
+		const channel = await Channel.findOneOrFail({
+			where: { id: channel_id },
+		});
 
-	if (!channel.guild_id) throw new HTTPError("Can't purge dm channels", 400);
-	isTextChannel(channel.type);
+		if (!channel.guild_id)
+			throw new HTTPError("Can't purge dm channels", 400);
+		isTextChannel(channel.type);
 
-	const rights = await getRights(req.user_id);
-	if (!rights.has("MANAGE_MESSAGES")) {
-		const permissions = await getPermission(req.user_id, channel.guild_id, channel_id);
-		permissions.hasThrow("MANAGE_MESSAGES");
-		permissions.hasThrow("MANAGE_CHANNELS");
-	}
+		const rights = await getRights(req.user_id);
+		if (!rights.has("MANAGE_MESSAGES")) {
+			const permissions = await getPermission(
+				req.user_id,
+				channel.guild_id,
+				channel_id,
+			);
+			permissions.hasThrow("MANAGE_MESSAGES");
+			permissions.hasThrow("MANAGE_CHANNELS");
+		}
 
-	const { before, after } = req.body as PurgeSchema;
+		const { before, after } = req.body as PurgeSchema;
 
-	// TODO: send the deletion event bite-by-bite to prevent client stress
-
-	var query: FindManyOptions<Message> & { where: { id?: any; }; } = {
-		order: { id: "ASC" },
-		// take: limit,
-		where: {
-			channel_id,
-			id: Between(after, before), // the right way around
-			author_id: rights.has("SELF_DELETE_MESSAGES") ? undefined : Not(req.user_id)
-			// if you lack the right of self-deletion, you can't delete your own messages, even in purges
-		},
-		relations: ["author", "webhook", "application", "mentions", "mention_roles", "mention_channels", "sticker_items", "attachments"]
-	};
+		// TODO: send the deletion event bite-by-bite to prevent client stress
 
+		var query: FindManyOptions<Message> & { where: { id?: any } } = {
+			order: { id: "ASC" },
+			// take: limit,
+			where: {
+				channel_id,
+				id: Between(after, before), // the right way around
+				author_id: rights.has("SELF_DELETE_MESSAGES")
+					? undefined
+					: Not(req.user_id),
+				// if you lack the right of self-deletion, you can't delete your own messages, even in purges
+			},
+			relations: [
+				"author",
+				"webhook",
+				"application",
+				"mentions",
+				"mention_roles",
+				"mention_channels",
+				"sticker_items",
+				"attachments",
+			],
+		};
 
-	const messages = await Message.find(query);
-	const endpoint = Config.get().cdn.endpointPublic;
+		const messages = await Message.find(query);
+		const endpoint = Config.get().cdn.endpointPublic;
 
-	if (messages.length == 0) {
-		res.sendStatus(304);
-		return;
-	}
+		if (messages.length == 0) {
+			res.sendStatus(304);
+			return;
+		}
 
-	await Message.delete(messages.map((x) => x.id));
+		await Message.delete(messages.map((x) => x.id));
 
-	await emitEvent({
-		event: "MESSAGE_DELETE_BULK",
-		channel_id,
-		data: { ids: messages.map(x => x.id), channel_id, guild_id: channel.guild_id }
-	} as MessageDeleteBulkEvent);
+		await emitEvent({
+			event: "MESSAGE_DELETE_BULK",
+			channel_id,
+			data: {
+				ids: messages.map((x) => x.id),
+				channel_id,
+				guild_id: channel.guild_id,
+			},
+		} as MessageDeleteBulkEvent);
 
-	res.sendStatus(204);
-});
+		res.sendStatus(204);
+	},
+);
diff --git a/src/api/routes/channels/#channel_id/recipients.ts b/src/api/routes/channels/#channel_id/recipients.ts
index 25854415..cc7e5756 100644
--- a/src/api/routes/channels/#channel_id/recipients.ts
+++ b/src/api/routes/channels/#channel_id/recipients.ts
@@ -8,7 +8,7 @@ import {
 	emitEvent,
 	PublicUserProjection,
 	Recipient,
-	User
+	User,
 } from "@fosscord/util";
 import { route } from "@fosscord/api";
 
@@ -16,34 +16,48 @@ const router: Router = Router();
 
 router.put("/:user_id", route({}), async (req: Request, res: Response) => {
 	const { channel_id, user_id } = req.params;
-	const channel = await Channel.findOneOrFail({ where: { id: channel_id }, relations: ["recipients"] });
+	const channel = await Channel.findOneOrFail({
+		where: { id: channel_id },
+		relations: ["recipients"],
+	});
 
 	if (channel.type !== ChannelType.GROUP_DM) {
-		const recipients = [...channel.recipients!.map((r) => r.user_id), user_id].unique();
+		const recipients = [
+			...channel.recipients!.map((r) => r.user_id),
+			user_id,
+		].unique();
 
-		const new_channel = await Channel.createDMChannel(recipients, req.user_id);
+		const new_channel = await Channel.createDMChannel(
+			recipients,
+			req.user_id,
+		);
 		return res.status(201).json(new_channel);
 	} else {
 		if (channel.recipients!.map((r) => r.user_id).includes(user_id)) {
 			throw DiscordApiErrors.INVALID_RECIPIENT; //TODO is this the right error?
 		}
 
-		channel.recipients!.push(Recipient.create({ channel_id: channel_id, user_id: user_id }));
+		channel.recipients!.push(
+			Recipient.create({ channel_id: channel_id, user_id: user_id }),
+		);
 		await channel.save();
 
 		await emitEvent({
 			event: "CHANNEL_CREATE",
 			data: await DmChannelDTO.from(channel, [user_id]),
-			user_id: user_id
+			user_id: user_id,
 		});
 
 		await emitEvent({
 			event: "CHANNEL_RECIPIENT_ADD",
 			data: {
 				channel_id: channel_id,
-				user: await User.findOneOrFail({ where: { id: user_id }, select: PublicUserProjection })
+				user: await User.findOneOrFail({
+					where: { id: user_id },
+					select: PublicUserProjection,
+				}),
 			},
-			channel_id: channel_id
+			channel_id: channel_id,
 		} as ChannelRecipientAddEvent);
 		return res.sendStatus(204);
 	}
@@ -51,8 +65,16 @@ router.put("/:user_id", route({}), async (req: Request, res: Response) => {
 
 router.delete("/:user_id", route({}), async (req: Request, res: Response) => {
 	const { channel_id, user_id } = req.params;
-	const channel = await Channel.findOneOrFail({ where: { id: channel_id }, relations: ["recipients"] });
-	if (!(channel.type === ChannelType.GROUP_DM && (channel.owner_id === req.user_id || user_id === req.user_id)))
+	const channel = await Channel.findOneOrFail({
+		where: { id: channel_id },
+		relations: ["recipients"],
+	});
+	if (
+		!(
+			channel.type === ChannelType.GROUP_DM &&
+			(channel.owner_id === req.user_id || user_id === req.user_id)
+		)
+	)
 		throw DiscordApiErrors.MISSING_PERMISSIONS;
 
 	if (!channel.recipients!.map((r) => r.user_id).includes(user_id)) {
diff --git a/src/api/routes/channels/#channel_id/typing.ts b/src/api/routes/channels/#channel_id/typing.ts
index 99460f6e..03f76205 100644
--- a/src/api/routes/channels/#channel_id/typing.ts
+++ b/src/api/routes/channels/#channel_id/typing.ts
@@ -4,26 +4,42 @@ import { Router, Request, Response } from "express";
 
 const router: Router = Router();
 
-router.post("/", route({ permission: "SEND_MESSAGES" }), async (req: Request, res: Response) => {
-	const { channel_id } = req.params;
-	const user_id = req.user_id;
-	const timestamp = Date.now();
-	const channel = await Channel.findOneOrFail({ where: { id: channel_id } });
-	const member = await Member.findOne({ where: { id: user_id, guild_id: channel.guild_id }, relations: ["roles", "user"] });
+router.post(
+	"/",
+	route({ permission: "SEND_MESSAGES" }),
+	async (req: Request, res: Response) => {
+		const { channel_id } = req.params;
+		const user_id = req.user_id;
+		const timestamp = Date.now();
+		const channel = await Channel.findOneOrFail({
+			where: { id: channel_id },
+		});
+		const member = await Member.findOne({
+			where: { id: user_id, guild_id: channel.guild_id },
+			relations: ["roles", "user"],
+		});
 
-	await emitEvent({
-		event: "TYPING_START",
-		channel_id: channel_id,
-		data: {
-			...(member ? { member: { ...member, roles: member?.roles?.map((x) => x.id) } } : null),
-			channel_id,
-			timestamp,
-			user_id,
-			guild_id: channel.guild_id
-		}
-	} as TypingStartEvent);
+		await emitEvent({
+			event: "TYPING_START",
+			channel_id: channel_id,
+			data: {
+				...(member
+					? {
+							member: {
+								...member,
+								roles: member?.roles?.map((x) => x.id),
+							},
+					  }
+					: null),
+				channel_id,
+				timestamp,
+				user_id,
+				guild_id: channel.guild_id,
+			},
+		} as TypingStartEvent);
 
-	res.sendStatus(204);
-});
+		res.sendStatus(204);
+	},
+);
 
 export default router;
diff --git a/src/api/routes/channels/#channel_id/webhooks.ts b/src/api/routes/channels/#channel_id/webhooks.ts
index 99c104ca..da8fe73c 100644
--- a/src/api/routes/channels/#channel_id/webhooks.ts
+++ b/src/api/routes/channels/#channel_id/webhooks.ts
@@ -13,22 +13,29 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 });
 
 // TODO: use Image Data Type for avatar instead of String
-router.post("/", route({ body: "WebhookCreateSchema", permission: "MANAGE_WEBHOOKS" }), async (req: Request, res: Response) => {
-	const channel_id = req.params.channel_id;
-	const channel = await Channel.findOneOrFail({ where: { id: channel_id } });
-
-	isTextChannel(channel.type);
-	if (!channel.guild_id) throw new HTTPError("Not a guild channel", 400);
-
-	const webhook_count = await Webhook.count({ where: { channel_id } });
-	const { maxWebhooks } = Config.get().limits.channel;
-	if (webhook_count > maxWebhooks) throw DiscordApiErrors.MAXIMUM_WEBHOOKS.withParams(maxWebhooks);
-
-	var { avatar, name } = req.body as { name: string; avatar?: string };
-	name = trimSpecial(name);
-	if (name === "clyde") throw new HTTPError("Invalid name", 400);
-
-	// TODO: save webhook in database and send response
-});
+router.post(
+	"/",
+	route({ body: "WebhookCreateSchema", permission: "MANAGE_WEBHOOKS" }),
+	async (req: Request, res: Response) => {
+		const channel_id = req.params.channel_id;
+		const channel = await Channel.findOneOrFail({
+			where: { id: channel_id },
+		});
+
+		isTextChannel(channel.type);
+		if (!channel.guild_id) throw new HTTPError("Not a guild channel", 400);
+
+		const webhook_count = await Webhook.count({ where: { channel_id } });
+		const { maxWebhooks } = Config.get().limits.channel;
+		if (webhook_count > maxWebhooks)
+			throw DiscordApiErrors.MAXIMUM_WEBHOOKS.withParams(maxWebhooks);
+
+		var { avatar, name } = req.body as { name: string; avatar?: string };
+		name = trimSpecial(name);
+		if (name === "clyde") throw new HTTPError("Invalid name", 400);
+
+		// TODO: save webhook in database and send response
+	},
+);
 
 export default router;
diff --git a/src/api/routes/discoverable-guilds.ts b/src/api/routes/discoverable-guilds.ts
index 383e2b24..0e7cfbab 100644
--- a/src/api/routes/discoverable-guilds.ts
+++ b/src/api/routes/discoverable-guilds.ts
@@ -17,19 +17,33 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	if (categories == undefined) {
 		guilds = showAllGuilds
 			? await Guild.find({ take: Math.abs(Number(limit || configLimit)) })
-			: await Guild.find({ where: { features: Like(`%DISCOVERABLE%`) }, take: Math.abs(Number(limit || configLimit)) });
+			: await Guild.find({
+					where: { features: Like(`%DISCOVERABLE%`) },
+					take: Math.abs(Number(limit || configLimit)),
+			  });
 	} else {
 		guilds = showAllGuilds
-			? await Guild.find({ where: { primary_category_id: categories.toString() }, take: Math.abs(Number(limit || configLimit)) })
+			? await Guild.find({
+					where: { primary_category_id: categories.toString() },
+					take: Math.abs(Number(limit || configLimit)),
+			  })
 			: await Guild.find({
-				where: { primary_category_id: categories.toString(), features: Like("%DISCOVERABLE%") },
-				take: Math.abs(Number(limit || configLimit))
-			});
+					where: {
+						primary_category_id: categories.toString(),
+						features: Like("%DISCOVERABLE%"),
+					},
+					take: Math.abs(Number(limit || configLimit)),
+			  });
 	}
 
 	const total = guilds ? guilds.length : undefined;
 
-	res.send({ total: total, guilds: guilds, offset: Number(offset || Config.get().guild.discovery.offset), limit: Number(limit || configLimit) });
+	res.send({
+		total: total,
+		guilds: guilds,
+		offset: Number(offset || Config.get().guild.discovery.offset),
+		limit: Number(limit || configLimit),
+	});
 });
 
 export default router;
diff --git a/src/api/routes/discovery.ts b/src/api/routes/discovery.ts
index 6ab2cc13..90450035 100644
--- a/src/api/routes/discovery.ts
+++ b/src/api/routes/discovery.ts
@@ -10,7 +10,9 @@ router.get("/categories", route({}), async (req: Request, res: Response) => {
 
 	const { locale, primary_only } = req.query;
 
-	const out = primary_only ? await Categories.find() : await Categories.find({ where: { is_primary: true } });
+	const out = primary_only
+		? await Categories.find()
+		: await Categories.find({ where: { is_primary: true } });
 
 	res.send(out);
 });
diff --git a/src/api/routes/downloads.ts b/src/api/routes/downloads.ts
index df3df911..bc0750f7 100644
--- a/src/api/routes/downloads.ts
+++ b/src/api/routes/downloads.ts
@@ -10,9 +10,12 @@ router.get("/:branch", route({}), async (req: Request, res: Response) => {
 	const { platform } = req.query;
 	//TODO
 
-	if (!platform || !["linux", "osx", "win"].includes(platform.toString())) return res.status(404);
+	if (!platform || !["linux", "osx", "win"].includes(platform.toString()))
+		return res.status(404);
 
-	const release = await Release.findOneOrFail({ where: { name: client.releases.upstreamVersion } });
+	const release = await Release.findOneOrFail({
+		where: { name: client.releases.upstreamVersion },
+	});
 
 	res.redirect(release[`win_url`]);
 });
diff --git a/src/api/routes/experiments.ts b/src/api/routes/experiments.ts
index 7be86fb8..b2b7d724 100644
--- a/src/api/routes/experiments.ts
+++ b/src/api/routes/experiments.ts
@@ -5,7 +5,7 @@ const router = Router();
 
 router.get("/", route({}), (req: Request, res: Response) => {
 	// TODO:
-	res.send({ fingerprint: "", assignments: [], guild_experiments:[] });
+	res.send({ fingerprint: "", assignments: [], guild_experiments: [] });
 });
 
 export default router;
diff --git a/src/api/routes/gateway/bot.ts b/src/api/routes/gateway/bot.ts
index f1dbb9df..2e26d019 100644
--- a/src/api/routes/gateway/bot.ts
+++ b/src/api/routes/gateway/bot.ts
@@ -18,9 +18,9 @@ export interface GatewayBotResponse {
 const options: RouteOptions = {
 	test: {
 		response: {
-			body: "GatewayBotResponse"
-		}
-	}
+			body: "GatewayBotResponse",
+		},
+	},
 };
 
 router.get("/", route(options), (req: Request, res: Response) => {
@@ -32,8 +32,8 @@ router.get("/", route(options), (req: Request, res: Response) => {
 			total: 1000,
 			remaining: 999,
 			reset_after: 14400000,
-			max_concurrency: 1
-		}
+			max_concurrency: 1,
+		},
 	});
 });
 
diff --git a/src/api/routes/gateway/index.ts b/src/api/routes/gateway/index.ts
index 9bad7478..a6ed9dc4 100644
--- a/src/api/routes/gateway/index.ts
+++ b/src/api/routes/gateway/index.ts
@@ -11,14 +11,16 @@ export interface GatewayResponse {
 const options: RouteOptions = {
 	test: {
 		response: {
-			body: "GatewayResponse"
-		}
-	}
+			body: "GatewayResponse",
+		},
+	},
 };
 
 router.get("/", route(options), (req: Request, res: Response) => {
 	const { endpointPublic } = Config.get().gateway;
-	res.json({ url: endpointPublic || process.env.GATEWAY || "ws://localhost:3002" });
+	res.json({
+		url: endpointPublic || process.env.GATEWAY || "ws://localhost:3002",
+	});
 });
 
 export default router;
diff --git a/src/api/routes/gifs/search.ts b/src/api/routes/gifs/search.ts
index c7468641..54352215 100644
--- a/src/api/routes/gifs/search.ts
+++ b/src/api/routes/gifs/search.ts
@@ -1,6 +1,6 @@
 import { Router, Response, Request } from "express";
 import fetch from "node-fetch";
-import ProxyAgent from 'proxy-agent';
+import ProxyAgent from "proxy-agent";
 import { route } from "@fosscord/api";
 import { getGifApiKey, parseGifResult } from "./trending";
 
@@ -11,16 +11,19 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	const { q, media_format, locale } = req.query;
 
 	const apiKey = getGifApiKey();
-	
+
 	const agent = new ProxyAgent();
 
-	const response = await fetch(`https://g.tenor.com/v1/search?q=${q}&media_format=${media_format}&locale=${locale}&key=${apiKey}`, {
-		agent,
-		method: "get",
-		headers: { "Content-Type": "application/json" }
-	});
+	const response = await fetch(
+		`https://g.tenor.com/v1/search?q=${q}&media_format=${media_format}&locale=${locale}&key=${apiKey}`,
+		{
+			agent,
+			method: "get",
+			headers: { "Content-Type": "application/json" },
+		},
+	);
 
-	const { results } = await response.json() as any;	// TODO: types
+	const { results } = (await response.json()) as any; // TODO: types
 
 	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 52a8969d..e4b28e24 100644
--- a/src/api/routes/gifs/trending-gifs.ts
+++ b/src/api/routes/gifs/trending-gifs.ts
@@ -1,6 +1,6 @@
 import { Router, Response, Request } from "express";
 import fetch from "node-fetch";
-import ProxyAgent from 'proxy-agent';
+import ProxyAgent from "proxy-agent";
 import { route } from "@fosscord/api";
 import { getGifApiKey, parseGifResult } from "./trending";
 
@@ -11,16 +11,19 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	const { media_format, locale } = req.query;
 
 	const apiKey = getGifApiKey();
-	
+
 	const agent = new ProxyAgent();
 
-	const response = await fetch(`https://g.tenor.com/v1/trending?media_format=${media_format}&locale=${locale}&key=${apiKey}`, {
-		agent,
-		method: "get",
-		headers: { "Content-Type": "application/json" }
-	});
+	const response = await fetch(
+		`https://g.tenor.com/v1/trending?media_format=${media_format}&locale=${locale}&key=${apiKey}`,
+		{
+			agent,
+			method: "get",
+			headers: { "Content-Type": "application/json" },
+		},
+	);
 
-	const { results } = await response.json() as any; // TODO: types
+	const { results } = (await response.json()) as any; // TODO: types
 
 	res.json(results.map(parseGifResult)).status(200);
 });
diff --git a/src/api/routes/gifs/trending.ts b/src/api/routes/gifs/trending.ts
index aa976c3f..58044ea5 100644
--- a/src/api/routes/gifs/trending.ts
+++ b/src/api/routes/gifs/trending.ts
@@ -1,6 +1,6 @@
 import { Router, Response, Request } from "express";
 import fetch from "node-fetch";
-import ProxyAgent from 'proxy-agent';
+import ProxyAgent from "proxy-agent";
 import { route } from "@fosscord/api";
 import { Config } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
@@ -16,14 +16,15 @@ export function parseGifResult(result: any) {
 		gif_src: result.media[0].gif.url,
 		width: result.media[0].mp4.dims[0],
 		height: result.media[0].mp4.dims[1],
-		preview: result.media[0].mp4.preview
+		preview: result.media[0].mp4.preview,
 	};
 }
 
 export function getGifApiKey() {
 	const { enabled, provider, apiKey } = Config.get().gif;
 	if (!enabled) throw new HTTPError(`Gifs are disabled`);
-	if (provider !== "tenor" || !apiKey) throw new HTTPError(`${provider} gif provider not supported`);
+	if (provider !== "tenor" || !apiKey)
+		throw new HTTPError(`${provider} gif provider not supported`);
 
 	return apiKey;
 }
@@ -34,28 +35,37 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	const { media_format, locale } = req.query;
 
 	const apiKey = getGifApiKey();
-	
+
 	const agent = new ProxyAgent();
 
 	const [responseSource, trendGifSource] = await Promise.all([
-		fetch(`https://g.tenor.com/v1/categories?locale=${locale}&key=${apiKey}`, {
-			agent,
-			method: "get",
-			headers: { "Content-Type": "application/json" }
-		}),
-		fetch(`https://g.tenor.com/v1/trending?locale=${locale}&key=${apiKey}`, {
-			agent,
-			method: "get",
-			headers: { "Content-Type": "application/json" }
-		})
+		fetch(
+			`https://g.tenor.com/v1/categories?locale=${locale}&key=${apiKey}`,
+			{
+				agent,
+				method: "get",
+				headers: { "Content-Type": "application/json" },
+			},
+		),
+		fetch(
+			`https://g.tenor.com/v1/trending?locale=${locale}&key=${apiKey}`,
+			{
+				agent,
+				method: "get",
+				headers: { "Content-Type": "application/json" },
+			},
+		),
 	]);
 
-	const { tags } = await responseSource.json() as any; // TODO: types
-	const { results } = await trendGifSource.json() as any; //TODO: types;
+	const { tags } = (await responseSource.json()) as any; // TODO: types
+	const { results } = (await trendGifSource.json()) as any; //TODO: types;
 
 	res.json({
-		categories: tags.map((x: any) => ({ name: x.searchterm, src: x.image })),
-		gifs: [parseGifResult(results[0])]
+		categories: tags.map((x: any) => ({
+			name: x.searchterm,
+			src: x.image,
+		})),
+		gifs: [parseGifResult(results[0])],
 	}).status(200);
 });
 
diff --git a/src/api/routes/guild-recommendations.ts b/src/api/routes/guild-recommendations.ts
index b851d710..bda37973 100644
--- a/src/api/routes/guild-recommendations.ts
+++ b/src/api/routes/guild-recommendations.ts
@@ -13,12 +13,21 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	// TODO: implement this with default typeorm query
 	// const guilds = await Guild.find({ where: { features: "DISCOVERABLE" } }); //, take: Math.abs(Number(limit)) });
 
-	const genLoadId = (size: Number) => [...Array(size)].map(() => Math.floor(Math.random() * 16).toString(16)).join('');
+	const genLoadId = (size: Number) =>
+		[...Array(size)]
+			.map(() => Math.floor(Math.random() * 16).toString(16))
+			.join("");
 
 	const guilds = showAllGuilds
 		? await Guild.find({ take: Math.abs(Number(limit || 24)) })
-		: await Guild.find({ where: { features: Like("%DISCOVERABLE%") }, take: Math.abs(Number(limit || 24)) });
-	res.send({ recommended_guilds: guilds, load_id: `server_recs/${genLoadId(32)}` }).status(200);
+		: await Guild.find({
+				where: { features: Like("%DISCOVERABLE%") },
+				take: Math.abs(Number(limit || 24)),
+		  });
+	res.send({
+		recommended_guilds: guilds,
+		load_id: `server_recs/${genLoadId(32)}`,
+	}).status(200);
 });
 
 export default router;
diff --git a/src/api/routes/guilds/#guild_id/audit-logs.ts b/src/api/routes/guilds/#guild_id/audit-logs.ts
index b54835fc..76a11f6b 100644
--- a/src/api/routes/guilds/#guild_id/audit-logs.ts
+++ b/src/api/routes/guilds/#guild_id/audit-logs.ts
@@ -11,7 +11,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 		webhooks: [],
 		guild_scheduled_events: [],
 		threads: [],
-		application_commands: []
+		application_commands: [],
 	});
 });
 export default router;
diff --git a/src/api/routes/guilds/#guild_id/bans.ts b/src/api/routes/guilds/#guild_id/bans.ts
index ed00f9c0..930985d7 100644
--- a/src/api/routes/guilds/#guild_id/bans.ts
+++ b/src/api/routes/guilds/#guild_id/bans.ts
@@ -1,5 +1,15 @@
 import { Request, Response, Router } from "express";
-import { DiscordApiErrors, emitEvent, GuildBanAddEvent, GuildBanRemoveEvent, Ban, User, Member, BanRegistrySchema, BanModeratorSchema } from "@fosscord/util";
+import {
+	DiscordApiErrors,
+	emitEvent,
+	GuildBanAddEvent,
+	GuildBanRemoveEvent,
+	Ban,
+	User,
+	Member,
+	BanRegistrySchema,
+	BanModeratorSchema,
+} from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { getIpAdress, route } from "@fosscord/api";
 
@@ -7,150 +17,184 @@ const router: Router = Router();
 
 /* TODO: Deleting the secrets is just a temporary go-around. Views should be implemented for both safety and better handling. */
 
-router.get("/", route({ permission: "BAN_MEMBERS" }), async (req: Request, res: Response) => {
-	const { guild_id } = req.params;
+router.get(
+	"/",
+	route({ permission: "BAN_MEMBERS" }),
+	async (req: Request, res: Response) => {
+		const { guild_id } = req.params;
 
-	let bans = await Ban.find({ where: { guild_id: guild_id } });
-	let promisesToAwait: object[] = [];
-	const bansObj: object[] = [];
+		let bans = await Ban.find({ where: { guild_id: guild_id } });
+		let promisesToAwait: object[] = [];
+		const bansObj: object[] = [];
 
-	bans.filter((ban) => ban.user_id !== ban.executor_id); // pretend self-bans don't exist to prevent victim chasing
+		bans.filter((ban) => ban.user_id !== ban.executor_id); // pretend self-bans don't exist to prevent victim chasing
 
-	bans.forEach((ban) => {
-		promisesToAwait.push(User.getPublicUser(ban.user_id));
-	});
-
-	const bannedUsers: object[] = await Promise.all(promisesToAwait);
-
-	bans.forEach((ban, index) => {
-		const user = bannedUsers[index] as User;
-		bansObj.push({
-			reason: ban.reason,
-			user: {
-				username: user.username,
-				discriminator: user.discriminator,
-				id: user.id,
-				avatar: user.avatar,
-				public_flags: user.public_flags
-			}
+		bans.forEach((ban) => {
+			promisesToAwait.push(User.getPublicUser(ban.user_id));
 		});
-	});
-
-	return res.json(bansObj);
-});
-
-router.get("/:user", route({ permission: "BAN_MEMBERS" }), async (req: Request, res: Response) => {
-	const { guild_id } = req.params;
-	const user_id = req.params.ban;
-
-	let ban = await Ban.findOneOrFail({ where: { guild_id: guild_id, user_id: user_id } }) as BanRegistrySchema;
-
-	if (ban.user_id === ban.executor_id) throw DiscordApiErrors.UNKNOWN_BAN;
-	// pretend self-bans don't exist to prevent victim chasing
-
-	/* Filter secret from registry. */
-
-	ban = ban as BanModeratorSchema;
-
-	delete ban.ip;
-
-	return res.json(ban);
-});
-
-router.put("/:user_id", route({ body: "BanCreateSchema", permission: "BAN_MEMBERS" }), async (req: Request, res: Response) => {
-	const { guild_id } = req.params;
-	const banned_user_id = req.params.user_id;
 
-	if ((req.user_id === banned_user_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) throw new HTTPError("You can't ban the owner", 400);
-
-	const banned_user = await User.getPublicUser(banned_user_id);
+		const bannedUsers: object[] = await Promise.all(promisesToAwait);
+
+		bans.forEach((ban, index) => {
+			const user = bannedUsers[index] as User;
+			bansObj.push({
+				reason: ban.reason,
+				user: {
+					username: user.username,
+					discriminator: user.discriminator,
+					id: user.id,
+					avatar: user.avatar,
+					public_flags: user.public_flags,
+				},
+			});
+		});
 
-	const ban = Ban.create({
-		user_id: banned_user_id,
-		guild_id: guild_id,
-		ip: getIpAdress(req),
-		executor_id: req.user_id,
-		reason: req.body.reason // || otherwise empty
-	});
+		return res.json(bansObj);
+	},
+);
+
+router.get(
+	"/:user",
+	route({ permission: "BAN_MEMBERS" }),
+	async (req: Request, res: Response) => {
+		const { guild_id } = req.params;
+		const user_id = req.params.ban;
+
+		let ban = (await Ban.findOneOrFail({
+			where: { guild_id: guild_id, user_id: user_id },
+		})) as BanRegistrySchema;
+
+		if (ban.user_id === ban.executor_id) throw DiscordApiErrors.UNKNOWN_BAN;
+		// pretend self-bans don't exist to prevent victim chasing
+
+		/* Filter secret from registry. */
+
+		ban = ban as BanModeratorSchema;
+
+		delete ban.ip;
+
+		return res.json(ban);
+	},
+);
+
+router.put(
+	"/:user_id",
+	route({ body: "BanCreateSchema", permission: "BAN_MEMBERS" }),
+	async (req: Request, res: Response) => {
+		const { guild_id } = req.params;
+		const banned_user_id = req.params.user_id;
+
+		if (
+			req.user_id === banned_user_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)
+			throw new HTTPError("You can't ban the owner", 400);
+
+		const banned_user = await User.getPublicUser(banned_user_id);
+
+		const ban = Ban.create({
+			user_id: banned_user_id,
+			guild_id: guild_id,
+			ip: getIpAdress(req),
+			executor_id: req.user_id,
+			reason: req.body.reason, // || otherwise empty
+		});
 
-	await Promise.all([
-		Member.removeFromGuild(banned_user_id, guild_id),
-		ban.save(),
-		emitEvent({
-			event: "GUILD_BAN_ADD",
-			data: {
-				guild_id: guild_id,
-				user: banned_user
-			},
-			guild_id: guild_id
-		} as GuildBanAddEvent)
-	]);
-
-	return res.json(ban);
-});
-
-router.put("/@me", route({ body: "BanCreateSchema" }), async (req: Request, res: Response) => {
-	const { guild_id } = req.params;
-
-	const banned_user = await User.getPublicUser(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);
-
-	const ban = Ban.create({
-		user_id: req.params.user_id,
-		guild_id: guild_id,
-		ip: getIpAdress(req),
-		executor_id: req.params.user_id,
-		reason: req.body.reason // || otherwise empty
-	});
-
-	await Promise.all([
-		Member.removeFromGuild(req.user_id, guild_id),
-		ban.save(),
-		emitEvent({
-			event: "GUILD_BAN_ADD",
-			data: {
+		await Promise.all([
+			Member.removeFromGuild(banned_user_id, guild_id),
+			ban.save(),
+			emitEvent({
+				event: "GUILD_BAN_ADD",
+				data: {
+					guild_id: guild_id,
+					user: banned_user,
+				},
 				guild_id: guild_id,
-				user: banned_user
-			},
-			guild_id: guild_id
-		} as GuildBanAddEvent)
-	]);
+			} as GuildBanAddEvent),
+		]);
+
+		return res.json(ban);
+	},
+);
+
+router.put(
+	"/@me",
+	route({ body: "BanCreateSchema" }),
+	async (req: Request, res: Response) => {
+		const { guild_id } = req.params;
+
+		const banned_user = await User.getPublicUser(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,
+			);
+
+		const ban = Ban.create({
+			user_id: req.params.user_id,
+			guild_id: guild_id,
+			ip: getIpAdress(req),
+			executor_id: req.params.user_id,
+			reason: req.body.reason, // || otherwise empty
+		});
 
-	return res.json(ban);
-});
+		await Promise.all([
+			Member.removeFromGuild(req.user_id, guild_id),
+			ban.save(),
+			emitEvent({
+				event: "GUILD_BAN_ADD",
+				data: {
+					guild_id: guild_id,
+					user: banned_user,
+				},
+				guild_id: guild_id,
+			} as GuildBanAddEvent),
+		]);
 
-router.delete("/:user_id", route({ permission: "BAN_MEMBERS" }), async (req: Request, res: Response) => {
-	const { guild_id, user_id } = req.params;
+		return res.json(ban);
+	},
+);
 
-	let ban = await Ban.findOneOrFail({ where: { guild_id: guild_id, user_id: user_id } });
+router.delete(
+	"/:user_id",
+	route({ permission: "BAN_MEMBERS" }),
+	async (req: Request, res: Response) => {
+		const { guild_id, user_id } = req.params;
 
-	if (ban.user_id === ban.executor_id) throw DiscordApiErrors.UNKNOWN_BAN;
-	// make self-bans irreversible and hide them from view to avoid victim chasing
+		let ban = await Ban.findOneOrFail({
+			where: { guild_id: guild_id, user_id: user_id },
+		});
 
-	const banned_user = await User.getPublicUser(user_id);
+		if (ban.user_id === ban.executor_id) throw DiscordApiErrors.UNKNOWN_BAN;
+		// make self-bans irreversible and hide them from view to avoid victim chasing
 
-	await Promise.all([
-		Ban.delete({
-			user_id: user_id,
-			guild_id
-		}),
+		const banned_user = await User.getPublicUser(user_id);
 
-		emitEvent({
-			event: "GUILD_BAN_REMOVE",
-			data: {
+		await Promise.all([
+			Ban.delete({
+				user_id: user_id,
 				guild_id,
-				user: banned_user
-			},
-			guild_id
-		} as GuildBanRemoveEvent)
-	]);
-
-	return res.status(204).send();
-});
+			}),
+
+			emitEvent({
+				event: "GUILD_BAN_REMOVE",
+				data: {
+					guild_id,
+					user: banned_user,
+				},
+				guild_id,
+			} as GuildBanRemoveEvent),
+		]);
+
+		return res.status(204).send();
+	},
+);
 
 export default router;
diff --git a/src/api/routes/guilds/#guild_id/channels.ts b/src/api/routes/guilds/#guild_id/channels.ts
index 7a5b50d1..af17465d 100644
--- a/src/api/routes/guilds/#guild_id/channels.ts
+++ b/src/api/routes/guilds/#guild_id/channels.ts
@@ -1,5 +1,10 @@
 import { Router, Response, Request } from "express";
-import { Channel, ChannelUpdateEvent, emitEvent, ChannelModifySchema } from "@fosscord/util";
+import {
+	Channel,
+	ChannelUpdateEvent,
+	emitEvent,
+	ChannelModifySchema,
+} from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { route } from "@fosscord/api";
 const router = Router();
@@ -11,49 +16,77 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	res.json(channels);
 });
 
-router.post("/", route({ body: "ChannelModifySchema", permission: "MANAGE_CHANNELS" }), async (req: Request, res: Response) => {
-	// creates a new guild channel https://discord.com/developers/docs/resources/guild#create-guild-channel
-	const { guild_id } = req.params;
-	const body = req.body as ChannelModifySchema;
+router.post(
+	"/",
+	route({ body: "ChannelModifySchema", permission: "MANAGE_CHANNELS" }),
+	async (req: Request, res: Response) => {
+		// creates a new guild channel https://discord.com/developers/docs/resources/guild#create-guild-channel
+		const { guild_id } = req.params;
+		const body = req.body as ChannelModifySchema;
 
-	const channel = await Channel.createChannel({ ...body, guild_id }, req.user_id);
+		const channel = await Channel.createChannel(
+			{ ...body, guild_id },
+			req.user_id,
+		);
 
-	res.status(201).json(channel);
-});
+		res.status(201).json(channel);
+	},
+);
 
-export type ChannelReorderSchema = { id: string; position?: number; lock_permissions?: boolean; parent_id?: string; }[];
+export type ChannelReorderSchema = {
+	id: string;
+	position?: number;
+	lock_permissions?: boolean;
+	parent_id?: string;
+}[];
 
-router.patch("/", route({ body: "ChannelReorderSchema", permission: "MANAGE_CHANNELS" }), async (req: Request, res: Response) => {
-	// changes guild channel position
-	const { guild_id } = req.params;
-	const body = req.body as ChannelReorderSchema;
+router.patch(
+	"/",
+	route({ body: "ChannelReorderSchema", permission: "MANAGE_CHANNELS" }),
+	async (req: Request, res: Response) => {
+		// changes guild channel position
+		const { guild_id } = req.params;
+		const body = req.body as ChannelReorderSchema;
 
-	await Promise.all([
-		body.map(async (x) => {
-			if (x.position == null && !x.parent_id) throw new HTTPError(`You need to at least specify position or parent_id`, 400);
+		await Promise.all([
+			body.map(async (x) => {
+				if (x.position == null && !x.parent_id)
+					throw new HTTPError(
+						`You need to at least specify position or parent_id`,
+						400,
+					);
 
-			const opts: any = {};
-			if (x.position != null) opts.position = x.position;
+				const opts: any = {};
+				if (x.position != null) opts.position = x.position;
 
-			if (x.parent_id) {
-				opts.parent_id = x.parent_id;
-				const parent_channel = await Channel.findOneOrFail({
-					where: { id: x.parent_id, guild_id },
-					select: ["permission_overwrites"]
-				});
-				if (x.lock_permissions) {
-					opts.permission_overwrites = parent_channel.permission_overwrites;
+				if (x.parent_id) {
+					opts.parent_id = x.parent_id;
+					const parent_channel = await Channel.findOneOrFail({
+						where: { id: x.parent_id, guild_id },
+						select: ["permission_overwrites"],
+					});
+					if (x.lock_permissions) {
+						opts.permission_overwrites =
+							parent_channel.permission_overwrites;
+					}
 				}
-			}
 
-			await Channel.update({ guild_id, id: x.id }, opts);
-			const channel = await Channel.findOneOrFail({ where: { guild_id, id: x.id } });
+				await Channel.update({ guild_id, id: x.id }, opts);
+				const channel = await Channel.findOneOrFail({
+					where: { guild_id, id: x.id },
+				});
 
-			await emitEvent({ event: "CHANNEL_UPDATE", data: channel, channel_id: x.id, guild_id } as ChannelUpdateEvent);
-		})
-	]);
+				await emitEvent({
+					event: "CHANNEL_UPDATE",
+					data: channel,
+					channel_id: x.id,
+					guild_id,
+				} as ChannelUpdateEvent);
+			}),
+		]);
 
-	res.sendStatus(204);
-});
+		res.sendStatus(204);
+	},
+);
 
 export default router;
diff --git a/src/api/routes/guilds/#guild_id/delete.ts b/src/api/routes/guilds/#guild_id/delete.ts
index bd158c56..b951e4f4 100644
--- a/src/api/routes/guilds/#guild_id/delete.ts
+++ b/src/api/routes/guilds/#guild_id/delete.ts
@@ -1,4 +1,14 @@
-import { Channel, emitEvent, GuildDeleteEvent, Guild, Member, Message, Role, Invite, Emoji } from "@fosscord/util";
+import {
+	Channel,
+	emitEvent,
+	GuildDeleteEvent,
+	Guild,
+	Member,
+	Message,
+	Role,
+	Invite,
+	Emoji,
+} from "@fosscord/util";
 import { Router, Request, Response } from "express";
 import { HTTPError } from "lambert-server";
 import { route } from "@fosscord/api";
@@ -10,18 +20,22 @@ const router = Router();
 router.post("/", route({}), async (req: Request, res: Response) => {
 	var { guild_id } = req.params;
 
-	const guild = await Guild.findOneOrFail({ where: { id: guild_id }, select: ["owner_id"] });
-	if (guild.owner_id !== req.user_id) throw new HTTPError("You are not the owner of this guild", 401);
+	const guild = await Guild.findOneOrFail({
+		where: { id: guild_id },
+		select: ["owner_id"],
+	});
+	if (guild.owner_id !== req.user_id)
+		throw new HTTPError("You are not the owner of this guild", 401);
 
 	await Promise.all([
 		Guild.delete({ id: guild_id }), // this will also delete all guild related data
 		emitEvent({
 			event: "GUILD_DELETE",
 			data: {
-				id: guild_id
+				id: guild_id,
 			},
-			guild_id: guild_id
-		} as GuildDeleteEvent)
+			guild_id: guild_id,
+		} as GuildDeleteEvent),
 	]);
 
 	return res.sendStatus(204);
diff --git a/src/api/routes/guilds/#guild_id/discovery-requirements.ts b/src/api/routes/guilds/#guild_id/discovery-requirements.ts
index ad20633f..7e63c06b 100644
--- a/src/api/routes/guilds/#guild_id/discovery-requirements.ts
+++ b/src/api/routes/guilds/#guild_id/discovery-requirements.ts
@@ -6,33 +6,33 @@ import { route } from "@fosscord/api";
 const router = Router();
 
 router.get("/", route({}), async (req: Request, res: Response) => {
-	const { guild_id } = req.params;	
-    // TODO:
-    // Load from database
-    // Admin control, but for now it allows anyone to be discoverable
+	const { guild_id } = req.params;
+	// TODO:
+	// Load from database
+	// Admin control, but for now it allows anyone to be discoverable
 
 	res.send({
 		guild_id: guild_id,
 		safe_environment: true,
-        healthy: true,
-        health_score_pending: false,
-        size: true,
-        nsfw_properties: {},
-        protected: true,
-        sufficient: true,
-        sufficient_without_grace_period: true,
-        valid_rules_channel: true,
-        retention_healthy: true,
-        engagement_healthy: true,
-        age: true,
-        minimum_age: 0,
-        health_score: {
-            avg_nonnew_participators: 0,
-            avg_nonnew_communicators: 0,
-            num_intentful_joiners: 0,
-            perc_ret_w1_intentful: 0
-        },
-        minimum_size: 0
+		healthy: true,
+		health_score_pending: false,
+		size: true,
+		nsfw_properties: {},
+		protected: true,
+		sufficient: true,
+		sufficient_without_grace_period: true,
+		valid_rules_channel: true,
+		retention_healthy: true,
+		engagement_healthy: true,
+		age: true,
+		minimum_age: 0,
+		health_score: {
+			avg_nonnew_participators: 0,
+			avg_nonnew_communicators: 0,
+			num_intentful_joiners: 0,
+			perc_ret_w1_intentful: 0,
+		},
+		minimum_size: 0,
 	});
 });
 
diff --git a/src/api/routes/guilds/#guild_id/emojis.ts b/src/api/routes/guilds/#guild_id/emojis.ts
index cf9d742a..6e8570eb 100644
--- a/src/api/routes/guilds/#guild_id/emojis.ts
+++ b/src/api/routes/guilds/#guild_id/emojis.ts
@@ -1,5 +1,17 @@
 import { Router, Request, Response } from "express";
-import { Config, DiscordApiErrors, emitEvent, Emoji, GuildEmojisUpdateEvent, handleFile, Member, Snowflake, User, EmojiCreateSchema, EmojiModifySchema } from "@fosscord/util";
+import {
+	Config,
+	DiscordApiErrors,
+	emitEvent,
+	Emoji,
+	GuildEmojisUpdateEvent,
+	handleFile,
+	Member,
+	Snowflake,
+	User,
+	EmojiCreateSchema,
+	EmojiModifySchema,
+} from "@fosscord/util";
 import { route } from "@fosscord/api";
 
 const router = Router();
@@ -9,7 +21,10 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 
 	await Member.IsInGuildOrFail(req.user_id, guild_id);
 
-	const emojis = await Emoji.find({ where: { guild_id: guild_id }, relations: ["user"] });
+	const emojis = await Emoji.find({
+		where: { guild_id: guild_id },
+		relations: ["user"],
+	});
 
 	return res.json(emojis);
 });
@@ -19,89 +34,115 @@ router.get("/:emoji_id", route({}), async (req: Request, res: Response) => {
 
 	await Member.IsInGuildOrFail(req.user_id, guild_id);
 
-	const emoji = await Emoji.findOneOrFail({ where: { guild_id: guild_id, id: emoji_id }, relations: ["user"] });
+	const emoji = await Emoji.findOneOrFail({
+		where: { guild_id: guild_id, id: emoji_id },
+		relations: ["user"],
+	});
 
 	return res.json(emoji);
 });
 
-router.post("/", route({ body: "EmojiCreateSchema", permission: "MANAGE_EMOJIS_AND_STICKERS" }), async (req: Request, res: Response) => {
-	const { guild_id } = req.params;
-	const body = req.body as EmojiCreateSchema;
-
-	const id = Snowflake.generate();
-	const emoji_count = await Emoji.count({ where: { guild_id: guild_id } });
-	const { maxEmojis } = Config.get().limits.guild;
-
-	if (emoji_count >= maxEmojis) throw DiscordApiErrors.MAXIMUM_NUMBER_OF_EMOJIS_REACHED.withParams(maxEmojis);
-	if (body.require_colons == null) body.require_colons = true;
-
-	const user = await User.findOneOrFail({ where: { id: req.user_id } });
-	body.image = (await handleFile(`/emojis/${id}`, body.image)) as string;
-
-	const emoji = await Emoji.create({
-		id: id,
-		guild_id: guild_id,
-		...body,
-		require_colons: body.require_colons ?? undefined,	// schema allows nulls, db does not
-		user: user,
-		managed: false,
-		animated: false, // TODO: Add support animated emojis
-		available: true,
-		roles: []
-	}).save();
-
-	await emitEvent({
-		event: "GUILD_EMOJIS_UPDATE",
-		guild_id: guild_id,
-		data: {
+router.post(
+	"/",
+	route({
+		body: "EmojiCreateSchema",
+		permission: "MANAGE_EMOJIS_AND_STICKERS",
+	}),
+	async (req: Request, res: Response) => {
+		const { guild_id } = req.params;
+		const body = req.body as EmojiCreateSchema;
+
+		const id = Snowflake.generate();
+		const emoji_count = await Emoji.count({
+			where: { guild_id: guild_id },
+		});
+		const { maxEmojis } = Config.get().limits.guild;
+
+		if (emoji_count >= maxEmojis)
+			throw DiscordApiErrors.MAXIMUM_NUMBER_OF_EMOJIS_REACHED.withParams(
+				maxEmojis,
+			);
+		if (body.require_colons == null) body.require_colons = true;
+
+		const user = await User.findOneOrFail({ where: { id: req.user_id } });
+		body.image = (await handleFile(`/emojis/${id}`, body.image)) as string;
+
+		const emoji = await Emoji.create({
+			id: id,
 			guild_id: guild_id,
-			emojis: await Emoji.find({ where: { guild_id: guild_id } })
-		}
-	} as GuildEmojisUpdateEvent);
+			...body,
+			require_colons: body.require_colons ?? undefined, // schema allows nulls, db does not
+			user: user,
+			managed: false,
+			animated: false, // TODO: Add support animated emojis
+			available: true,
+			roles: [],
+		}).save();
 
-	return res.status(201).json(emoji);
-});
+		await emitEvent({
+			event: "GUILD_EMOJIS_UPDATE",
+			guild_id: guild_id,
+			data: {
+				guild_id: guild_id,
+				emojis: await Emoji.find({ where: { guild_id: guild_id } }),
+			},
+		} as GuildEmojisUpdateEvent);
+
+		return res.status(201).json(emoji);
+	},
+);
 
 router.patch(
 	"/:emoji_id",
-	route({ body: "EmojiModifySchema", permission: "MANAGE_EMOJIS_AND_STICKERS" }),
+	route({
+		body: "EmojiModifySchema",
+		permission: "MANAGE_EMOJIS_AND_STICKERS",
+	}),
 	async (req: Request, res: Response) => {
 		const { emoji_id, guild_id } = req.params;
 		const body = req.body as EmojiModifySchema;
 
-		const emoji = await Emoji.create({ ...body, id: emoji_id, guild_id: guild_id }).save();
+		const emoji = await Emoji.create({
+			...body,
+			id: emoji_id,
+			guild_id: guild_id,
+		}).save();
 
 		await emitEvent({
 			event: "GUILD_EMOJIS_UPDATE",
 			guild_id: guild_id,
 			data: {
 				guild_id: guild_id,
-				emojis: await Emoji.find({ where: { guild_id: guild_id } })
-			}
+				emojis: await Emoji.find({ where: { guild_id: guild_id } }),
+			},
 		} as GuildEmojisUpdateEvent);
 
 		return res.json(emoji);
-	}
+	},
 );
 
-router.delete("/:emoji_id", route({ permission: "MANAGE_EMOJIS_AND_STICKERS" }), async (req: Request, res: Response) => {
-	const { emoji_id, guild_id } = req.params;
+router.delete(
+	"/:emoji_id",
+	route({ permission: "MANAGE_EMOJIS_AND_STICKERS" }),
+	async (req: Request, res: Response) => {
+		const { emoji_id, guild_id } = req.params;
 
-	await Emoji.delete({
-		id: emoji_id,
-		guild_id: guild_id
-	});
+		await Emoji.delete({
+			id: emoji_id,
+			guild_id: guild_id,
+		});
 
-	await emitEvent({
-		event: "GUILD_EMOJIS_UPDATE",
-		guild_id: guild_id,
-		data: {
+		await emitEvent({
+			event: "GUILD_EMOJIS_UPDATE",
 			guild_id: guild_id,
-			emojis: await Emoji.find({ where: { guild_id: guild_id } })
-		}
-	} as GuildEmojisUpdateEvent);
+			data: {
+				guild_id: guild_id,
+				emojis: await Emoji.find({ where: { guild_id: guild_id } }),
+			},
+		} as GuildEmojisUpdateEvent);
 
-	res.sendStatus(204);
-});
+		res.sendStatus(204);
+	},
+);
 
 export default router;
diff --git a/src/api/routes/guilds/#guild_id/index.ts b/src/api/routes/guilds/#guild_id/index.ts
index afeb0938..715a3835 100644
--- a/src/api/routes/guilds/#guild_id/index.ts
+++ b/src/api/routes/guilds/#guild_id/index.ts
@@ -1,5 +1,15 @@
 import { Request, Response, Router } from "express";
-import { DiscordApiErrors, emitEvent, getPermission, getRights, Guild, GuildUpdateEvent, handleFile, Member, GuildCreateSchema } from "@fosscord/util";
+import {
+	DiscordApiErrors,
+	emitEvent,
+	getPermission,
+	getRights,
+	Guild,
+	GuildUpdateEvent,
+	handleFile,
+	Member,
+	GuildCreateSchema,
+} from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { route } from "@fosscord/api";
 
@@ -26,9 +36,13 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 
 	const [guild, member] = await Promise.all([
 		Guild.findOneOrFail({ where: { id: guild_id } }),
-		Member.findOne({ where: { guild_id: guild_id, id: req.user_id } })
+		Member.findOne({ where: { guild_id: guild_id, id: req.user_id } }),
 	]);
-	if (!member) throw new HTTPError("You are not a member of the guild you are trying to access", 401);
+	if (!member)
+		throw new HTTPError(
+			"You are not a member of the guild you are trying to access",
+			401,
+		);
 
 	// @ts-ignore
 	guild.joined_at = member?.joined_at;
@@ -36,39 +50,57 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	return res.send(guild);
 });
 
-router.patch("/", route({ body: "GuildUpdateSchema" }), async (req: Request, res: Response) => {
-	const body = req.body as GuildUpdateSchema;
-	const { guild_id } = req.params;
-
-
-	const rights = await getRights(req.user_id);
-	const permission = await getPermission(req.user_id, guild_id);
-
-	if (!rights.has("MANAGE_GUILDS") || !permission.has("MANAGE_GUILD"))
-		throw DiscordApiErrors.MISSING_PERMISSIONS.withParams("MANAGE_GUILD");
-
-	// TODO: guild update check image
-
-	if (body.icon) body.icon = await handleFile(`/icons/${guild_id}`, body.icon);
-	if (body.banner) body.banner = await handleFile(`/banners/${guild_id}`, body.banner);
-	if (body.splash) body.splash = await handleFile(`/splashes/${guild_id}`, body.splash);
-
-	var guild = await Guild.findOneOrFail({
-		where: { id: guild_id },
-		relations: ["emojis", "roles", "stickers"]
-	});
-	// TODO: check if body ids are valid
-	guild.assign(body);
-
-	const data = guild.toJSON();
-	// TODO: guild hashes
-	// TODO: fix vanity_url_code, template_id
-	delete data.vanity_url_code;
-	delete data.template_id;
-
-	await Promise.all([guild.save(), emitEvent({ event: "GUILD_UPDATE", data, guild_id } as GuildUpdateEvent)]);
-
-	return res.json(data);
-});
+router.patch(
+	"/",
+	route({ body: "GuildUpdateSchema" }),
+	async (req: Request, res: Response) => {
+		const body = req.body as GuildUpdateSchema;
+		const { guild_id } = req.params;
+
+		const rights = await getRights(req.user_id);
+		const permission = await getPermission(req.user_id, guild_id);
+
+		if (!rights.has("MANAGE_GUILDS") || !permission.has("MANAGE_GUILD"))
+			throw DiscordApiErrors.MISSING_PERMISSIONS.withParams(
+				"MANAGE_GUILD",
+			);
+
+		// TODO: guild update check image
+
+		if (body.icon)
+			body.icon = await handleFile(`/icons/${guild_id}`, body.icon);
+		if (body.banner)
+			body.banner = await handleFile(`/banners/${guild_id}`, body.banner);
+		if (body.splash)
+			body.splash = await handleFile(
+				`/splashes/${guild_id}`,
+				body.splash,
+			);
+
+		var guild = await Guild.findOneOrFail({
+			where: { id: guild_id },
+			relations: ["emojis", "roles", "stickers"],
+		});
+		// TODO: check if body ids are valid
+		guild.assign(body);
+
+		const data = guild.toJSON();
+		// TODO: guild hashes
+		// TODO: fix vanity_url_code, template_id
+		delete data.vanity_url_code;
+		delete data.template_id;
+
+		await Promise.all([
+			guild.save(),
+			emitEvent({
+				event: "GUILD_UPDATE",
+				data,
+				guild_id,
+			} as GuildUpdateEvent),
+		]);
+
+		return res.json(data);
+	},
+);
 
 export default router;
diff --git a/src/api/routes/guilds/#guild_id/invites.ts b/src/api/routes/guilds/#guild_id/invites.ts
index b7534e31..4d033e9c 100644
--- a/src/api/routes/guilds/#guild_id/invites.ts
+++ b/src/api/routes/guilds/#guild_id/invites.ts
@@ -4,12 +4,19 @@ import { Request, Response, Router } from "express";
 
 const router = Router();
 
-router.get("/", route({ permission: "MANAGE_GUILD" }), async (req: Request, res: Response) => {
-	const { guild_id } = req.params;
+router.get(
+	"/",
+	route({ permission: "MANAGE_GUILD" }),
+	async (req: Request, res: Response) => {
+		const { guild_id } = req.params;
 
-	const invites = await Invite.find({ where: { guild_id }, relations: PublicInviteRelation });
+		const invites = await Invite.find({
+			where: { guild_id },
+			relations: PublicInviteRelation,
+		});
 
-	return res.json(invites);
-});
+		return res.json(invites);
+	},
+);
 
 export default router;
diff --git a/src/api/routes/guilds/#guild_id/member-verification.ts b/src/api/routes/guilds/#guild_id/member-verification.ts
index 265a1b35..c2f946b2 100644
--- a/src/api/routes/guilds/#guild_id/member-verification.ts
+++ b/src/api/routes/guilds/#guild_id/member-verification.ts
@@ -2,12 +2,12 @@ import { Router, Request, Response } from "express";
 import { route } from "@fosscord/api";
 const router = Router();
 
-router.get("/",route({}), async (req: Request, res: Response) => {
+router.get("/", route({}), async (req: Request, res: Response) => {
 	// TODO: member verification
 
 	res.status(404).json({
 		message: "Unknown Guild Member Verification Form",
-		code: 10068
+		code: 10068,
 	});
 });
 
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 407619d3..2d867920 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
@@ -1,5 +1,16 @@
 import { Request, Response, Router } from "express";
-import { Member, getPermission, getRights, Role, GuildMemberUpdateEvent, emitEvent, Sticker, Emoji, Guild, MemberChangeSchema } from "@fosscord/util";
+import {
+	Member,
+	getPermission,
+	getRights,
+	Role,
+	GuildMemberUpdateEvent,
+	emitEvent,
+	Sticker,
+	Emoji,
+	Guild,
+	MemberChangeSchema,
+} from "@fosscord/util";
 import { route } from "@fosscord/api";
 
 const router = Router();
@@ -8,48 +19,63 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	const { guild_id, member_id } = req.params;
 	await Member.IsInGuildOrFail(req.user_id, guild_id);
 
-	const member = await Member.findOneOrFail({ where: { id: member_id, guild_id } });
+	const member = await Member.findOneOrFail({
+		where: { id: member_id, guild_id },
+	});
 
 	return res.json(member);
 });
 
-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 body = req.body as MemberChangeSchema;
-
-	const member = await Member.findOneOrFail({ where: { id: member_id, guild_id }, relations: ["roles", "user"] });
-	const permission = await getPermission(req.user_id, guild_id);
-	const everyone = await Role.findOneOrFail({ where: { guild_id: guild_id, name: "@everyone", position: 0 } });
-
-	if (body.roles) {
-		permission.hasThrow("MANAGE_ROLES");
-
-		if (body.roles.indexOf(everyone.id) === -1) body.roles.push(everyone.id);
-		member.roles = body.roles.map((x) => Role.create({ id: x })); // foreign key constraint will fail if role doesn't exist
-	}
-
-	if ('nick' in body) {
-		permission.hasThrow(req.user_id == member.user.id ? "CHANGE_NICKNAME" : "MANAGE_NICKNAMES");
-		member.nick = body.nick?.trim() || undefined;
-	}
-
-	await member.save();
-
-	member.roles = member.roles.filter((x) => x.id !== everyone.id);
-
-	// do not use promise.all as we have to first write to db before emitting the event to catch errors
-	await emitEvent({
-		event: "GUILD_MEMBER_UPDATE",
-		guild_id,
-		data: { ...member, roles: member.roles.map((x) => x.id) }
-	} as GuildMemberUpdateEvent);
-
-	res.json(member);
-});
+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 body = req.body as MemberChangeSchema;
+
+		const member = await Member.findOneOrFail({
+			where: { id: member_id, guild_id },
+			relations: ["roles", "user"],
+		});
+		const permission = await getPermission(req.user_id, guild_id);
+		const everyone = await Role.findOneOrFail({
+			where: { guild_id: guild_id, name: "@everyone", position: 0 },
+		});
+
+		if (body.roles) {
+			permission.hasThrow("MANAGE_ROLES");
+
+			if (body.roles.indexOf(everyone.id) === -1)
+				body.roles.push(everyone.id);
+			member.roles = body.roles.map((x) => Role.create({ id: x })); // foreign key constraint will fail if role doesn't exist
+		}
+
+		if ("nick" in body) {
+			permission.hasThrow(
+				req.user_id == member.user.id
+					? "CHANGE_NICKNAME"
+					: "MANAGE_NICKNAMES",
+			);
+			member.nick = body.nick?.trim() || undefined;
+		}
+
+		await member.save();
+
+		member.roles = member.roles.filter((x) => x.id !== everyone.id);
+
+		// do not use promise.all as we have to first write to db before emitting the event to catch errors
+		await emitEvent({
+			event: "GUILD_MEMBER_UPDATE",
+			guild_id,
+			data: { ...member, roles: member.roles.map((x) => x.id) },
+		} as GuildMemberUpdateEvent);
+
+		res.json(member);
+	},
+);
 
 router.put("/", route({}), async (req: Request, res: Response) => {
-
 	// TODO: Lurker mode
 
 	const rights = await getRights(req.user_id);
@@ -59,23 +85,23 @@ router.put("/", route({}), async (req: Request, res: Response) => {
 		member_id = req.user_id;
 		rights.hasThrow("JOIN_GUILDS");
 	} else {
-		// TODO: join others by controller	
+		// TODO: join others by controller
 	}
 
 	var guild = await Guild.findOneOrFail({
-		where: { id: guild_id }
+		where: { id: guild_id },
 	});
 
 	var emoji = await Emoji.find({
-		where: { guild_id: guild_id }
+		where: { guild_id: guild_id },
 	});
 
 	var roles = await Role.find({
-		where: { guild_id: guild_id }
+		where: { guild_id: guild_id },
 	});
 
 	var stickers = await Sticker.find({
-		where: { guild_id: guild_id }
+		where: { guild_id: guild_id },
 	});
 
 	await Member.addToGuild(member_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 edd47605..20443821 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
@@ -4,19 +4,23 @@ import { Request, Response, Router } from "express";
 
 const router = Router();
 
-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";
-	}
+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 perms = await getPermission(req.user_id, guild_id);
-	perms.hasThrow(permissionString);
+		const perms = await getPermission(req.user_id, guild_id);
+		perms.hasThrow(permissionString);
 
-	await Member.changeNickname(member_id, guild_id, req.body.nick);
-	res.status(200).send();
-});
+		await Member.changeNickname(member_id, guild_id, req.body.nick);
+		res.status(200).send();
+	},
+);
 
 export default router;
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 8f5ca7ba..c0383912 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
@@ -4,18 +4,26 @@ import { Request, Response, Router } from "express";
 
 const router = Router();
 
-router.delete("/", route({ permission: "MANAGE_ROLES" }), async (req: Request, res: Response) => {
-	const { guild_id, role_id, member_id } = req.params;
+router.delete(
+	"/",
+	route({ permission: "MANAGE_ROLES" }),
+	async (req: Request, res: Response) => {
+		const { guild_id, role_id, member_id } = req.params;
 
-	await Member.removeRole(member_id, guild_id, role_id);
-	res.sendStatus(204);
-});
+		await Member.removeRole(member_id, guild_id, role_id);
+		res.sendStatus(204);
+	},
+);
 
-router.put("/", route({ permission: "MANAGE_ROLES" }), async (req: Request, res: Response) => {
-	const { guild_id, role_id, member_id } = req.params;
+router.put(
+	"/",
+	route({ permission: "MANAGE_ROLES" }),
+	async (req: Request, res: Response) => {
+		const { guild_id, role_id, member_id } = req.params;
 
-	await Member.addRole(member_id, guild_id, role_id);
-	res.sendStatus(204);
-});
+		await Member.addRole(member_id, guild_id, role_id);
+		res.sendStatus(204);
+	},
+);
 
 export default router;
diff --git a/src/api/routes/guilds/#guild_id/members/index.ts b/src/api/routes/guilds/#guild_id/members/index.ts
index b730a4e7..b516b9e9 100644
--- a/src/api/routes/guilds/#guild_id/members/index.ts
+++ b/src/api/routes/guilds/#guild_id/members/index.ts
@@ -12,7 +12,8 @@ const router = Router();
 router.get("/", route({}), async (req: Request, res: Response) => {
 	const { guild_id } = req.params;
 	const limit = Number(req.query.limit) || 1;
-	if (limit > 1000 || limit < 1) throw new HTTPError("Limit must be between 1 and 1000");
+	if (limit > 1000 || limit < 1)
+		throw new HTTPError("Limit must be between 1 and 1000");
 	const after = `${req.query.after}`;
 	const query = after ? { id: MoreThan(after) } : {};
 
@@ -22,7 +23,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 		where: { guild_id, ...query },
 		select: PublicMemberProjection,
 		take: limit,
-		order: { id: "ASC" }
+		order: { id: "ASC" },
 	});
 
 	return res.json(members);
diff --git a/src/api/routes/guilds/#guild_id/messages/search.ts b/src/api/routes/guilds/#guild_id/messages/search.ts
index a7516ebd..f2d8087e 100644
--- a/src/api/routes/guilds/#guild_id/messages/search.ts
+++ b/src/api/routes/guilds/#guild_id/messages/search.ts
@@ -10,36 +10,62 @@ 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;
 
 	const parsedLimit = Number(limit) || 50;
-	if (parsedLimit < 1 || parsedLimit > 100) throw new HTTPError("limit must be between 1 and 100", 422);
+	if (parsedLimit < 1 || parsedLimit > 100)
+		throw new HTTPError("limit must be between 1 and 100", 422);
 
 	if (sort_order) {
-		if (typeof sort_order != "string"
-			|| ["desc", "asc"].indexOf(sort_order) == -1)
-			throw FieldErrors({ sort_order: { message: "Value must be one of ('desc', 'asc').", code: "BASE_TYPE_CHOICES" } }); // todo this is wrong
+		if (
+			typeof sort_order != "string" ||
+			["desc", "asc"].indexOf(sort_order) == -1
+		)
+			throw FieldErrors({
+				sort_order: {
+					message: "Value must be one of ('desc', 'asc').",
+					code: "BASE_TYPE_CHOICES",
+				},
+			}); // todo this is wrong
 	}
 
-	const permissions = await getPermission(req.user_id, req.params.guild_id, channel_id as string);
+	const permissions = await getPermission(
+		req.user_id,
+		req.params.guild_id,
+		channel_id as string,
+	);
 	permissions.hasThrow("VIEW_CHANNEL");
-	if (!permissions.has("READ_MESSAGE_HISTORY")) return res.json({ messages: [], total_results: 0 });
+	if (!permissions.has("READ_MESSAGE_HISTORY"))
+		return res.json({ messages: [], total_results: 0 });
 
 	var query: FindManyOptions<Message> = {
-		order: { timestamp: sort_order ? sort_order.toUpperCase() as "ASC" | "DESC" : "DESC" },
+		order: {
+			timestamp: sort_order
+				? (sort_order.toUpperCase() as "ASC" | "DESC")
+				: "DESC",
+		},
 		take: parsedLimit || 0,
 		where: {
 			guild: {
 				id: req.params.guild_id,
 			},
 		},
-		relations: ["author", "webhook", "application", "mentions", "mention_roles", "mention_channels", "sticker_items", "attachments"],
+		relations: [
+			"author",
+			"webhook",
+			"application",
+			"mentions",
+			"mention_roles",
+			"mention_channels",
+			"sticker_items",
+			"attachments",
+		],
 		skip: offset ? Number(offset) : 0,
 	};
 	//@ts-ignore
@@ -51,32 +77,34 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 
 	const messages: Message[] = await Message.find(query);
 
-	const messagesDto = messages.map(x => [{
-		id: x.id,
-		type: x.type,
-		content: x.content,
-		channel_id: x.channel_id,
-		author: {
-			id: x.author?.id,
-			username: x.author?.username,
-			avatar: x.author?.avatar,
-			avatar_decoration: null,
-			discriminator: x.author?.discriminator,
-			public_flags: x.author?.public_flags,
+	const messagesDto = messages.map((x) => [
+		{
+			id: x.id,
+			type: x.type,
+			content: x.content,
+			channel_id: x.channel_id,
+			author: {
+				id: x.author?.id,
+				username: x.author?.username,
+				avatar: x.author?.avatar,
+				avatar_decoration: null,
+				discriminator: x.author?.discriminator,
+				public_flags: x.author?.public_flags,
+			},
+			attachments: x.attachments,
+			embeds: x.embeds,
+			mentions: x.mentions,
+			mention_roles: x.mention_roles,
+			pinned: x.pinned,
+			mention_everyone: x.mention_everyone,
+			tts: x.tts,
+			timestamp: x.timestamp,
+			edited_timestamp: x.edited_timestamp,
+			flags: x.flags,
+			components: x.components,
+			hit: true,
 		},
-		attachments: x.attachments,
-		embeds: x.embeds,
-		mentions: x.mentions,
-		mention_roles: x.mention_roles,
-		pinned: x.pinned,
-		mention_everyone: x.mention_everyone,
-		tts: x.tts,
-		timestamp: x.timestamp,
-		edited_timestamp: x.edited_timestamp,
-		flags: x.flags,
-		components: x.components,
-		hit: true,
-	}]);
+	]);
 
 	return res.json({
 		messages: messagesDto,
@@ -84,4 +112,4 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	});
 });
 
-export default router;
\ No newline at end of file
+export default router;
diff --git a/src/api/routes/guilds/#guild_id/prune.ts b/src/api/routes/guilds/#guild_id/prune.ts
index 2e674349..d11244b1 100644
--- a/src/api/routes/guilds/#guild_id/prune.ts
+++ b/src/api/routes/guilds/#guild_id/prune.ts
@@ -5,7 +5,12 @@ import { route } from "@fosscord/api";
 const router = Router();
 
 //Returns all inactive members, respecting role hierarchy
-export const inactiveMembers = async (guild_id: string, user_id: string, days: number, roles: string[] = []) => {
+export const inactiveMembers = async (
+	guild_id: string,
+	user_id: string,
+	days: number,
+	roles: string[] = [],
+) => {
 	var date = new Date();
 	date.setDate(date.getDate() - days);
 	//Snowflake should have `generateFromTime` method? Or similar?
@@ -19,21 +24,27 @@ export const inactiveMembers = async (guild_id: string, user_id: string, days: n
 		where: [
 			{
 				guild_id,
-				last_message_id: LessThan(minId.toString())
+				last_message_id: LessThan(minId.toString()),
 			},
 			{
-				last_message_id: IsNull()
-			}
+				last_message_id: IsNull(),
+			},
 		],
-		relations: ["roles"]
+		relations: ["roles"],
 	});
 	console.log(members);
 	if (!members.length) return [];
 
 	//I'm sure I can do this in the above db query ( and it would probably be better to do so ), but oh well.
-	if (roles.length && members.length) members = members.filter((user) => user.roles?.some((role) => roles.includes(role.id)));
-
-	const me = await Member.findOneOrFail({ where: { id: user_id, guild_id }, relations: ["roles"] });
+	if (roles.length && members.length)
+		members = members.filter((user) =>
+			user.roles?.some((role) => roles.includes(role.id)),
+		);
+
+	const me = await Member.findOneOrFail({
+		where: { id: user_id, guild_id },
+		relations: ["roles"],
+	});
 	const myHighestRole = Math.max(...(me.roles?.map((x) => x.position) || []));
 
 	const guild = await Guild.findOneOrFail({ where: { id: guild_id } });
@@ -44,8 +55,8 @@ export const inactiveMembers = async (guild_id: string, user_id: string, days: n
 			member.roles?.some(
 				(role) =>
 					role.position < myHighestRole || //roles higher than me can't be kicked
-					me.id === guild.owner_id //owner can kick anyone
-			)
+					me.id === guild.owner_id, //owner can kick anyone
+			),
 	);
 
 	return members;
@@ -57,23 +68,39 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	var roles = req.query.include_roles;
 	if (typeof roles === "string") roles = [roles]; //express will return array otherwise
 
-	const members = await inactiveMembers(req.params.guild_id, req.user_id, days, roles as string[]);
+	const members = await inactiveMembers(
+		req.params.guild_id,
+		req.user_id,
+		days,
+		roles as string[],
+	);
 
 	res.send({ pruned: members.length });
 });
 
-router.post("/", route({ permission: "KICK_MEMBERS", right: "KICK_BAN_MEMBERS" }), async (req: Request, res: Response) => {
-	const days = parseInt(req.body.days);
-
-	var roles = req.query.include_roles;
-	if (typeof roles === "string") roles = [roles];
-
-	const { guild_id } = req.params;
-	const members = await inactiveMembers(guild_id, req.user_id, days, roles as string[]);
-
-	await Promise.all(members.map((x) => Member.removeFromGuild(x.id, guild_id)));
-
-	res.send({ purged: members.length });
-});
+router.post(
+	"/",
+	route({ permission: "KICK_MEMBERS", right: "KICK_BAN_MEMBERS" }),
+	async (req: Request, res: Response) => {
+		const days = parseInt(req.body.days);
+
+		var roles = req.query.include_roles;
+		if (typeof roles === "string") roles = [roles];
+
+		const { guild_id } = req.params;
+		const members = await inactiveMembers(
+			guild_id,
+			req.user_id,
+			days,
+			roles as string[],
+		);
+
+		await Promise.all(
+			members.map((x) => Member.removeFromGuild(x.id, guild_id)),
+		);
+
+		res.send({ purged: members.length });
+	},
+);
 
 export default router;
diff --git a/src/api/routes/guilds/#guild_id/regions.ts b/src/api/routes/guilds/#guild_id/regions.ts
index 308d5ee5..0b275ea4 100644
--- a/src/api/routes/guilds/#guild_id/regions.ts
+++ b/src/api/routes/guilds/#guild_id/regions.ts
@@ -9,7 +9,12 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	const { guild_id } = req.params;
 	const guild = await Guild.findOneOrFail({ where: { id: guild_id } });
 	//TODO we should use an enum for guild's features and not hardcoded strings
-	return res.json(await getVoiceRegions(getIpAdress(req), guild.features.includes("VIP_REGIONS")));
+	return res.json(
+		await getVoiceRegions(
+			getIpAdress(req),
+			guild.features.includes("VIP_REGIONS"),
+		),
+	);
 });
 
 export default 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 87cf5261..e274e3d0 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
@@ -1,5 +1,13 @@
 import { Router, Request, Response } from "express";
-import { Role, Member, GuildRoleUpdateEvent, GuildRoleDeleteEvent, emitEvent, handleFile, RoleModifySchema } from "@fosscord/util";
+import {
+	Role,
+	Member,
+	GuildRoleUpdateEvent,
+	GuildRoleDeleteEvent,
+	emitEvent,
+	handleFile,
+	RoleModifySchema,
+} from "@fosscord/util";
 import { route } from "@fosscord/api";
 import { HTTPError } from "lambert-server";
 
@@ -12,57 +20,72 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	return res.json(role);
 });
 
-router.delete("/", route({ permission: "MANAGE_ROLES" }), async (req: Request, res: Response) => {
-	const { guild_id, role_id } = req.params;
-	if (role_id === guild_id) throw new HTTPError("You can't delete the @everyone role");
+router.delete(
+	"/",
+	route({ permission: "MANAGE_ROLES" }),
+	async (req: Request, res: Response) => {
+		const { guild_id, role_id } = req.params;
+		if (role_id === guild_id)
+			throw new HTTPError("You can't delete the @everyone role");
 
-	await Promise.all([
-		Role.delete({
-			id: role_id,
-			guild_id: guild_id
-		}),
-		emitEvent({
-			event: "GUILD_ROLE_DELETE",
-			guild_id,
-			data: {
+		await Promise.all([
+			Role.delete({
+				id: role_id,
+				guild_id: guild_id,
+			}),
+			emitEvent({
+				event: "GUILD_ROLE_DELETE",
 				guild_id,
-				role_id
-			}
-		} as GuildRoleDeleteEvent)
-	]);
+				data: {
+					guild_id,
+					role_id,
+				},
+			} as GuildRoleDeleteEvent),
+		]);
 
-	res.sendStatus(204);
-});
+		res.sendStatus(204);
+	},
+);
 
 // TODO: check role hierarchy
 
-router.patch("/", route({ body: "RoleModifySchema", permission: "MANAGE_ROLES" }), async (req: Request, res: Response) => {
-	const { role_id, guild_id } = req.params;
-	const body = req.body as RoleModifySchema;
+router.patch(
+	"/",
+	route({ body: "RoleModifySchema", permission: "MANAGE_ROLES" }),
+	async (req: Request, res: Response) => {
+		const { role_id, guild_id } = req.params;
+		const body = req.body as RoleModifySchema;
 
-	if (body.icon && body.icon.length) body.icon = await handleFile(`/role-icons/${role_id}`, body.icon as string);
-	else body.icon = undefined;
+		if (body.icon && body.icon.length)
+			body.icon = await handleFile(
+				`/role-icons/${role_id}`,
+				body.icon as string,
+			);
+		else body.icon = undefined;
 
-	const role = Role.create({
-		...body,
-		id: role_id,
-		guild_id,
-		permissions: String(req.permission!.bitfield & BigInt(body.permissions || "0"))
-	});
-
-	await Promise.all([
-		role.save(),
-		emitEvent({
-			event: "GUILD_ROLE_UPDATE",
+		const role = Role.create({
+			...body,
+			id: role_id,
 			guild_id,
-			data: {
+			permissions: String(
+				req.permission!.bitfield & BigInt(body.permissions || "0"),
+			),
+		});
+
+		await Promise.all([
+			role.save(),
+			emitEvent({
+				event: "GUILD_ROLE_UPDATE",
 				guild_id,
-				role
-			}
-		} as GuildRoleUpdateEvent)
-	]);
+				data: {
+					guild_id,
+					role,
+				},
+			} as GuildRoleUpdateEvent),
+		]);
 
-	res.json(role);
-});
+		res.json(role);
+	},
+);
 
 export default router;
diff --git a/src/api/routes/guilds/#guild_id/roles/index.ts b/src/api/routes/guilds/#guild_id/roles/index.ts
index c5a86400..e3c7373e 100644
--- a/src/api/routes/guilds/#guild_id/roles/index.ts
+++ b/src/api/routes/guilds/#guild_id/roles/index.ts
@@ -29,70 +29,87 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	return res.json(roles);
 });
 
-router.post("/", route({ body: "RoleModifySchema", permission: "MANAGE_ROLES" }), async (req: Request, res: Response) => {
-	const guild_id = req.params.guild_id;
-	const body = req.body as RoleModifySchema;
-
-	const role_count = await Role.count({ where: { guild_id } });
-	const { maxRoles } = Config.get().limits.guild;
-
-	if (role_count > maxRoles) throw DiscordApiErrors.MAXIMUM_ROLES.withParams(maxRoles);
-
-	const role = Role.create({
-		// values before ...body are default and can be overriden
-		position: 0,
-		hoist: false,
-		color: 0,
-		mentionable: false,
-		...body,
-		guild_id: guild_id,
-		managed: false,
-		permissions: String(req.permission!.bitfield & BigInt(body.permissions || "0")),
-		tags: undefined,
-		icon: undefined,
-		unicode_emoji: undefined
-	});
-
-	await Promise.all([
-		role.save(),
-		emitEvent({
-			event: "GUILD_ROLE_CREATE",
-			guild_id,
-			data: {
-				guild_id,
-				role: role
-			}
-		} as GuildRoleCreateEvent)
-	]);
-
-	res.json(role);
-});
-
-router.patch("/", route({ body: "RolePositionUpdateSchema" }), async (req: Request, res: Response) => {
-	const { guild_id } = req.params;
-	const body = req.body as RolePositionUpdateSchema;
-
-	const perms = await getPermission(req.user_id, guild_id);
-	perms.hasThrow("MANAGE_ROLES");
-
-	await Promise.all(body.map(async (x) => Role.update({ guild_id, id: x.id }, { position: x.position })));
-
-	const roles = await Role.find({ where: body.map((x) => ({ id: x.id, guild_id })) });
-
-	await Promise.all(
-		roles.map((x) =>
+router.post(
+	"/",
+	route({ body: "RoleModifySchema", permission: "MANAGE_ROLES" }),
+	async (req: Request, res: Response) => {
+		const guild_id = req.params.guild_id;
+		const body = req.body as RoleModifySchema;
+
+		const role_count = await Role.count({ where: { guild_id } });
+		const { maxRoles } = Config.get().limits.guild;
+
+		if (role_count > maxRoles)
+			throw DiscordApiErrors.MAXIMUM_ROLES.withParams(maxRoles);
+
+		const role = Role.create({
+			// values before ...body are default and can be overriden
+			position: 0,
+			hoist: false,
+			color: 0,
+			mentionable: false,
+			...body,
+			guild_id: guild_id,
+			managed: false,
+			permissions: String(
+				req.permission!.bitfield & BigInt(body.permissions || "0"),
+			),
+			tags: undefined,
+			icon: undefined,
+			unicode_emoji: undefined,
+		});
+
+		await Promise.all([
+			role.save(),
 			emitEvent({
-				event: "GUILD_ROLE_UPDATE",
+				event: "GUILD_ROLE_CREATE",
 				guild_id,
 				data: {
 					guild_id,
-					role: x
-				}
-			} as GuildRoleUpdateEvent)
-		)
-	);
-
-	res.json(roles);
-});
+					role: role,
+				},
+			} as GuildRoleCreateEvent),
+		]);
+
+		res.json(role);
+	},
+);
+
+router.patch(
+	"/",
+	route({ body: "RolePositionUpdateSchema" }),
+	async (req: Request, res: Response) => {
+		const { guild_id } = req.params;
+		const body = req.body as RolePositionUpdateSchema;
+
+		const perms = await getPermission(req.user_id, guild_id);
+		perms.hasThrow("MANAGE_ROLES");
+
+		await Promise.all(
+			body.map(async (x) =>
+				Role.update({ guild_id, id: x.id }, { position: x.position }),
+			),
+		);
+
+		const roles = await Role.find({
+			where: body.map((x) => ({ id: x.id, guild_id })),
+		});
+
+		await Promise.all(
+			roles.map((x) =>
+				emitEvent({
+					event: "GUILD_ROLE_UPDATE",
+					guild_id,
+					data: {
+						guild_id,
+						role: x,
+					},
+				} as GuildRoleUpdateEvent),
+			),
+		);
+
+		res.json(roles);
+	},
+);
 
 export default router;
diff --git a/src/api/routes/guilds/#guild_id/stickers.ts b/src/api/routes/guilds/#guild_id/stickers.ts
index fc0f49ab..3b1f5f8e 100644
--- a/src/api/routes/guilds/#guild_id/stickers.ts
+++ b/src/api/routes/guilds/#guild_id/stickers.ts
@@ -26,15 +26,18 @@ const bodyParser = multer({
 	limits: {
 		fileSize: 1024 * 1024 * 100,
 		fields: 10,
-		files: 1
+		files: 1,
 	},
-	storage: multer.memoryStorage()
+	storage: multer.memoryStorage(),
 }).single("file");
 
 router.post(
 	"/",
 	bodyParser,
-	route({ permission: "MANAGE_EMOJIS_AND_STICKERS", body: "ModifyGuildStickerSchema" }),
+	route({
+		permission: "MANAGE_EMOJIS_AND_STICKERS",
+		body: "ModifyGuildStickerSchema",
+	}),
 	async (req: Request, res: Response) => {
 		if (!req.file) throw new HTTPError("missing file");
 
@@ -49,15 +52,15 @@ router.post(
 				id,
 				type: StickerType.GUILD,
 				format_type: getStickerFormat(req.file.mimetype),
-				available: true
+				available: true,
 			}).save(),
-			uploadFile(`/stickers/${id}`, req.file)
+			uploadFile(`/stickers/${id}`, req.file),
 		]);
 
 		await sendStickerUpdateEvent(guild_id);
 
 		res.json(sticker);
-	}
+	},
 );
 
 export function getStickerFormat(mime_type: string) {
@@ -71,7 +74,9 @@ export function getStickerFormat(mime_type: string) {
 		case "image/gif":
 			return StickerFormatType.GIF;
 		default:
-			throw new HTTPError("invalid sticker format: must be png, apng or lottie");
+			throw new HTTPError(
+				"invalid sticker format: must be png, apng or lottie",
+			);
 	}
 }
 
@@ -79,21 +84,30 @@ router.get("/:sticker_id", route({}), async (req: Request, res: Response) => {
 	const { guild_id, sticker_id } = req.params;
 	await Member.IsInGuildOrFail(req.user_id, guild_id);
 
-	res.json(await Sticker.findOneOrFail({ where: { guild_id, id: sticker_id } }));
+	res.json(
+		await Sticker.findOneOrFail({ where: { guild_id, id: sticker_id } }),
+	);
 });
 
 router.patch(
 	"/:sticker_id",
-	route({ body: "ModifyGuildStickerSchema", permission: "MANAGE_EMOJIS_AND_STICKERS" }),
+	route({
+		body: "ModifyGuildStickerSchema",
+		permission: "MANAGE_EMOJIS_AND_STICKERS",
+	}),
 	async (req: Request, res: Response) => {
 		const { guild_id, sticker_id } = req.params;
 		const body = req.body as ModifyGuildStickerSchema;
 
-		const sticker = await Sticker.create({ ...body, guild_id, id: sticker_id }).save();
+		const sticker = await Sticker.create({
+			...body,
+			guild_id,
+			id: sticker_id,
+		}).save();
 		await sendStickerUpdateEvent(guild_id);
 
 		return res.json(sticker);
-	}
+	},
 );
 
 async function sendStickerUpdateEvent(guild_id: string) {
@@ -102,18 +116,22 @@ async function sendStickerUpdateEvent(guild_id: string) {
 		guild_id: guild_id,
 		data: {
 			guild_id: guild_id,
-			stickers: await Sticker.find({ where: { guild_id: guild_id } })
-		}
+			stickers: await Sticker.find({ where: { guild_id: guild_id } }),
+		},
 	} as GuildStickersUpdateEvent);
 }
 
-router.delete("/:sticker_id", route({ permission: "MANAGE_EMOJIS_AND_STICKERS" }), async (req: Request, res: Response) => {
-	const { guild_id, sticker_id } = req.params;
+router.delete(
+	"/:sticker_id",
+	route({ permission: "MANAGE_EMOJIS_AND_STICKERS" }),
+	async (req: Request, res: Response) => {
+		const { guild_id, sticker_id } = req.params;
 
-	await Sticker.delete({ guild_id, id: sticker_id });
-	await sendStickerUpdateEvent(guild_id);
+		await Sticker.delete({ guild_id, id: sticker_id });
+		await sendStickerUpdateEvent(guild_id);
 
-	return res.sendStatus(204);
-});
+		return res.sendStatus(204);
+	},
+);
 
 export default router;
diff --git a/src/api/routes/guilds/#guild_id/templates.ts b/src/api/routes/guilds/#guild_id/templates.ts
index 628321f5..3b5eddaa 100644
--- a/src/api/routes/guilds/#guild_id/templates.ts
+++ b/src/api/routes/guilds/#guild_id/templates.ts
@@ -20,63 +20,97 @@ const TemplateGuildProjection: (keyof Guild)[] = [
 	"afk_channel_id",
 	"system_channel_id",
 	"system_channel_flags",
-	"icon"
+	"icon",
 ];
 
 router.get("/", route({}), async (req: Request, res: Response) => {
 	const { guild_id } = req.params;
 
-	var templates = await Template.find({ where: { source_guild_id: guild_id } });
-
-	return res.json(templates);
-});
-
-router.post("/", route({ body: "TemplateCreateSchema", permission: "MANAGE_GUILD" }), async (req: Request, res: Response) => {
-	const { guild_id } = req.params;
-	const guild = await Guild.findOneOrFail({ where: { id: guild_id }, select: TemplateGuildProjection });
-	const exists = await Template.findOneOrFail({ where: { id: guild_id } }).catch((e) => { });
-	if (exists) throw new HTTPError("Template already exists", 400);
-
-	const template = await Template.create({
-		...req.body,
-		code: generateCode(),
-		creator_id: req.user_id,
-		created_at: new Date(),
-		updated_at: new Date(),
-		source_guild_id: guild_id,
-		serialized_source_guild: guild
-	}).save();
-
-	res.json(template);
-});
-
-router.delete("/:code", route({ permission: "MANAGE_GUILD" }), async (req: Request, res: Response) => {
-	const { code, guild_id } = req.params;
-
-	const template = await Template.delete({
-		code,
-		source_guild_id: guild_id
+	var templates = await Template.find({
+		where: { source_guild_id: guild_id },
 	});
 
-	res.json(template);
-});
-
-router.put("/:code", route({ permission: "MANAGE_GUILD" }), async (req: Request, res: Response) => {
-	const { code, guild_id } = req.params;
-	const guild = await Guild.findOneOrFail({ where: { id: guild_id }, select: TemplateGuildProjection });
-
-	const template = await Template.create({ code, serialized_source_guild: guild }).save();
-
-	res.json(template);
+	return res.json(templates);
 });
 
-router.patch("/:code", route({ body: "TemplateModifySchema", permission: "MANAGE_GUILD" }), async (req: Request, res: Response) => {
-	const { code, guild_id } = req.params;
-	const { name, description } = req.body;
-
-	const template = await Template.create({ code, name: name, description: description, source_guild_id: guild_id }).save();
-
-	res.json(template);
-});
+router.post(
+	"/",
+	route({ body: "TemplateCreateSchema", permission: "MANAGE_GUILD" }),
+	async (req: Request, res: Response) => {
+		const { guild_id } = req.params;
+		const guild = await Guild.findOneOrFail({
+			where: { id: guild_id },
+			select: TemplateGuildProjection,
+		});
+		const exists = await Template.findOneOrFail({
+			where: { id: guild_id },
+		}).catch((e) => {});
+		if (exists) throw new HTTPError("Template already exists", 400);
+
+		const template = await Template.create({
+			...req.body,
+			code: generateCode(),
+			creator_id: req.user_id,
+			created_at: new Date(),
+			updated_at: new Date(),
+			source_guild_id: guild_id,
+			serialized_source_guild: guild,
+		}).save();
+
+		res.json(template);
+	},
+);
+
+router.delete(
+	"/:code",
+	route({ permission: "MANAGE_GUILD" }),
+	async (req: Request, res: Response) => {
+		const { code, guild_id } = req.params;
+
+		const template = await Template.delete({
+			code,
+			source_guild_id: guild_id,
+		});
+
+		res.json(template);
+	},
+);
+
+router.put(
+	"/:code",
+	route({ permission: "MANAGE_GUILD" }),
+	async (req: Request, res: Response) => {
+		const { code, guild_id } = req.params;
+		const guild = await Guild.findOneOrFail({
+			where: { id: guild_id },
+			select: TemplateGuildProjection,
+		});
+
+		const template = await Template.create({
+			code,
+			serialized_source_guild: guild,
+		}).save();
+
+		res.json(template);
+	},
+);
+
+router.patch(
+	"/:code",
+	route({ body: "TemplateModifySchema", permission: "MANAGE_GUILD" }),
+	async (req: Request, res: Response) => {
+		const { code, guild_id } = req.params;
+		const { name, description } = req.body;
+
+		const template = await Template.create({
+			code,
+			name: name,
+			description: description,
+			source_guild_id: guild_id,
+		}).save();
+
+		res.json(template);
+	},
+);
 
 export default router;
diff --git a/src/api/routes/guilds/#guild_id/vanity-url.ts b/src/api/routes/guilds/#guild_id/vanity-url.ts
index d1fe4726..9a96b066 100644
--- a/src/api/routes/guilds/#guild_id/vanity-url.ts
+++ b/src/api/routes/guilds/#guild_id/vanity-url.ts
@@ -1,4 +1,10 @@
-import { Channel, ChannelType, Guild, Invite, VanityUrlSchema } from "@fosscord/util";
+import {
+	Channel,
+	ChannelType,
+	Guild,
+	Invite,
+	VanityUrlSchema,
+} from "@fosscord/util";
 import { Router, Request, Response } from "express";
 import { route } from "@fosscord/api";
 import { HTTPError } from "lambert-server";
@@ -7,52 +13,70 @@ const router = Router();
 
 const InviteRegex = /\W/g;
 
-router.get("/", route({ permission: "MANAGE_GUILD" }), async (req: Request, res: Response) => {
-	const { guild_id } = req.params;
-	const guild = await Guild.findOneOrFail({ where: { id: guild_id } });
-
-	if (!guild.features.includes("ALIASABLE_NAMES")) {
-		const invite = await Invite.findOne({ where: { guild_id: guild_id, vanity_url: true } });
-		if (!invite) return res.json({ code: null });
-
-		return res.json({ code: invite.code, uses: invite.uses });
-	} else {
-		const invite = await Invite.find({ where: { guild_id: guild_id, vanity_url: true } });
-		if (!invite || invite.length == 0) return res.json({ code: null });
-
-		return res.json(invite.map((x) => ({ code: x.code, uses: x.uses })));
-	}
-});
-
-router.patch("/", route({ body: "VanityUrlSchema", permission: "MANAGE_GUILD" }), async (req: Request, res: Response) => {
-	const { guild_id } = req.params;
-	const body = req.body as VanityUrlSchema;
-	const code = body.code?.replace(InviteRegex, "");
-
-	const guild = await Guild.findOneOrFail({ where: { id: guild_id } });
-	if (!guild.features.includes("VANITY_URL")) throw new HTTPError("Your guild doesn't support vanity urls");
-
-	if (!code || code.length === 0) throw new HTTPError("Code cannot be null or empty");
-
-	const invite = await Invite.findOne({ where: { code } });
-	if (invite) throw new HTTPError("Invite already exists");
-
-	const { id } = await Channel.findOneOrFail({ where: { guild_id, type: ChannelType.GUILD_TEXT } });
-
-	await Invite.create({
-		vanity_url: true,
-		code: code,
-		temporary: false,
-		uses: 0,
-		max_uses: 0,
-		max_age: 0,
-		created_at: new Date(),
-		expires_at: new Date(),
-		guild_id: guild_id,
-		channel_id: id
-	}).save();
-
-	return res.json({ code: code });
-});
+router.get(
+	"/",
+	route({ permission: "MANAGE_GUILD" }),
+	async (req: Request, res: Response) => {
+		const { guild_id } = req.params;
+		const guild = await Guild.findOneOrFail({ where: { id: guild_id } });
+
+		if (!guild.features.includes("ALIASABLE_NAMES")) {
+			const invite = await Invite.findOne({
+				where: { guild_id: guild_id, vanity_url: true },
+			});
+			if (!invite) return res.json({ code: null });
+
+			return res.json({ code: invite.code, uses: invite.uses });
+		} else {
+			const invite = await Invite.find({
+				where: { guild_id: guild_id, vanity_url: true },
+			});
+			if (!invite || invite.length == 0) return res.json({ code: null });
+
+			return res.json(
+				invite.map((x) => ({ code: x.code, uses: x.uses })),
+			);
+		}
+	},
+);
+
+router.patch(
+	"/",
+	route({ body: "VanityUrlSchema", permission: "MANAGE_GUILD" }),
+	async (req: Request, res: Response) => {
+		const { guild_id } = req.params;
+		const body = req.body as VanityUrlSchema;
+		const code = body.code?.replace(InviteRegex, "");
+
+		const guild = await Guild.findOneOrFail({ where: { id: guild_id } });
+		if (!guild.features.includes("VANITY_URL"))
+			throw new HTTPError("Your guild doesn't support vanity urls");
+
+		if (!code || code.length === 0)
+			throw new HTTPError("Code cannot be null or empty");
+
+		const invite = await Invite.findOne({ where: { code } });
+		if (invite) throw new HTTPError("Invite already exists");
+
+		const { id } = await Channel.findOneOrFail({
+			where: { guild_id, type: ChannelType.GUILD_TEXT },
+		});
+
+		await Invite.create({
+			vanity_url: true,
+			code: code,
+			temporary: false,
+			uses: 0,
+			max_uses: 0,
+			max_age: 0,
+			created_at: new Date(),
+			expires_at: new Date(),
+			guild_id: guild_id,
+			channel_id: id,
+		}).save();
+
+		return res.json({ code: code });
+	},
+);
 
 export default router;
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 006e997f..af03a07e 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
@@ -1,52 +1,71 @@
-import { Channel, ChannelType, DiscordApiErrors, emitEvent, getPermission, VoiceState, VoiceStateUpdateEvent, VoiceStateUpdateSchema } from "@fosscord/util";
+import {
+	Channel,
+	ChannelType,
+	DiscordApiErrors,
+	emitEvent,
+	getPermission,
+	VoiceState,
+	VoiceStateUpdateEvent,
+	VoiceStateUpdateSchema,
+} from "@fosscord/util";
 import { route } from "@fosscord/api";
 import { Request, Response, Router } from "express";
 
 const router = Router();
 //TODO need more testing when community guild and voice stage channel are working
 
-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;
+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 perms = await getPermission(req.user_id, guild_id, body.channel_id);
+		const perms = await getPermission(
+			req.user_id,
+			guild_id,
+			body.channel_id,
+		);
 
-	/*
+		/*
 	From https://discord.com/developers/docs/resources/guild#modify-current-user-voice-state
 	You must have the MUTE_MEMBERS permission to unsuppress others. You can always suppress yourself.
 	You must have the REQUEST_TO_SPEAK permission to request to speak. You can always clear your own request to speak.
 	 */
-	if (body.suppress && user_id !== req.user_id) {
-		perms.hasThrow("MUTE_MEMBERS");
-	}
-	if (!body.suppress) body.request_to_speak_timestamp = new Date();
-	if (body.request_to_speak_timestamp) perms.hasThrow("REQUEST_TO_SPEAK");
-
-	const voice_state = await VoiceState.findOne({
-		where: {
-			guild_id,
-			channel_id: body.channel_id,
-			user_id
+		if (body.suppress && user_id !== req.user_id) {
+			perms.hasThrow("MUTE_MEMBERS");
+		}
+		if (!body.suppress) body.request_to_speak_timestamp = new Date();
+		if (body.request_to_speak_timestamp) perms.hasThrow("REQUEST_TO_SPEAK");
+
+		const voice_state = await VoiceState.findOne({
+			where: {
+				guild_id,
+				channel_id: body.channel_id,
+				user_id,
+			},
+		});
+		if (!voice_state) throw DiscordApiErrors.UNKNOWN_VOICE_STATE;
+
+		voice_state.assign(body);
+		const channel = await Channel.findOneOrFail({
+			where: { guild_id, id: body.channel_id },
+		});
+		if (channel.type !== ChannelType.GUILD_STAGE_VOICE) {
+			throw DiscordApiErrors.CANNOT_EXECUTE_ON_THIS_CHANNEL_TYPE;
 		}
-	});
-	if (!voice_state) throw DiscordApiErrors.UNKNOWN_VOICE_STATE;
-
-	voice_state.assign(body);
-	const channel = await Channel.findOneOrFail({ where: { guild_id, id: body.channel_id } });
-	if (channel.type !== ChannelType.GUILD_STAGE_VOICE) {
-		throw DiscordApiErrors.CANNOT_EXECUTE_ON_THIS_CHANNEL_TYPE;
-	}
-
-	await Promise.all([
-		voice_state.save(),
-		emitEvent({
-			event: "VOICE_STATE_UPDATE",
-			data: voice_state,
-			guild_id
-		} as VoiceStateUpdateEvent)
-	]);
-	return res.sendStatus(204);
-});
+
+		await Promise.all([
+			voice_state.save(),
+			emitEvent({
+				event: "VOICE_STATE_UPDATE",
+				data: voice_state,
+				guild_id,
+			} as VoiceStateUpdateEvent),
+		]);
+		return res.sendStatus(204);
+	},
+);
 
 export default router;
diff --git a/src/api/routes/guilds/#guild_id/welcome-screen.ts b/src/api/routes/guilds/#guild_id/welcome-screen.ts
index 57da062d..80ab138b 100644
--- a/src/api/routes/guilds/#guild_id/welcome-screen.ts
+++ b/src/api/routes/guilds/#guild_id/welcome-screen.ts
@@ -14,20 +14,30 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	res.json(guild.welcome_screen);
 });
 
-router.patch("/", route({ body: "GuildUpdateWelcomeScreenSchema", permission: "MANAGE_GUILD" }), async (req: Request, res: Response) => {
-	const guild_id = req.params.guild_id;
-	const body = req.body as GuildUpdateWelcomeScreenSchema;
-
-	const guild = await Guild.findOneOrFail({ where: { id: guild_id } });
-
-	if (!guild.welcome_screen.enabled) throw new HTTPError("Welcome screen disabled", 400);
-	if (body.welcome_channels) guild.welcome_screen.welcome_channels = body.welcome_channels; // TODO: check if they exist and are valid
-	if (body.description) guild.welcome_screen.description = body.description;
-	if (body.enabled != null) guild.welcome_screen.enabled = body.enabled;
-
-	await guild.save();
-
-	res.sendStatus(204);
-});
+router.patch(
+	"/",
+	route({
+		body: "GuildUpdateWelcomeScreenSchema",
+		permission: "MANAGE_GUILD",
+	}),
+	async (req: Request, res: Response) => {
+		const guild_id = req.params.guild_id;
+		const body = req.body as GuildUpdateWelcomeScreenSchema;
+
+		const guild = await Guild.findOneOrFail({ where: { id: guild_id } });
+
+		if (!guild.welcome_screen.enabled)
+			throw new HTTPError("Welcome screen disabled", 400);
+		if (body.welcome_channels)
+			guild.welcome_screen.welcome_channels = body.welcome_channels; // TODO: check if they exist and are valid
+		if (body.description)
+			guild.welcome_screen.description = body.description;
+		if (body.enabled != null) guild.welcome_screen.enabled = body.enabled;
+
+		await guild.save();
+
+		res.sendStatus(204);
+	},
+);
 
 export default router;
diff --git a/src/api/routes/guilds/#guild_id/widget.json.ts b/src/api/routes/guilds/#guild_id/widget.json.ts
index be5bf23f..2c3124a2 100644
--- a/src/api/routes/guilds/#guild_id/widget.json.ts
+++ b/src/api/routes/guilds/#guild_id/widget.json.ts
@@ -1,5 +1,12 @@
 import { Request, Response, Router } from "express";
-import { Config, Permissions, Guild, Invite, Channel, Member } from "@fosscord/util";
+import {
+	Config,
+	Permissions,
+	Guild,
+	Invite,
+	Channel,
+	Member,
+} from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { random, route } from "@fosscord/api";
 
@@ -21,7 +28,9 @@ 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({ where: { channel_id: guild.widget_channel_id } });
+	var invite = await Invite.findOne({
+		where: { channel_id: guild.widget_channel_id },
+	});
 
 	if (guild.widget_channel_id && !invite) {
 		// Create invite for channel if none exists
@@ -45,16 +54,24 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	// Fetch voice channels, and the @everyone permissions object
 	const channels = [] as any[];
 
-	(await Channel.find({ where: { guild_id: guild_id, type: 2 }, order: { position: "ASC" } })).filter((doc) => {
+	(
+		await Channel.find({
+			where: { guild_id: guild_id, type: 2 },
+			order: { position: "ASC" },
+		})
+	).filter((doc) => {
 		// Only return channels where @everyone has the CONNECT permission
 		if (
 			doc.permission_overwrites === undefined ||
-			Permissions.channelPermission(doc.permission_overwrites, Permissions.FLAGS.CONNECT) === Permissions.FLAGS.CONNECT
+			Permissions.channelPermission(
+				doc.permission_overwrites,
+				Permissions.FLAGS.CONNECT,
+			) === Permissions.FLAGS.CONNECT
 		) {
 			channels.push({
 				id: doc.id,
 				name: doc.name,
-				position: doc.position
+				position: doc.position,
 			});
 		}
 	});
@@ -70,7 +87,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 		instant_invite: invite?.code,
 		channels: channels,
 		members: members,
-		presence_count: guild.presence_count
+		presence_count: guild.presence_count,
 	};
 
 	res.set("Cache-Control", "public, max-age=300");
diff --git a/src/api/routes/guilds/#guild_id/widget.png.ts b/src/api/routes/guilds/#guild_id/widget.png.ts
index c17d511e..eaec8f07 100644
--- a/src/api/routes/guilds/#guild_id/widget.png.ts
+++ b/src/api/routes/guilds/#guild_id/widget.png.ts
@@ -24,8 +24,13 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 
 	// Fetch parameter
 	const style = req.query.style?.toString() || "shield";
-	if (!["shield", "banner1", "banner2", "banner3", "banner4"].includes(style)) {
-		throw new HTTPError("Value must be one of ('shield', 'banner1', 'banner2', 'banner3', 'banner4').", 400);
+	if (
+		!["shield", "banner1", "banner2", "banner3", "banner4"].includes(style)
+	) {
+		throw new HTTPError(
+			"Value must be one of ('shield', 'banner1', 'banner2', 'banner3', 'banner4').",
+			400,
+		);
 	}
 
 	// Setup canvas
@@ -34,7 +39,17 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	const sizeOf = require("image-size");
 
 	// TODO: Widget style templates need Fosscord branding
-	const source = path.join(__dirname, "..", "..", "..", "..", "..", "assets", "widget", `${style}.png`);
+	const source = path.join(
+		__dirname,
+		"..",
+		"..",
+		"..",
+		"..",
+		"..",
+		"assets",
+		"widget",
+		`${style}.png`,
+	);
 	if (!fs.existsSync(source)) {
 		throw new HTTPError("Widget template does not exist.", 400);
 	}
@@ -50,30 +65,68 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	switch (style) {
 		case "shield":
 			ctx.textAlign = "center";
-			await drawText(ctx, 73, 13, "#FFFFFF", "thin 10px Verdana", presence);
+			await drawText(
+				ctx,
+				73,
+				13,
+				"#FFFFFF",
+				"thin 10px Verdana",
+				presence,
+			);
 			break;
 		case "banner1":
 			if (icon) await drawIcon(ctx, 20, 27, 50, icon);
 			await drawText(ctx, 83, 51, "#FFFFFF", "12px Verdana", name, 22);
-			await drawText(ctx, 83, 66, "#C9D2F0FF", "thin 11px Verdana", presence);
+			await drawText(
+				ctx,
+				83,
+				66,
+				"#C9D2F0FF",
+				"thin 11px Verdana",
+				presence,
+			);
 			break;
 		case "banner2":
 			if (icon) await drawIcon(ctx, 13, 19, 36, icon);
 			await drawText(ctx, 62, 34, "#FFFFFF", "12px Verdana", name, 15);
-			await drawText(ctx, 62, 49, "#C9D2F0FF", "thin 11px Verdana", presence);
+			await drawText(
+				ctx,
+				62,
+				49,
+				"#C9D2F0FF",
+				"thin 11px Verdana",
+				presence,
+			);
 			break;
 		case "banner3":
 			if (icon) await drawIcon(ctx, 20, 20, 50, icon);
 			await drawText(ctx, 83, 44, "#FFFFFF", "12px Verdana", name, 27);
-			await drawText(ctx, 83, 58, "#C9D2F0FF", "thin 11px Verdana", presence);
+			await drawText(
+				ctx,
+				83,
+				58,
+				"#C9D2F0FF",
+				"thin 11px Verdana",
+				presence,
+			);
 			break;
 		case "banner4":
 			if (icon) await drawIcon(ctx, 21, 136, 50, icon);
 			await drawText(ctx, 84, 156, "#FFFFFF", "13px Verdana", name, 27);
-			await drawText(ctx, 84, 171, "#C9D2F0FF", "thin 12px Verdana", presence);
+			await drawText(
+				ctx,
+				84,
+				171,
+				"#C9D2F0FF",
+				"thin 12px Verdana",
+				presence,
+			);
 			break;
 		default:
-			throw new HTTPError("Value must be one of ('shield', 'banner1', 'banner2', 'banner3', 'banner4').", 400);
+			throw new HTTPError(
+				"Value must be one of ('shield', 'banner1', 'banner2', 'banner3', 'banner4').",
+				400,
+			);
 	}
 
 	// Return final image
@@ -83,7 +136,13 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	return res.send(buffer);
 });
 
-async function drawIcon(canvas: any, x: number, y: number, scale: number, icon: string) {
+async function drawIcon(
+	canvas: any,
+	x: number,
+	y: number,
+	scale: number,
+	icon: string,
+) {
 	// @ts-ignore
 	const img = new require("canvas").Image();
 	img.src = icon;
@@ -101,10 +160,19 @@ async function drawIcon(canvas: any, x: number, y: number, scale: number, icon:
 	canvas.restore();
 }
 
-async function drawText(canvas: any, x: number, y: number, color: string, font: string, text: string, maxcharacters?: number) {
+async function drawText(
+	canvas: any,
+	x: number,
+	y: number,
+	color: string,
+	font: string,
+	text: string,
+	maxcharacters?: number,
+) {
 	canvas.fillStyle = color;
 	canvas.font = font;
-	if (text.length > (maxcharacters || 0) && maxcharacters) text = text.slice(0, maxcharacters) + "...";
+	if (text.length > (maxcharacters || 0) && maxcharacters)
+		text = text.slice(0, maxcharacters) + "...";
 	canvas.fillText(text, x, y);
 }
 
diff --git a/src/api/routes/guilds/#guild_id/widget.ts b/src/api/routes/guilds/#guild_id/widget.ts
index dbb4cc0c..108339e1 100644
--- a/src/api/routes/guilds/#guild_id/widget.ts
+++ b/src/api/routes/guilds/#guild_id/widget.ts
@@ -10,18 +10,31 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 
 	const guild = await Guild.findOneOrFail({ where: { id: guild_id } });
 
-	return res.json({ enabled: guild.widget_enabled || false, channel_id: guild.widget_channel_id || null });
+	return res.json({
+		enabled: guild.widget_enabled || false,
+		channel_id: guild.widget_channel_id || null,
+	});
 });
 
 // https://discord.com/developers/docs/resources/guild#modify-guild-widget
-router.patch("/", route({ body: "WidgetModifySchema", permission: "MANAGE_GUILD" }), async (req: Request, res: Response) => {
-	const body = req.body as WidgetModifySchema;
-	const { guild_id } = req.params;
-
-	await Guild.update({ id: guild_id }, { widget_enabled: body.enabled, widget_channel_id: body.channel_id });
-	// Widget invite for the widget_channel_id gets created as part of the /guilds/{guild.id}/widget.json request
-
-	return res.json(body);
-});
+router.patch(
+	"/",
+	route({ body: "WidgetModifySchema", permission: "MANAGE_GUILD" }),
+	async (req: Request, res: Response) => {
+		const body = req.body as WidgetModifySchema;
+		const { guild_id } = req.params;
+
+		await Guild.update(
+			{ id: guild_id },
+			{
+				widget_enabled: body.enabled,
+				widget_channel_id: body.channel_id,
+			},
+		);
+		// Widget invite for the widget_channel_id gets created as part of the /guilds/{guild.id}/widget.json request
+
+		return res.json(body);
+	},
+);
 
 export default router;
diff --git a/src/api/routes/guilds/index.ts b/src/api/routes/guilds/index.ts
index 0807cb96..69575aea 100644
--- a/src/api/routes/guilds/index.ts
+++ b/src/api/routes/guilds/index.ts
@@ -1,32 +1,47 @@
 import { Router, Request, Response } from "express";
-import { Role, Guild, Config, getRights, Member, DiscordApiErrors, GuildCreateSchema } from "@fosscord/util";
+import {
+	Role,
+	Guild,
+	Config,
+	getRights,
+	Member,
+	DiscordApiErrors,
+	GuildCreateSchema,
+} from "@fosscord/util";
 import { route } from "@fosscord/api";
 
 const router: Router = Router();
 
 //TODO: create default channel
 
-router.post("/", route({ body: "GuildCreateSchema", right: "CREATE_GUILDS" }), async (req: Request, res: Response) => {
-	const body = req.body as GuildCreateSchema;
-
-	const { maxGuilds } = Config.get().limits.user;
-	const guild_count = await Member.count({ where: { id: req.user_id } });
-	const rights = await getRights(req.user_id);
-	if ((guild_count >= maxGuilds) && !rights.has("MANAGE_GUILDS")) {
-		throw DiscordApiErrors.MAXIMUM_GUILDS.withParams(maxGuilds);
-	}
-
-	const guild = await Guild.createGuild({ ...body, owner_id: req.user_id });
-
-	const { autoJoin } = Config.get().guild;
-	if (autoJoin.enabled && !autoJoin.guilds?.length) {
-		// @ts-ignore
-		await Config.set({ guild: { autoJoin: { guilds: [guild.id] } } });
-	}
-
-	await Member.addToGuild(req.user_id, guild.id);
-
-	res.status(201).json({ id: guild.id });
-});
+router.post(
+	"/",
+	route({ body: "GuildCreateSchema", right: "CREATE_GUILDS" }),
+	async (req: Request, res: Response) => {
+		const body = req.body as GuildCreateSchema;
+
+		const { maxGuilds } = Config.get().limits.user;
+		const guild_count = await Member.count({ where: { id: req.user_id } });
+		const rights = await getRights(req.user_id);
+		if (guild_count >= maxGuilds && !rights.has("MANAGE_GUILDS")) {
+			throw DiscordApiErrors.MAXIMUM_GUILDS.withParams(maxGuilds);
+		}
+
+		const guild = await Guild.createGuild({
+			...body,
+			owner_id: req.user_id,
+		});
+
+		const { autoJoin } = Config.get().guild;
+		if (autoJoin.enabled && !autoJoin.guilds?.length) {
+			// @ts-ignore
+			await Config.set({ guild: { autoJoin: { guilds: [guild.id] } } });
+		}
+
+		await Member.addToGuild(req.user_id, guild.id);
+
+		res.status(201).json({ id: guild.id });
+	},
+);
 
 export default router;
diff --git a/src/api/routes/guilds/templates/index.ts b/src/api/routes/guilds/templates/index.ts
index 4e7abcc5..240bf074 100644
--- a/src/api/routes/guilds/templates/index.ts
+++ b/src/api/routes/guilds/templates/index.ts
@@ -1,29 +1,58 @@
 import { Request, Response, Router } from "express";
-import { Template, Guild, Role, Snowflake, Config, Member, GuildTemplateCreateSchema } from "@fosscord/util";
+import {
+	Template,
+	Guild,
+	Role,
+	Snowflake,
+	Config,
+	Member,
+	GuildTemplateCreateSchema,
+} from "@fosscord/util";
 import { route } from "@fosscord/api";
 import { DiscordApiErrors } from "@fosscord/util";
 import fetch from "node-fetch";
 const router: Router = Router();
 
 router.get("/:code", route({}), async (req: Request, res: Response) => {
-	const { allowDiscordTemplates, allowRaws, enabled } = Config.get().templates;
-	if (!enabled) res.json({ code: 403, message: "Template creation & usage is disabled on this instance." }).sendStatus(403);
+	const { allowDiscordTemplates, allowRaws, enabled } =
+		Config.get().templates;
+	if (!enabled)
+		res.json({
+			code: 403,
+			message: "Template creation & usage is disabled on this instance.",
+		}).sendStatus(403);
 
 	const { code } = req.params;
 
 	if (code.startsWith("discord:")) {
-		if (!allowDiscordTemplates) return res.json({ code: 403, message: "Discord templates cannot be used on this instance." }).sendStatus(403);
+		if (!allowDiscordTemplates)
+			return res
+				.json({
+					code: 403,
+					message:
+						"Discord templates cannot be used on this instance.",
+				})
+				.sendStatus(403);
 		const discordTemplateID = code.split("discord:", 2)[1];
 
-		const discordTemplateData = await fetch(`https://discord.com/api/v9/guilds/templates/${discordTemplateID}`, {
-			method: "get",
-			headers: { "Content-Type": "application/json" }
-		});
+		const discordTemplateData = await fetch(
+			`https://discord.com/api/v9/guilds/templates/${discordTemplateID}`,
+			{
+				method: "get",
+				headers: { "Content-Type": "application/json" },
+			},
+		);
 		return res.json(await discordTemplateData.json());
 	}
 
 	if (code.startsWith("external:")) {
-		if (!allowRaws) return res.json({ code: 403, message: "Importing raws is disabled on this instance." }).sendStatus(403);
+		if (!allowRaws)
+			return res
+				.json({
+					code: 403,
+					message: "Importing raws is disabled on this instance.",
+				})
+				.sendStatus(403);
 
 		return res.json(code.split("external:", 2)[1]);
 	}
@@ -32,48 +61,72 @@ router.get("/:code", route({}), async (req: Request, res: Response) => {
 	res.json(template);
 });
 
-router.post("/:code", route({ body: "GuildTemplateCreateSchema" }), async (req: Request, res: Response) => {
-	const { enabled, allowTemplateCreation, allowDiscordTemplates, allowRaws } = Config.get().templates;
-	if (!enabled) return res.json({ code: 403, message: "Template creation & usage is disabled on this instance." }).sendStatus(403);
-	if (!allowTemplateCreation) return res.json({ code: 403, message: "Template creation is disabled on this instance." }).sendStatus(403);
-
-	const { code } = req.params;
-	const body = req.body as GuildTemplateCreateSchema;
-
-	const { maxGuilds } = Config.get().limits.user;
-
-	const guild_count = await Member.count({ where: { id: req.user_id } });
-	if (guild_count >= maxGuilds) {
-		throw DiscordApiErrors.MAXIMUM_GUILDS.withParams(maxGuilds);
-	}
-
-	const template = await Template.findOneOrFail({ where: { code: code } });
+router.post(
+	"/:code",
+	route({ body: "GuildTemplateCreateSchema" }),
+	async (req: Request, res: Response) => {
+		const {
+			enabled,
+			allowTemplateCreation,
+			allowDiscordTemplates,
+			allowRaws,
+		} = Config.get().templates;
+		if (!enabled)
+			return res
+				.json({
+					code: 403,
+					message:
+						"Template creation & usage is disabled on this instance.",
+				})
+				.sendStatus(403);
+		if (!allowTemplateCreation)
+			return res
+				.json({
+					code: 403,
+					message: "Template creation is disabled on this instance.",
+				})
+				.sendStatus(403);
+
+		const { code } = req.params;
+		const body = req.body as GuildTemplateCreateSchema;
+
+		const { maxGuilds } = Config.get().limits.user;
+
+		const guild_count = await Member.count({ where: { id: req.user_id } });
+		if (guild_count >= maxGuilds) {
+			throw DiscordApiErrors.MAXIMUM_GUILDS.withParams(maxGuilds);
+		}
+
+		const template = await Template.findOneOrFail({
+			where: { code: code },
+		});
 
-	const guild_id = Snowflake.generate();
-
-	const [guild, role] = await Promise.all([
-		Guild.create({
-			...body,
-			...template.serialized_source_guild,
-			id: guild_id,
-			owner_id: req.user_id
-		}).save(),
-		Role.create({
-			id: guild_id,
-			guild_id: guild_id,
-			color: 0,
-			hoist: false,
-			managed: true,
-			mentionable: true,
-			name: "@everyone",
-			permissions: BigInt("2251804225").toString(), // TODO: where did this come from?
-			position: 0,
-		}).save()
-	]);
-
-	await Member.addToGuild(req.user_id, guild_id);
-
-	res.status(201).json({ id: guild.id });
-});
+		const guild_id = Snowflake.generate();
+
+		const [guild, role] = await Promise.all([
+			Guild.create({
+				...body,
+				...template.serialized_source_guild,
+				id: guild_id,
+				owner_id: req.user_id,
+			}).save(),
+			Role.create({
+				id: guild_id,
+				guild_id: guild_id,
+				color: 0,
+				hoist: false,
+				managed: true,
+				mentionable: true,
+				name: "@everyone",
+				permissions: BigInt("2251804225").toString(), // TODO: where did this come from?
+				position: 0,
+			}).save(),
+		]);
+
+		await Member.addToGuild(req.user_id, guild_id);
+
+		res.status(201).json({ id: guild.id });
+	},
+);
 
 export default router;
diff --git a/src/api/routes/invites/index.ts b/src/api/routes/invites/index.ts
index c268085f..ce0ba982 100644
--- a/src/api/routes/invites/index.ts
+++ b/src/api/routes/invites/index.ts
@@ -1,5 +1,13 @@
 import { Router, Request, Response } from "express";
-import { emitEvent, getPermission, Guild, Invite, InviteDeleteEvent, User, PublicInviteRelation } from "@fosscord/util";
+import {
+	emitEvent,
+	getPermission,
+	Guild,
+	Invite,
+	InviteDeleteEvent,
+	User,
+	PublicInviteRelation,
+} from "@fosscord/util";
 import { route } from "@fosscord/api";
 import { HTTPError } from "lambert-server";
 
@@ -8,24 +16,45 @@ const router: Router = Router();
 router.get("/:code", route({}), async (req: Request, res: Response) => {
 	const { code } = req.params;
 
-	const invite = await Invite.findOneOrFail({ where: { code }, relations: PublicInviteRelation });
+	const invite = await Invite.findOneOrFail({
+		where: { code },
+		relations: PublicInviteRelation,
+	});
 
 	res.status(200).send(invite);
 });
 
-router.post("/:code", route({ right: "USE_MASS_INVITES" }), async (req: Request, res: Response) => {
-	const { code } = req.params;
-	const { guild_id } = await Invite.findOneOrFail({ where: { code: code } });
-	const { features } = await Guild.findOneOrFail({ where: { id: guild_id } });
-	const { public_flags } = await User.findOneOrFail({ where: { id: req.user_id } });
+router.post(
+	"/:code",
+	route({ right: "USE_MASS_INVITES" }),
+	async (req: Request, res: Response) => {
+		const { code } = req.params;
+		const { guild_id } = await Invite.findOneOrFail({
+			where: { code: code },
+		});
+		const { features } = await Guild.findOneOrFail({
+			where: { id: guild_id },
+		});
+		const { public_flags } = await User.findOneOrFail({
+			where: { id: req.user_id },
+		});
 
-	if (features.includes("INTERNAL_EMPLOYEE_ONLY") && (public_flags & 1) !== 1) throw new HTTPError("Only intended for the staff of this server.", 401);
-	if (features.includes("INVITES_CLOSED")) throw new HTTPError("Sorry, this guild has joins closed.", 403);
+		if (
+			features.includes("INTERNAL_EMPLOYEE_ONLY") &&
+			(public_flags & 1) !== 1
+		)
+			throw new HTTPError(
+				"Only intended for the staff of this server.",
+				401,
+			);
+		if (features.includes("INVITES_CLOSED"))
+			throw new HTTPError("Sorry, this guild has joins closed.", 403);
 
-	const invite = await Invite.joinGuild(req.user_id, code);
+		const invite = await Invite.joinGuild(req.user_id, code);
 
-	res.json(invite);
-});
+		res.json(invite);
+	},
+);
 
 // * cant use permission of route() function because path doesn't have guild_id/channel_id
 router.delete("/:code", route({}), async (req: Request, res: Response) => {
@@ -36,7 +65,10 @@ router.delete("/:code", route({}), async (req: Request, res: Response) => {
 	const permission = await getPermission(req.user_id, guild_id, channel_id);
 
 	if (!permission.has("MANAGE_GUILD") && !permission.has("MANAGE_CHANNELS"))
-		throw new HTTPError("You missing the MANAGE_GUILD or MANAGE_CHANNELS permission", 401);
+		throw new HTTPError(
+			"You missing the MANAGE_GUILD or MANAGE_CHANNELS permission",
+			401,
+		);
 
 	await Promise.all([
 		Invite.delete({ code }),
@@ -46,9 +78,9 @@ router.delete("/:code", route({}), async (req: Request, res: Response) => {
 			data: {
 				channel_id: channel_id,
 				guild_id: guild_id,
-				code: code
-			}
-		} as InviteDeleteEvent)
+				code: code,
+			},
+		} as InviteDeleteEvent),
 	]);
 
 	res.json({ invite: invite });
diff --git a/src/api/routes/partners/#guild_id/requirements.ts b/src/api/routes/partners/#guild_id/requirements.ts
index 545c5c78..7e63c06b 100644
--- a/src/api/routes/partners/#guild_id/requirements.ts
+++ b/src/api/routes/partners/#guild_id/requirements.ts
@@ -1,4 +1,3 @@
-
 import { Guild, Config } from "@fosscord/util";
 
 import { Router, Request, Response } from "express";
@@ -7,33 +6,33 @@ import { route } from "@fosscord/api";
 const router = Router();
 
 router.get("/", route({}), async (req: Request, res: Response) => {
-	const { guild_id } = req.params;	
-    // TODO:
-    // Load from database
-    // Admin control, but for now it allows anyone to be discoverable
+	const { guild_id } = req.params;
+	// TODO:
+	// Load from database
+	// Admin control, but for now it allows anyone to be discoverable
 
 	res.send({
 		guild_id: guild_id,
 		safe_environment: true,
-        healthy: true,
-        health_score_pending: false,
-        size: true,
-        nsfw_properties: {},
-        protected: true,
-        sufficient: true,
-        sufficient_without_grace_period: true,
-        valid_rules_channel: true,
-        retention_healthy: true,
-        engagement_healthy: true,
-        age: true,
-        minimum_age: 0,
-        health_score: {
-            avg_nonnew_participators: 0,
-            avg_nonnew_communicators: 0,
-            num_intentful_joiners: 0,
-            perc_ret_w1_intentful: 0
-        },
-        minimum_size: 0
+		healthy: true,
+		health_score_pending: false,
+		size: true,
+		nsfw_properties: {},
+		protected: true,
+		sufficient: true,
+		sufficient_without_grace_period: true,
+		valid_rules_channel: true,
+		retention_healthy: true,
+		engagement_healthy: true,
+		age: true,
+		minimum_age: 0,
+		health_score: {
+			avg_nonnew_participators: 0,
+			avg_nonnew_communicators: 0,
+			num_intentful_joiners: 0,
+			perc_ret_w1_intentful: 0,
+		},
+		minimum_size: 0,
 	});
 });
 
diff --git a/src/api/routes/policies/instance/domains.ts b/src/api/routes/policies/instance/domains.ts
index 20cd07ba..f22eac17 100644
--- a/src/api/routes/policies/instance/domains.ts
+++ b/src/api/routes/policies/instance/domains.ts
@@ -1,16 +1,19 @@
 import { Router, Request, Response } from "express";
 import { route } from "@fosscord/api";
 import { Config } from "@fosscord/util";
-import { config } from "dotenv"
+import { config } from "dotenv";
 const router = Router();
 
-router.get("/",route({}), async (req: Request, res: Response) => {
-    const { cdn, gateway } = Config.get();
-    
-    const IdentityForm = {
-        cdn: cdn.endpointPublic || process.env.CDN || "http://localhost:3001",
-        gateway: gateway.endpointPublic || process.env.GATEWAY || "ws://localhost:3002"
-    };
+router.get("/", route({}), async (req: Request, res: Response) => {
+	const { cdn, gateway } = Config.get();
+
+	const IdentityForm = {
+		cdn: cdn.endpointPublic || process.env.CDN || "http://localhost:3001",
+		gateway:
+			gateway.endpointPublic ||
+			process.env.GATEWAY ||
+			"ws://localhost:3002",
+	};
 
 	res.json(IdentityForm);
 });
diff --git a/src/api/routes/policies/instance/index.ts b/src/api/routes/policies/instance/index.ts
index e3da014f..1c1afa09 100644
--- a/src/api/routes/policies/instance/index.ts
+++ b/src/api/routes/policies/instance/index.ts
@@ -3,8 +3,7 @@ import { route } from "@fosscord/api";
 import { Config } from "@fosscord/util";
 const router = Router();
 
-
-router.get("/",route({}), async (req: Request, res: Response) => {
+router.get("/", route({}), async (req: Request, res: Response) => {
 	const { general } = Config.get();
 	res.json(general);
 });
diff --git a/src/api/routes/policies/instance/limits.ts b/src/api/routes/policies/instance/limits.ts
index 7de1476b..06f14f83 100644
--- a/src/api/routes/policies/instance/limits.ts
+++ b/src/api/routes/policies/instance/limits.ts
@@ -3,7 +3,7 @@ import { route } from "@fosscord/api";
 import { Config } from "@fosscord/util";
 const router = Router();
 
-router.get("/",route({}), async (req: Request, res: Response) => {
+router.get("/", route({}), async (req: Request, res: Response) => {
 	const { limits } = Config.get();
 	res.json(limits);
 });
diff --git a/src/api/routes/scheduled-maintenances/upcoming_json.ts b/src/api/routes/scheduled-maintenances/upcoming_json.ts
index 83092e44..e42723a1 100644
--- a/src/api/routes/scheduled-maintenances/upcoming_json.ts
+++ b/src/api/routes/scheduled-maintenances/upcoming_json.ts
@@ -2,11 +2,15 @@ import { Router, Request, Response } from "express";
 import { route } from "@fosscord/api";
 const router = Router();
 
-router.get("/scheduled-maintenances/upcoming.json",route({}), async (req: Request, res: Response) => {
-	res.json({
-  "page": {},
-  "scheduled_maintenances": {}
-  });
-});
+router.get(
+	"/scheduled-maintenances/upcoming.json",
+	route({}),
+	async (req: Request, res: Response) => {
+		res.json({
+			page: {},
+			scheduled_maintenances: {},
+		});
+	},
+);
 
 export default router;
diff --git a/src/api/routes/stop.ts b/src/api/routes/stop.ts
index 7f8b78ba..78abb9d7 100644
--- a/src/api/routes/stop.ts
+++ b/src/api/routes/stop.ts
@@ -6,17 +6,19 @@ const router: Router = Router();
 
 router.post("/", route({}), async (req: Request, res: Response) => {
 	//EXPERIMENTAL: have an "OPERATOR" platform permission implemented for this API route
-	const user = await User.findOneOrFail({ where: { id: req.user_id }, select: ["rights"] });
-	if((Number(user.rights) << Number(0))%Number(2)==Number(1)) {
+	const user = await User.findOneOrFail({
+		where: { id: req.user_id },
+		select: ["rights"],
+	});
+	if ((Number(user.rights) << Number(0)) % Number(2) == Number(1)) {
 		console.log("user that POSTed to the API was ALLOWED");
 		console.log(user.rights);
-		res.sendStatus(200)
-		process.kill(process.pid, 'SIGTERM')
-	}
-	else {
+		res.sendStatus(200);
+		process.kill(process.pid, "SIGTERM");
+	} else {
 		console.log("operation failed");
 		console.log(user.rights);
-		res.sendStatus(403)
+		res.sendStatus(403);
 	}
 });
 
diff --git a/src/api/routes/store/published-listings/applications.ts b/src/api/routes/store/published-listings/applications.ts
index 060a4c3d..6156f43e 100644
--- a/src/api/routes/store/published-listings/applications.ts
+++ b/src/api/routes/store/published-listings/applications.ts
@@ -41,29 +41,29 @@ router.get("/:id", route({}), async (req: Request, res: Response) => {
 				publishers: [
 					{
 						id: "",
-						name: ""
-					}
+						name: "",
+					},
 				],
 				developers: [
 					{
 						id: "",
-						name: ""
-					}
+						name: "",
+					},
 				],
 				system_requirements: {},
 				show_age_gate: false,
 				price: {
 					amount: 0,
-					currency: "EUR"
+					currency: "EUR",
 				},
-				locales: []
+				locales: [],
 			},
 			tagline: "",
 			description: "",
 			carousel_items: [
 				{
-					asset_id: ""
-				}
+					asset_id: "",
+				},
 			],
 			header_logo_dark_theme: {}, //{id: "", size: 4665, mime_type: "image/gif", width 160, height: 160}
 			header_logo_light_theme: {},
@@ -71,8 +71,8 @@ router.get("/:id", route({}), async (req: Request, res: Response) => {
 			thumbnail: {},
 			header_background: {},
 			hero_background: {},
-			assets: []
-		}
+			assets: [],
+		},
 	}).status(200);
 });
 
diff --git a/src/api/routes/store/published-listings/applications/#id/subscription-plans.ts b/src/api/routes/store/published-listings/applications/#id/subscription-plans.ts
index 54151ae5..845cdfe7 100644
--- a/src/api/routes/store/published-listings/applications/#id/subscription-plans.ts
+++ b/src/api/routes/store/published-listings/applications/#id/subscription-plans.ts
@@ -17,8 +17,8 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 			fallback_currency: "eur",
 			currency: "eur",
 			price: 4199,
-			price_tier: null
-		}
+			price_tier: null,
+		},
 	]).status(200);
 });
 
diff --git a/src/api/routes/store/published-listings/skus.ts b/src/api/routes/store/published-listings/skus.ts
index 060a4c3d..6156f43e 100644
--- a/src/api/routes/store/published-listings/skus.ts
+++ b/src/api/routes/store/published-listings/skus.ts
@@ -41,29 +41,29 @@ router.get("/:id", route({}), async (req: Request, res: Response) => {
 				publishers: [
 					{
 						id: "",
-						name: ""
-					}
+						name: "",
+					},
 				],
 				developers: [
 					{
 						id: "",
-						name: ""
-					}
+						name: "",
+					},
 				],
 				system_requirements: {},
 				show_age_gate: false,
 				price: {
 					amount: 0,
-					currency: "EUR"
+					currency: "EUR",
 				},
-				locales: []
+				locales: [],
 			},
 			tagline: "",
 			description: "",
 			carousel_items: [
 				{
-					asset_id: ""
-				}
+					asset_id: "",
+				},
 			],
 			header_logo_dark_theme: {}, //{id: "", size: 4665, mime_type: "image/gif", width 160, height: 160}
 			header_logo_light_theme: {},
@@ -71,8 +71,8 @@ router.get("/:id", route({}), async (req: Request, res: Response) => {
 			thumbnail: {},
 			header_background: {},
 			hero_background: {},
-			assets: []
-		}
+			assets: [],
+		},
 	}).status(200);
 });
 
diff --git a/src/api/routes/store/published-listings/skus/#sku_id/subscription-plans.ts b/src/api/routes/store/published-listings/skus/#sku_id/subscription-plans.ts
index 03162ec8..33151056 100644
--- a/src/api/routes/store/published-listings/skus/#sku_id/subscription-plans.ts
+++ b/src/api/routes/store/published-listings/skus/#sku_id/subscription-plans.ts
@@ -17,8 +17,8 @@ const skus = new Map([
 				currency: "usd",
 				price: 0,
 				price_tier: null,
-			}
-		]
+			},
+		],
 	],
 	[
 		"521842865731534868",
@@ -32,7 +32,7 @@ const skus = new Map([
 				sku_id: "521842865731534868",
 				currency: "usd",
 				price: 0,
-				price_tier: null
+				price_tier: null,
 			},
 			{
 				id: "511651860671627264",
@@ -43,9 +43,9 @@ const skus = new Map([
 				sku_id: "521842865731534868",
 				currency: "usd",
 				price: 0,
-				price_tier: null
-			}
-		]
+				price_tier: null,
+			},
+		],
 	],
 	[
 		"521846918637420545",
@@ -59,7 +59,7 @@ const skus = new Map([
 				sku_id: "521846918637420545",
 				currency: "usd",
 				price: 0,
-				price_tier: null
+				price_tier: null,
 			},
 			{
 				id: "511651876987469824",
@@ -70,9 +70,9 @@ const skus = new Map([
 				sku_id: "521846918637420545",
 				currency: "usd",
 				price: 0,
-				price_tier: null
-			}
-		]
+				price_tier: null,
+			},
+		],
 	],
 	[
 		"521847234246082599",
@@ -86,7 +86,7 @@ const skus = new Map([
 				sku_id: "521847234246082599",
 				currency: "usd",
 				price: 0,
-				price_tier: null
+				price_tier: null,
 			},
 			{
 				id: "511651880837840896",
@@ -97,7 +97,7 @@ const skus = new Map([
 				sku_id: "521847234246082599",
 				currency: "usd",
 				price: 0,
-				price_tier: null
+				price_tier: null,
 			},
 			{
 				id: "511651885459963904",
@@ -108,9 +108,9 @@ const skus = new Map([
 				sku_id: "521847234246082599",
 				currency: "usd",
 				price: 0,
-				price_tier: null
-			}
-		]
+				price_tier: null,
+			},
+		],
 	],
 	[
 		"590663762298667008",
@@ -125,7 +125,7 @@ const skus = new Map([
 				discount_price: 0,
 				currency: "usd",
 				price: 0,
-				price_tier: null
+				price_tier: null,
 			},
 			{
 				id: "590665538238152709",
@@ -137,10 +137,10 @@ const skus = new Map([
 				discount_price: 0,
 				currency: "usd",
 				price: 0,
-				price_tier: null
-			}
-		]
-	]
+				price_tier: null,
+			},
+		],
+	],
 ]);
 
 router.get("/", route({}), async (req: Request, res: Response) => {
diff --git a/src/api/routes/updates.ts b/src/api/routes/updates.ts
index 42f77323..8fe6fc2a 100644
--- a/src/api/routes/updates.ts
+++ b/src/api/routes/updates.ts
@@ -7,13 +7,15 @@ const router = Router();
 router.get("/", route({}), async (req: Request, res: Response) => {
 	const { client } = Config.get();
 
-	const release = await Release.findOneOrFail({ where: { name: client.releases.upstreamVersion } });
+	const release = await Release.findOneOrFail({
+		where: { name: client.releases.upstreamVersion },
+	});
 
 	res.json({
 		name: release.name,
 		pub_date: release.pub_date,
 		url: release.url,
-		notes: release.notes
+		notes: release.notes,
 	});
 });
 
diff --git a/src/api/routes/users/#id/profile.ts b/src/api/routes/users/#id/profile.ts
index de96422a..ebea805b 100644
--- a/src/api/routes/users/#id/profile.ts
+++ b/src/api/routes/users/#id/profile.ts
@@ -1,5 +1,12 @@
 import { Router, Request, Response } from "express";
-import { PublicConnectedAccount, PublicUser, User, UserPublic, Member, Guild } from "@fosscord/util";
+import {
+	PublicConnectedAccount,
+	PublicUser,
+	User,
+	UserPublic,
+	Member,
+	Guild,
+} from "@fosscord/util";
 import { route } from "@fosscord/api";
 
 const router: Router = Router();
@@ -11,81 +18,102 @@ export interface UserProfileResponse {
 	premium_since?: Date;
 }
 
-router.get("/", route({ test: { response: { body: "UserProfileResponse" } } }), async (req: Request, res: Response) => {
-	if (req.params.id === "@me") req.params.id = req.user_id;
+router.get(
+	"/",
+	route({ test: { response: { body: "UserProfileResponse" } } }),
+	async (req: Request, res: Response) => {
+		if (req.params.id === "@me") req.params.id = req.user_id;
 
-	const { guild_id, with_mutual_guilds } = req.query;
+		const { guild_id, with_mutual_guilds } = req.query;
 
-	const user = await User.getPublicUser(req.params.id, { relations: ["connected_accounts"] });
+		const user = await User.getPublicUser(req.params.id, {
+			relations: ["connected_accounts"],
+		});
 
-	var mutual_guilds: object[] = [];
-	var premium_guild_since;
+		var mutual_guilds: object[] = [];
+		var premium_guild_since;
 
-	if (with_mutual_guilds == "true") {
-		const requested_member = await Member.find({ where: { id: req.params.id } });
-		const self_member = await Member.find({ where: { id: req.user_id } });
+		if (with_mutual_guilds == "true") {
+			const requested_member = await Member.find({
+				where: { id: req.params.id },
+			});
+			const self_member = await Member.find({
+				where: { id: req.user_id },
+			});
 
-		for (const rmem of requested_member) {
-			if (rmem.premium_since) {
-				if (premium_guild_since) {
-					if (premium_guild_since > rmem.premium_since) {
+			for (const rmem of requested_member) {
+				if (rmem.premium_since) {
+					if (premium_guild_since) {
+						if (premium_guild_since > rmem.premium_since) {
+							premium_guild_since = rmem.premium_since;
+						}
+					} else {
 						premium_guild_since = rmem.premium_since;
 					}
-				} else {
-					premium_guild_since = rmem.premium_since;
 				}
-			}
-			for (const smem of self_member) {
-				if (smem.guild_id === rmem.guild_id) {
-					mutual_guilds.push({ id: rmem.guild_id, nick: rmem.nick });
+				for (const smem of self_member) {
+					if (smem.guild_id === rmem.guild_id) {
+						mutual_guilds.push({
+							id: rmem.guild_id,
+							nick: rmem.nick,
+						});
+					}
 				}
 			}
 		}
-	}
 
-	const guild_member = guild_id && typeof guild_id == "string"
-		? await Member.findOneOrFail({ where: { id: req.params.id, guild_id: guild_id }, relations: ["roles"] })
-		: undefined;
+		const guild_member =
+			guild_id && typeof guild_id == "string"
+				? await Member.findOneOrFail({
+						where: { id: req.params.id, guild_id: guild_id },
+						relations: ["roles"],
+				  })
+				: undefined;
 
-	// TODO: make proper DTO's in util?
+		// TODO: make proper DTO's in util?
 
-	const userDto = {
-		username: user.username,
-		discriminator: user.discriminator,
-		id: user.id,
-		public_flags: user.public_flags,
-		avatar: user.avatar,
-		accent_color: user.accent_color,
-		banner: user.banner,
-		bio: req.user_bot ? null : user.bio,
-		bot: user.bot
-	};
+		const userDto = {
+			username: user.username,
+			discriminator: user.discriminator,
+			id: user.id,
+			public_flags: user.public_flags,
+			avatar: user.avatar,
+			accent_color: user.accent_color,
+			banner: user.banner,
+			bio: req.user_bot ? null : user.bio,
+			bot: user.bot,
+		};
 
-	const guildMemberDto = guild_member ? {
-		avatar: user.avatar,	// TODO
-		banner: user.banner,	// TODO
-		bio: req.user_bot ? null : user.bio, // TODO
-		communication_disabled_until: null,	// TODO
-		deaf: guild_member.deaf,
-		flags: user.flags,
-		is_pending: guild_member.pending,
-		pending: guild_member.pending,	// why is this here twice, discord?
-		joined_at: guild_member.joined_at,
-		mute: guild_member.mute,
-		nick: guild_member.nick,
-		premium_since: guild_member.premium_since,
-		roles: guild_member.roles.map(x => x.id).filter(id => id != guild_id),
-		user: userDto
-	} : undefined;
+		const guildMemberDto = guild_member
+			? {
+					avatar: user.avatar, // TODO
+					banner: user.banner, // TODO
+					bio: req.user_bot ? null : user.bio, // TODO
+					communication_disabled_until: null, // TODO
+					deaf: guild_member.deaf,
+					flags: user.flags,
+					is_pending: guild_member.pending,
+					pending: guild_member.pending, // why is this here twice, discord?
+					joined_at: guild_member.joined_at,
+					mute: guild_member.mute,
+					nick: guild_member.nick,
+					premium_since: guild_member.premium_since,
+					roles: guild_member.roles
+						.map((x) => x.id)
+						.filter((id) => id != guild_id),
+					user: userDto,
+			  }
+			: undefined;
 
-	res.json({
-		connected_accounts: user.connected_accounts,
-		premium_guild_since: premium_guild_since, // TODO
-		premium_since: user.premium_since, // TODO
-		mutual_guilds: mutual_guilds, // TODO {id: "", nick: null} when ?with_mutual_guilds=true
-		user: userDto,
-		guild_member: guildMemberDto,
-	});
-});
+		res.json({
+			connected_accounts: user.connected_accounts,
+			premium_guild_since: premium_guild_since, // TODO
+			premium_since: user.premium_since, // TODO
+			mutual_guilds: mutual_guilds, // TODO {id: "", nick: null} when ?with_mutual_guilds=true
+			user: userDto,
+			guild_member: guildMemberDto,
+		});
+	},
+);
 
 export default router;
diff --git a/src/api/routes/users/#id/relationships.ts b/src/api/routes/users/#id/relationships.ts
index de7cb9d3..c6480567 100644
--- a/src/api/routes/users/#id/relationships.ts
+++ b/src/api/routes/users/#id/relationships.ts
@@ -6,36 +6,49 @@ const router: Router = Router();
 
 export interface UserRelationsResponse {
 	object: {
-		id?: string,
-		username?: string,
-		avatar?: string, 
-		discriminator?: string, 
-		public_flags?: number
-	}
+		id?: string;
+		username?: string;
+		avatar?: string;
+		discriminator?: string;
+		public_flags?: number;
+	};
 }
 
+router.get(
+	"/",
+	route({ test: { response: { body: "UserRelationsResponse" } } }),
+	async (req: Request, res: Response) => {
+		var mutual_relations: object[] = [];
+		const requested_relations = await User.findOneOrFail({
+			where: { id: req.params.id },
+			relations: ["relationships"],
+		});
+		const self_relations = await User.findOneOrFail({
+			where: { id: req.user_id },
+			relations: ["relationships"],
+		});
 
-router.get("/", route({ test: { response: { body: "UserRelationsResponse" } } }), async (req: Request, res: Response) => {
-	var mutual_relations: object[] = [];
-    const requested_relations = await User.findOneOrFail({
-		where: { id: req.params.id },
-		relations: ["relationships"]
-	});
-    const self_relations = await User.findOneOrFail({
-		where: { id: req.user_id },
-		relations: ["relationships"]
-	});
-	
-    for(const rmem of requested_relations.relationships) {
-		for(const smem of self_relations.relationships)
-		if (rmem.to_id === smem.to_id && rmem.type === 1 && rmem.to_id !== req.user_id) {
-			var relation_user = await User.getPublicUser(rmem.to_id)
+		for (const rmem of requested_relations.relationships) {
+			for (const smem of self_relations.relationships)
+				if (
+					rmem.to_id === smem.to_id &&
+					rmem.type === 1 &&
+					rmem.to_id !== req.user_id
+				) {
+					var relation_user = await User.getPublicUser(rmem.to_id);
 
-			mutual_relations.push({id: relation_user.id, username: relation_user.username, avatar: relation_user.avatar, discriminator: relation_user.discriminator, public_flags: relation_user.public_flags})
+					mutual_relations.push({
+						id: relation_user.id,
+						username: relation_user.username,
+						avatar: relation_user.avatar,
+						discriminator: relation_user.discriminator,
+						public_flags: relation_user.public_flags,
+					});
+				}
 		}
-	}
 
-	res.json(mutual_relations)
-});
+		res.json(mutual_relations);
+	},
+);
 
 export default router;
diff --git a/src/api/routes/users/@me/channels.ts b/src/api/routes/users/@me/channels.ts
index ad483529..237be102 100644
--- a/src/api/routes/users/@me/channels.ts
+++ b/src/api/routes/users/@me/channels.ts
@@ -1,5 +1,10 @@
 import { Request, Response, Router } from "express";
-import { Recipient, DmChannelDTO, Channel, DmChannelCreateSchema } from "@fosscord/util";
+import {
+	Recipient,
+	DmChannelDTO,
+	Channel,
+	DmChannelCreateSchema,
+} from "@fosscord/util";
 import { route } from "@fosscord/api";
 
 const router: Router = Router();
@@ -7,14 +12,28 @@ const router: Router = Router();
 router.get("/", route({}), async (req: Request, res: Response) => {
 	const recipients = await Recipient.find({
 		where: { user_id: req.user_id, closed: false },
-		relations: ["channel", "channel.recipients"]
+		relations: ["channel", "channel.recipients"],
 	});
-	res.json(await Promise.all(recipients.map((r) => DmChannelDTO.from(r.channel, [req.user_id]))));
+	res.json(
+		await Promise.all(
+			recipients.map((r) => DmChannelDTO.from(r.channel, [req.user_id])),
+		),
+	);
 });
 
-router.post("/", route({ body: "DmChannelCreateSchema" }), async (req: Request, res: Response) => {
-	const body = req.body as DmChannelCreateSchema;
-	res.json(await Channel.createDMChannel(body.recipients, req.user_id, body.name));
-});
+router.post(
+	"/",
+	route({ body: "DmChannelCreateSchema" }),
+	async (req: Request, res: Response) => {
+		const body = req.body as DmChannelCreateSchema;
+		res.json(
+			await Channel.createDMChannel(
+				body.recipients,
+				req.user_id,
+				body.name,
+			),
+		);
+	},
+);
 
 export default router;
diff --git a/src/api/routes/users/@me/delete.ts b/src/api/routes/users/@me/delete.ts
index c24c3f1e..a9f8167c 100644
--- a/src/api/routes/users/@me/delete.ts
+++ b/src/api/routes/users/@me/delete.ts
@@ -7,7 +7,10 @@ import { HTTPError } from "lambert-server";
 const router = Router();
 
 router.post("/", route({}), async (req: Request, res: Response) => {
-	const user = await User.findOneOrFail({ where: { id: req.user_id }, select: ["data"] }); //User object
+	const user = await User.findOneOrFail({
+		where: { id: req.user_id },
+		select: ["data"],
+	}); //User object
 	let correctpass = true;
 
 	if (user.data.hash) {
@@ -21,7 +24,10 @@ router.post("/", route({}), async (req: Request, res: Response) => {
 	// TODO: decrement guild member count
 
 	if (correctpass) {
-		await Promise.all([User.delete({ id: req.user_id }), Member.delete({ id: req.user_id })]);
+		await Promise.all([
+			User.delete({ id: req.user_id }),
+			Member.delete({ id: req.user_id }),
+		]);
 
 		res.sendStatus(204);
 	} else {
diff --git a/src/api/routes/users/@me/disable.ts b/src/api/routes/users/@me/disable.ts
index 4aff3774..313a888f 100644
--- a/src/api/routes/users/@me/disable.ts
+++ b/src/api/routes/users/@me/disable.ts
@@ -6,7 +6,10 @@ import bcrypt from "bcrypt";
 const router = Router();
 
 router.post("/", route({}), async (req: Request, res: Response) => {
-	const user = await User.findOneOrFail({ where: { id: req.user_id }, select: ["data"] }); //User object
+	const user = await User.findOneOrFail({
+		where: { id: req.user_id },
+		select: ["data"],
+	}); //User object
 	let correctpass = true;
 
 	if (user.data.hash) {
@@ -19,7 +22,10 @@ router.post("/", route({}), async (req: Request, res: Response) => {
 
 		res.sendStatus(204);
 	} else {
-		res.status(400).json({ message: "Password does not match", code: 50018 });
+		res.status(400).json({
+			message: "Password does not match",
+			code: 50018,
+		});
 	}
 });
 
diff --git a/src/api/routes/users/@me/email-settings.ts b/src/api/routes/users/@me/email-settings.ts
index 3114984e..a2834b89 100644
--- a/src/api/routes/users/@me/email-settings.ts
+++ b/src/api/routes/users/@me/email-settings.ts
@@ -11,9 +11,9 @@ router.get("/", route({}), (req: Request, res: Response) => {
 			communication: true,
 			tips: false,
 			updates_and_announcements: false,
-			recommendations_and_events: false
+			recommendations_and_events: false,
 		},
-		initialized: false
+		initialized: false,
 	}).status(200);
 });
 
diff --git a/src/api/routes/users/@me/guilds.ts b/src/api/routes/users/@me/guilds.ts
index 754a240e..e12bf258 100644
--- a/src/api/routes/users/@me/guilds.ts
+++ b/src/api/routes/users/@me/guilds.ts
@@ -1,12 +1,23 @@
 import { Router, Request, Response } from "express";
-import { Guild, Member, User, GuildDeleteEvent, GuildMemberRemoveEvent, emitEvent, Config } from "@fosscord/util";
+import {
+	Guild,
+	Member,
+	User,
+	GuildDeleteEvent,
+	GuildMemberRemoveEvent,
+	emitEvent,
+	Config,
+} from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { route } from "@fosscord/api";
 
 const router: Router = Router();
 
 router.get("/", route({}), async (req: Request, res: Response) => {
-	const members = await Member.find({ relations: ["guild"], where: { id: req.user_id } });
+	const members = await Member.find({
+		relations: ["guild"],
+		where: { id: req.user_id },
+	});
 
 	let guild = members.map((x) => x.guild);
 
@@ -21,11 +32,19 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 router.delete("/:guild_id", route({}), async (req: Request, res: Response) => {
 	const { autoJoin } = Config.get().guild;
 	const { guild_id } = req.params;
-	const guild = await Guild.findOneOrFail({ where: { id: guild_id }, select: ["owner_id"] });
+	const guild = await Guild.findOneOrFail({
+		where: { id: guild_id },
+		select: ["owner_id"],
+	});
 
 	if (!guild) throw new HTTPError("Guild doesn't exist", 404);
-	if (guild.owner_id === req.user_id) throw new HTTPError("You can't leave your own guild", 400);
-	if (autoJoin.enabled && autoJoin.guilds.includes(guild_id) && !autoJoin.canLeave) {
+	if (guild.owner_id === req.user_id)
+		throw new HTTPError("You can't leave your own guild", 400);
+	if (
+		autoJoin.enabled &&
+		autoJoin.guilds.includes(guild_id) &&
+		!autoJoin.canLeave
+	) {
 		throw new HTTPError("You can't leave instance auto join guilds", 400);
 	}
 
@@ -34,10 +53,10 @@ router.delete("/:guild_id", route({}), async (req: Request, res: Response) => {
 		emitEvent({
 			event: "GUILD_DELETE",
 			data: {
-				id: guild_id
+				id: guild_id,
 			},
-			user_id: req.user_id
-		} as GuildDeleteEvent)
+			user_id: req.user_id,
+		} as GuildDeleteEvent),
 	]);
 
 	const user = await User.getPublicUser(req.user_id);
@@ -46,9 +65,9 @@ router.delete("/:guild_id", route({}), async (req: Request, res: Response) => {
 		event: "GUILD_MEMBER_REMOVE",
 		data: {
 			guild_id: guild_id,
-			user: user
+			user: user,
 		},
-		guild_id: guild_id
+		guild_id: guild_id,
 	} as GuildMemberRemoveEvent);
 
 	return res.sendStatus(204);
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 f09be25b..4b806cfb 100644
--- a/src/api/routes/users/@me/guilds/#guild_id/settings.ts
+++ b/src/api/routes/users/@me/guilds/#guild_id/settings.ts
@@ -1,39 +1,51 @@
 import { Router, Response, Request } from "express";
-import { Channel, ChannelOverride, Member, UserGuildSettings } from "@fosscord/util";
+import {
+	Channel,
+	ChannelOverride,
+	Member,
+	UserGuildSettings,
+} from "@fosscord/util";
 import { route } from "@fosscord/api";
 
 const router = Router();
 
 // This sucks. I would use a DeepPartial, my own or typeorms, but they both generate inncorect schema
-export interface UserGuildSettingsSchema extends Partial<Omit<UserGuildSettings, 'channel_overrides'>> {
+export interface UserGuildSettingsSchema
+	extends Partial<Omit<UserGuildSettings, "channel_overrides">> {
 	channel_overrides: {
 		[channel_id: string]: Partial<ChannelOverride>;
-	},
+	};
 }
 
 // GET doesn't exist on discord.com
 router.get("/", route({}), async (req: Request, res: Response) => {
 	const user = await Member.findOneOrFail({
 		where: { id: req.user_id, guild_id: req.params.guild_id },
-		select: ["settings"]
+		select: ["settings"],
 	});
 	return res.json(user.settings);
 });
 
-router.patch("/", route({ body: "UserGuildSettingsSchema" }), async (req: Request, res: Response) => {
-	const body = req.body as UserGuildSettings;
+router.patch(
+	"/",
+	route({ body: "UserGuildSettingsSchema" }),
+	async (req: Request, res: Response) => {
+		const body = req.body as UserGuildSettings;
 
-	if (body.channel_overrides) {
-		for (var channel in body.channel_overrides) {
-			Channel.findOneOrFail({ where: { id: channel } });
+		if (body.channel_overrides) {
+			for (var channel in body.channel_overrides) {
+				Channel.findOneOrFail({ where: { id: channel } });
+			}
 		}
-	}
 
-	const user = await Member.findOneOrFail({ where: { id: req.user_id, guild_id: req.params.guild_id } });
-	user.settings = { ...user.settings, ...body };
-	await user.save();
+		const user = await Member.findOneOrFail({
+			where: { id: req.user_id, guild_id: req.params.guild_id },
+		});
+		user.settings = { ...user.settings, ...body };
+		await user.save();
 
-	res.json(user.settings);
-});
+		res.json(user.settings);
+	},
+);
 
 export default router;
diff --git a/src/api/routes/users/@me/index.ts b/src/api/routes/users/@me/index.ts
index e849b72a..5eba4665 100644
--- a/src/api/routes/users/@me/index.ts
+++ b/src/api/routes/users/@me/index.ts
@@ -1,5 +1,15 @@
 import { Router, Request, Response } from "express";
-import { User, PrivateUserProjection, emitEvent, UserUpdateEvent, handleFile, FieldErrors, adjustEmail, Config, UserModifySchema } from "@fosscord/util";
+import {
+	User,
+	PrivateUserProjection,
+	emitEvent,
+	UserUpdateEvent,
+	handleFile,
+	FieldErrors,
+	adjustEmail,
+	Config,
+	UserModifySchema,
+} from "@fosscord/util";
 import { route } from "@fosscord/api";
 import bcrypt from "bcrypt";
 import { HTTPError } from "lambert-server";
@@ -7,79 +17,134 @@ import { HTTPError } from "lambert-server";
 const router: Router = Router();
 
 router.get("/", route({}), async (req: Request, res: Response) => {
-	res.json(await User.findOne({ select: PrivateUserProjection, where: { id: req.user_id } }));
+	res.json(
+		await User.findOne({
+			select: PrivateUserProjection,
+			where: { id: req.user_id },
+		}),
+	);
 });
 
-router.patch("/", route({ body: "UserModifySchema" }), async (req: Request, res: Response) => {
-	const body = req.body as UserModifySchema;
-
-	const user = await User.findOneOrFail({ where: { id: req.user_id }, select: [...PrivateUserProjection, "data"] });
-
-	if (user.email == "demo@maddy.k.vu") throw new HTTPError("Demo user, sorry", 400);
+router.patch(
+	"/",
+	route({ body: "UserModifySchema" }),
+	async (req: Request, res: Response) => {
+		const body = req.body as UserModifySchema;
+
+		const user = await User.findOneOrFail({
+			where: { id: req.user_id },
+			select: [...PrivateUserProjection, "data"],
+		});
+
+		if (user.email == "demo@maddy.k.vu")
+			throw new HTTPError("Demo user, sorry", 400);
+
+		if (body.avatar)
+			body.avatar = await handleFile(
+				`/avatars/${req.user_id}`,
+				body.avatar as string,
+			);
+		if (body.banner)
+			body.banner = await handleFile(
+				`/banners/${req.user_id}`,
+				body.banner as string,
+			);
+
+		if (body.password) {
+			if (user.data?.hash) {
+				const same_password = await bcrypt.compare(
+					body.password,
+					user.data.hash || "",
+				);
+				if (!same_password) {
+					throw FieldErrors({
+						password: {
+							message: req.t("auth:login.INVALID_PASSWORD"),
+							code: "INVALID_PASSWORD",
+						},
+					});
+				}
+			} else {
+				user.data.hash = await bcrypt.hash(body.password, 12);
+			}
+		}
 
-	if (body.avatar) body.avatar = await handleFile(`/avatars/${req.user_id}`, body.avatar as string);
-	if (body.banner) body.banner = await handleFile(`/banners/${req.user_id}`, body.banner as string);
+		if (body.email) {
+			body.email = adjustEmail(body.email);
+			if (!body.email && Config.get().register.email.required)
+				throw FieldErrors({
+					email: {
+						message: req.t("auth:register.EMAIL_INVALID"),
+						code: "EMAIL_INVALID",
+					},
+				});
+			if (!body.password)
+				throw FieldErrors({
+					password: {
+						message: req.t("auth:register.INVALID_PASSWORD"),
+						code: "INVALID_PASSWORD",
+					},
+				});
+		}
 
-	if (body.password) {
-		if (user.data?.hash) {
-			const same_password = await bcrypt.compare(body.password, user.data.hash || "");
-			if (!same_password) {
-				throw FieldErrors({ password: { message: req.t("auth:login.INVALID_PASSWORD"), code: "INVALID_PASSWORD" } });
+		if (body.new_password) {
+			if (!body.password && !user.email) {
+				throw FieldErrors({
+					password: {
+						code: "BASE_TYPE_REQUIRED",
+						message: req.t("common:field.BASE_TYPE_REQUIRED"),
+					},
+				});
 			}
-		} else {
-			user.data.hash = await bcrypt.hash(body.password, 12);
+			user.data.hash = await bcrypt.hash(body.new_password, 12);
 		}
-	}
-
-	if (body.email) {
-		body.email = adjustEmail(body.email);
-		if (!body.email && Config.get().register.email.required)
-			throw FieldErrors({ email: { message: req.t("auth:register.EMAIL_INVALID"), code: "EMAIL_INVALID" } });
-		if (!body.password)
-			throw FieldErrors({ password: { message: req.t("auth:register.INVALID_PASSWORD"), code: "INVALID_PASSWORD" } });
-	}
-
-	if (body.new_password) {
-		if (!body.password && !user.email) {
-			throw FieldErrors({
-				password: { code: "BASE_TYPE_REQUIRED", message: req.t("common:field.BASE_TYPE_REQUIRED") }
-			});
-		}
-		user.data.hash = await bcrypt.hash(body.new_password, 12);
-	}
-
-	if (body.username) {
-		var check_username = body?.username?.replace(/\s/g, '');
-		if (!check_username) {
-			throw FieldErrors({
-				username: { code: "BASE_TYPE_REQUIRED", message: req.t("common:field.BASE_TYPE_REQUIRED") }
-			});
+
+		if (body.username) {
+			var check_username = body?.username?.replace(/\s/g, "");
+			if (!check_username) {
+				throw FieldErrors({
+					username: {
+						code: "BASE_TYPE_REQUIRED",
+						message: req.t("common:field.BASE_TYPE_REQUIRED"),
+					},
+				});
+			}
 		}
-	}
 
-	if (body.discriminator) {
-		if (await User.findOne({ where: { discriminator: body.discriminator, username: body.username || user.username } })) {
-			throw FieldErrors({
-				discriminator: { code: "INVALID_DISCRIMINATOR", message: "This discriminator is already in use." }
-			});
+		if (body.discriminator) {
+			if (
+				await User.findOne({
+					where: {
+						discriminator: body.discriminator,
+						username: body.username || user.username,
+					},
+				})
+			) {
+				throw FieldErrors({
+					discriminator: {
+						code: "INVALID_DISCRIMINATOR",
+						message: "This discriminator is already in use.",
+					},
+				});
+			}
 		}
-	}
 
-	user.assign(body);
-	await user.save();
+		user.assign(body);
+		await user.save();
 
-	// @ts-ignore
-	delete user.data;
+		// @ts-ignore
+		delete user.data;
 
-	// TODO: send update member list event in gateway
-	await emitEvent({
-		event: "USER_UPDATE",
-		user_id: req.user_id,
-		data: user
-	} as UserUpdateEvent);
+		// TODO: send update member list event in gateway
+		await emitEvent({
+			event: "USER_UPDATE",
+			user_id: req.user_id,
+			data: user,
+		} as UserUpdateEvent);
 
-	res.json(user);
-});
+		res.json(user);
+	},
+);
 
 export default router;
 // {"message": "Invalid two-factor code", "code": 60008}
diff --git a/src/api/routes/users/@me/mfa/codes-verification.ts b/src/api/routes/users/@me/mfa/codes-verification.ts
index 071c71fa..3411605b 100644
--- a/src/api/routes/users/@me/mfa/codes-verification.ts
+++ b/src/api/routes/users/@me/mfa/codes-verification.ts
@@ -1,41 +1,49 @@
 import { Router, Request, Response } from "express";
 import { route } from "@fosscord/api";
-import { BackupCode, generateMfaBackupCodes, User, CodesVerificationSchema } from "@fosscord/util";
+import {
+	BackupCode,
+	generateMfaBackupCodes,
+	User,
+	CodesVerificationSchema,
+} from "@fosscord/util";
 
 const router = Router();
 
-router.post("/", route({ body: "CodesVerificationSchema" }), async (req: Request, res: Response) => {
-	const { key, nonce, 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 } });
-
-	var codes: BackupCode[];
-	if (regenerate) {
-		await BackupCode.update(
-			{ user: { id: req.user_id } },
-			{ expired: true }
-		);
-
-		codes = generateMfaBackupCodes(req.user_id);
-		await Promise.all(codes.map(x => x.save()));
-	}
-	else {
-		codes = await BackupCode.find({
-			where: {
-				user: {
-					id: req.user_id,
+router.post(
+	"/",
+	route({ body: "CodesVerificationSchema" }),
+	async (req: Request, res: Response) => {
+		const { key, nonce, 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 } });
+
+		var codes: BackupCode[];
+		if (regenerate) {
+			await BackupCode.update(
+				{ user: { id: req.user_id } },
+				{ expired: true },
+			);
+
+			codes = generateMfaBackupCodes(req.user_id);
+			await Promise.all(codes.map((x) => x.save()));
+		} else {
+			codes = await BackupCode.find({
+				where: {
+					user: {
+						id: req.user_id,
+					},
+					expired: false,
 				},
-				expired: false,
-			}
-		});
-	}
+			});
+		}
 
-	return res.json({
-		backup_codes: codes.map(x => ({ ...x, expired: undefined })),
-	});
-});
+		return res.json({
+			backup_codes: codes.map((x) => ({ ...x, expired: undefined })),
+		});
+	},
+);
 
 export default router;
diff --git a/src/api/routes/users/@me/mfa/codes.ts b/src/api/routes/users/@me/mfa/codes.ts
index 58466b9c..33053028 100644
--- a/src/api/routes/users/@me/mfa/codes.ts
+++ b/src/api/routes/users/@me/mfa/codes.ts
@@ -1,45 +1,62 @@
 import { Router, Request, Response } from "express";
 import { route } from "@fosscord/api";
-import { BackupCode, FieldErrors, generateMfaBackupCodes, User, MfaCodesSchema } from "@fosscord/util";
+import {
+	BackupCode,
+	FieldErrors,
+	generateMfaBackupCodes,
+	User,
+	MfaCodesSchema,
+} from "@fosscord/util";
 import bcrypt from "bcrypt";
 
 const router = Router();
 
 // TODO: This route is replaced with users/@me/mfa/codes-verification in newer clients
 
-router.post("/", route({ body: "MfaCodesSchema" }), async (req: Request, res: Response) => {
-	const { password, regenerate } = req.body as MfaCodesSchema;
-
-	const user = await User.findOneOrFail({ where: { id: req.user_id }, select: ["data"] });
-
-	if (!await bcrypt.compare(password, user.data.hash || "")) {
-		throw FieldErrors({ password: { message: req.t("auth:login.INVALID_PASSWORD"), code: "INVALID_PASSWORD" } });
-	}
-
-	var codes: BackupCode[];
-	if (regenerate) {
-		await BackupCode.update(
-			{ user: { id: req.user_id } },
-			{ expired: true }
-		);
-
-		codes = generateMfaBackupCodes(req.user_id);
-		await Promise.all(codes.map(x => x.save()));
-	}
-	else {
-		codes = await BackupCode.find({
-			where: {
-				user: {
-					id: req.user_id,
-				},
-				expired: false,
-			}
+router.post(
+	"/",
+	route({ body: "MfaCodesSchema" }),
+	async (req: Request, res: Response) => {
+		const { password, regenerate } = req.body as MfaCodesSchema;
+
+		const user = await User.findOneOrFail({
+			where: { id: req.user_id },
+			select: ["data"],
 		});
-	}
 
-	return res.json({
-		backup_codes: codes.map(x => ({ ...x, expired: undefined })),
-	});
-});
+		if (!(await bcrypt.compare(password, user.data.hash || ""))) {
+			throw FieldErrors({
+				password: {
+					message: req.t("auth:login.INVALID_PASSWORD"),
+					code: "INVALID_PASSWORD",
+				},
+			});
+		}
+
+		var codes: BackupCode[];
+		if (regenerate) {
+			await BackupCode.update(
+				{ user: { id: req.user_id } },
+				{ expired: true },
+			);
+
+			codes = generateMfaBackupCodes(req.user_id);
+			await Promise.all(codes.map((x) => x.save()));
+		} else {
+			codes = await BackupCode.find({
+				where: {
+					user: {
+						id: req.user_id,
+					},
+					expired: false,
+				},
+			});
+		}
+
+		return res.json({
+			backup_codes: codes.map((x) => ({ ...x, expired: undefined })),
+		});
+	},
+);
 
 export default router;
diff --git a/src/api/routes/users/@me/mfa/totp/disable.ts b/src/api/routes/users/@me/mfa/totp/disable.ts
index 2fe9355c..7916e598 100644
--- a/src/api/routes/users/@me/mfa/totp/disable.ts
+++ b/src/api/routes/users/@me/mfa/totp/disable.ts
@@ -1,41 +1,56 @@
 import { Router, Request, Response } from "express";
 import { route } from "@fosscord/api";
-import { verifyToken } from 'node-2fa';
+import { verifyToken } from "node-2fa";
 import { HTTPError } from "lambert-server";
-import { User, generateToken, BackupCode, TotpDisableSchema } from "@fosscord/util";
+import {
+	User,
+	generateToken,
+	BackupCode,
+	TotpDisableSchema,
+} from "@fosscord/util";
 
 const router = Router();
 
-router.post("/", route({ body: "TotpDisableSchema" }), async (req: Request, res: Response) => {
-	const body = req.body as TotpDisableSchema;
-
-	const user = await User.findOneOrFail({ where: { id: req.user_id }, select: ["totp_secret"] });
-
-	const backup = await BackupCode.findOne({ where: { code: body.code } });
-	if (!backup) {
-		const ret = verifyToken(user.totp_secret!, body.code);
-		if (!ret || ret.delta != 0)
-			throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
-	}
-
-	await User.update(
-		{ id: req.user_id },
-		{
-			mfa_enabled: false,
-			totp_secret: "",
-		},
-	);
-
-	await BackupCode.update(
-		{ user: { id: req.user_id } },
-		{
-			expired: true,
+router.post(
+	"/",
+	route({ body: "TotpDisableSchema" }),
+	async (req: Request, res: Response) => {
+		const body = req.body as TotpDisableSchema;
+
+		const user = await User.findOneOrFail({
+			where: { id: req.user_id },
+			select: ["totp_secret"],
+		});
+
+		const backup = await BackupCode.findOne({ where: { code: body.code } });
+		if (!backup) {
+			const ret = verifyToken(user.totp_secret!, body.code);
+			if (!ret || ret.delta != 0)
+				throw new HTTPError(
+					req.t("auth:login.INVALID_TOTP_CODE"),
+					60008,
+				);
 		}
-	);
 
-	return res.json({
-		token: await generateToken(user.id),
-	});
-});
-
-export default router;
\ No newline at end of file
+		await User.update(
+			{ id: req.user_id },
+			{
+				mfa_enabled: false,
+				totp_secret: "",
+			},
+		);
+
+		await BackupCode.update(
+			{ user: { id: req.user_id } },
+			{
+				expired: true,
+			},
+		);
+
+		return res.json({
+			token: await generateToken(user.id),
+		});
+	},
+);
+
+export default router;
diff --git a/src/api/routes/users/@me/mfa/totp/enable.ts b/src/api/routes/users/@me/mfa/totp/enable.ts
index adafe180..75c64425 100644
--- a/src/api/routes/users/@me/mfa/totp/enable.ts
+++ b/src/api/routes/users/@me/mfa/totp/enable.ts
@@ -1,46 +1,62 @@
 import { Router, Request, Response } from "express";
-import { User, generateToken, generateMfaBackupCodes, TotpEnableSchema } from "@fosscord/util";
+import {
+	User,
+	generateToken,
+	generateMfaBackupCodes,
+	TotpEnableSchema,
+} from "@fosscord/util";
 import { route } from "@fosscord/api";
 import bcrypt from "bcrypt";
 import { HTTPError } from "lambert-server";
-import { verifyToken } from 'node-2fa';
+import { verifyToken } from "node-2fa";
 
 const router = Router();
 
-router.post("/", route({ body: "TotpEnableSchema" }), async (req: Request, res: Response) => {
-	const body = req.body as TotpEnableSchema;
-
-	const user = await User.findOneOrFail({ where: { id: req.user_id }, select: ["data", "email"] });
-
-	if (user.email == "demo@maddy.k.vu") throw new HTTPError("Demo user, sorry", 400);
-
-	// TODO: Are guests allowed to enable 2fa?
-	if (user.data.hash) {
-		if (!await bcrypt.compare(body.password, user.data.hash)) {
-			throw new HTTPError(req.t("auth:login.INVALID_PASSWORD"));
+router.post(
+	"/",
+	route({ body: "TotpEnableSchema" }),
+	async (req: Request, res: Response) => {
+		const body = req.body as TotpEnableSchema;
+
+		const user = await User.findOneOrFail({
+			where: { id: req.user_id },
+			select: ["data", "email"],
+		});
+
+		if (user.email == "demo@maddy.k.vu")
+			throw new HTTPError("Demo user, sorry", 400);
+
+		// TODO: Are guests allowed to enable 2fa?
+		if (user.data.hash) {
+			if (!(await bcrypt.compare(body.password, user.data.hash))) {
+				throw new HTTPError(req.t("auth:login.INVALID_PASSWORD"));
+			}
 		}
-	}
-
-	if (!body.secret)
-		throw new HTTPError(req.t("auth:login.INVALID_TOTP_SECRET"), 60005);
-
-	if (!body.code)
-		throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
-
-	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);
-	await Promise.all(backup_codes.map(x => x.save()));
-	await User.update(
-		{ id: req.user_id },
-		{ mfa_enabled: true, totp_secret: body.secret }
-	);
-
-	res.send({
-		token: await generateToken(user.id),
-		backup_codes: backup_codes.map(x => ({ ...x, expired: undefined })),
-	});
-});
 
-export default router;
\ No newline at end of file
+		if (!body.secret)
+			throw new HTTPError(req.t("auth:login.INVALID_TOTP_SECRET"), 60005);
+
+		if (!body.code)
+			throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
+
+		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);
+		await Promise.all(backup_codes.map((x) => x.save()));
+		await User.update(
+			{ id: req.user_id },
+			{ mfa_enabled: true, totp_secret: body.secret },
+		);
+
+		res.send({
+			token: await generateToken(user.id),
+			backup_codes: backup_codes.map((x) => ({
+				...x,
+				expired: undefined,
+			})),
+		});
+	},
+);
+
+export default router;
diff --git a/src/api/routes/users/@me/notes.ts b/src/api/routes/users/@me/notes.ts
index f938f088..e54eb897 100644
--- a/src/api/routes/users/@me/notes.ts
+++ b/src/api/routes/users/@me/notes.ts
@@ -11,7 +11,7 @@ router.get("/:id", route({}), async (req: Request, res: Response) => {
 		where: {
 			owner: { id: req.user_id },
 			target: { id: id },
-		}
+		},
 	});
 
 	return res.json({
@@ -24,32 +24,40 @@ router.get("/:id", route({}), async (req: Request, res: Response) => {
 router.put("/:id", route({}), async (req: Request, res: Response) => {
 	const { id } = req.params;
 	const owner = await User.findOneOrFail({ where: { id: req.user_id } });
-	const target = await User.findOneOrFail({ where: { id: id } });		//if noted user does not exist throw
+	const target = await User.findOneOrFail({ where: { id: id } }); //if noted user does not exist throw
 	const { note } = req.body;
 
 	if (note && note.length) {
 		// upsert a note
-		if (await Note.findOne({ where: { owner: { id: owner.id }, target: { id: target.id } } })) {
+		if (
+			await Note.findOne({
+				where: { owner: { id: owner.id }, target: { id: target.id } },
+			})
+		) {
 			Note.update(
 				{ owner: { id: owner.id }, target: { id: target.id } },
-				{ owner, target, content: note }
+				{ owner, target, content: note },
 			);
+		} else {
+			Note.insert({
+				id: Snowflake.generate(),
+				owner,
+				target,
+				content: note,
+			});
 		}
-		else {
-			Note.insert(
-				{ id: Snowflake.generate(), owner, target, content: note }
-			);
-		}
-	}
-	else {
-		await Note.delete({ owner: { id: owner.id }, target: { id: target.id } });
+	} else {
+		await Note.delete({
+			owner: { id: owner.id },
+			target: { id: target.id },
+		});
 	}
 
 	await emitEvent({
 		event: "USER_NOTE_UPDATE",
 		data: {
 			note: note,
-			id: target.id
+			id: target.id,
 		},
 		user_id: owner.id,
 	});
diff --git a/src/api/routes/users/@me/relationships.ts b/src/api/routes/users/@me/relationships.ts
index cd33704d..3eec704b 100644
--- a/src/api/routes/users/@me/relationships.ts
+++ b/src/api/routes/users/@me/relationships.ts
@@ -6,7 +6,7 @@ import {
 	RelationshipRemoveEvent,
 	emitEvent,
 	Relationship,
-	Config
+	Config,
 } from "@fosscord/util";
 import { Router, Response, Request } from "express";
 import { HTTPError } from "lambert-server";
@@ -15,13 +15,16 @@ import { route } from "@fosscord/api";
 
 const router = Router();
 
-const userProjection: (keyof User)[] = ["relationships", ...PublicUserProjection];
+const userProjection: (keyof User)[] = [
+	"relationships",
+	...PublicUserProjection,
+];
 
 router.get("/", route({}), async (req: Request, res: Response) => {
 	const user = await User.findOneOrFail({
 		where: { id: req.user_id },
 		relations: ["relationships", "relationships.to"],
-		select: ["id", "relationships"]
+		select: ["id", "relationships"],
 	});
 
 	//TODO DTO
@@ -30,49 +33,76 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 			id: r.to.id,
 			type: r.type,
 			nickname: null,
-			user: r.to.toPublicUser()
+			user: r.to.toPublicUser(),
 		};
 	});
 
 	return res.json(related_users);
 });
 
-router.put("/:id", route({ body: "RelationshipPutSchema" }), async (req: Request, res: Response) => {
-	return await updateRelationship(
-		req,
-		res,
-		await User.findOneOrFail({ where: { id: req.params.id }, relations: ["relationships", "relationships.to"], select: userProjection }),
-		req.body.type ?? RelationshipType.friends
-	);
-});
+router.put(
+	"/:id",
+	route({ body: "RelationshipPutSchema" }),
+	async (req: Request, res: Response) => {
+		return await updateRelationship(
+			req,
+			res,
+			await User.findOneOrFail({
+				where: { id: req.params.id },
+				relations: ["relationships", "relationships.to"],
+				select: userProjection,
+			}),
+			req.body.type ?? RelationshipType.friends,
+		);
+	},
+);
 
-router.post("/", route({ body: "RelationshipPostSchema" }), async (req: Request, res: Response) => {
-	return await updateRelationship(
-		req,
-		res,
-		await User.findOneOrFail({
-			relations: ["relationships", "relationships.to"],
-			select: userProjection,
-			where: {
-				discriminator: String(req.body.discriminator).padStart(4, "0"), //Discord send the discriminator as integer, we need to add leading zeroes
-				username: req.body.username
-			}
-		}),
-		req.body.type
-	);
-});
+router.post(
+	"/",
+	route({ body: "RelationshipPostSchema" }),
+	async (req: Request, res: Response) => {
+		return await updateRelationship(
+			req,
+			res,
+			await User.findOneOrFail({
+				relations: ["relationships", "relationships.to"],
+				select: userProjection,
+				where: {
+					discriminator: String(req.body.discriminator).padStart(
+						4,
+						"0",
+					), //Discord send the discriminator as integer, we need to add leading zeroes
+					username: req.body.username,
+				},
+			}),
+			req.body.type,
+		);
+	},
+);
 
 router.delete("/:id", route({}), async (req: Request, res: Response) => {
 	const { id } = req.params;
-	if (id === req.user_id) throw new HTTPError("You can't remove yourself as a friend");
+	if (id === req.user_id)
+		throw new HTTPError("You can't remove yourself as a friend");
 
-	const user = await User.findOneOrFail({ where: { id: req.user_id }, select: userProjection, relations: ["relationships"] });
-	const friend = await User.findOneOrFail({ where: { id: id }, select: userProjection, relations: ["relationships"] });
+	const user = await User.findOneOrFail({
+		where: { id: req.user_id },
+		select: userProjection,
+		relations: ["relationships"],
+	});
+	const friend = await User.findOneOrFail({
+		where: { id: id },
+		select: userProjection,
+		relations: ["relationships"],
+	});
 
 	const relationship = user.relationships.find((x) => x.to_id === id);
-	const friendRequest = friend.relationships.find((x) => x.to_id === req.user_id);
+	const friendRequest = friend.relationships.find(
+		(x) => x.to_id === req.user_id,
+	);
 
-	if (!relationship) throw new HTTPError("You are not friends with the user", 404);
+	if (!relationship)
+		throw new HTTPError("You are not friends with the user", 404);
 	if (relationship?.type === RelationshipType.blocked) {
 		// unblock user
 
@@ -81,8 +111,8 @@ router.delete("/:id", route({}), async (req: Request, res: Response) => {
 			emitEvent({
 				event: "RELATIONSHIP_REMOVE",
 				user_id: req.user_id,
-				data: relationship.toPublicRelationship()
-			} as RelationshipRemoveEvent)
+				data: relationship.toPublicRelationship(),
+			} as RelationshipRemoveEvent),
 		]);
 		return res.sendStatus(204);
 	}
@@ -92,8 +122,8 @@ router.delete("/:id", route({}), async (req: Request, res: Response) => {
 			await emitEvent({
 				event: "RELATIONSHIP_REMOVE",
 				data: friendRequest.toPublicRelationship(),
-				user_id: id
-			} as RelationshipRemoveEvent)
+				user_id: id,
+			} as RelationshipRemoveEvent),
 		]);
 	}
 
@@ -102,8 +132,8 @@ router.delete("/:id", route({}), async (req: Request, res: Response) => {
 		emitEvent({
 			event: "RELATIONSHIP_REMOVE",
 			data: relationship.toPublicRelationship(),
-			user_id: req.user_id
-		} as RelationshipRemoveEvent)
+			user_id: req.user_id,
+		} as RelationshipRemoveEvent),
 	]);
 
 	return res.sendStatus(204);
@@ -111,26 +141,40 @@ router.delete("/:id", route({}), async (req: Request, res: Response) => {
 
 export default router;
 
-async function updateRelationship(req: Request, res: Response, friend: User, type: RelationshipType) {
+async function updateRelationship(
+	req: Request,
+	res: Response,
+	friend: User,
+	type: RelationshipType,
+) {
 	const id = friend.id;
-	if (id === req.user_id) throw new HTTPError("You can't add yourself as a friend");
+	if (id === req.user_id)
+		throw new HTTPError("You can't add yourself as a friend");
 
 	const user = await User.findOneOrFail({
 		where: { id: req.user_id },
-		relations: ["relationships", "relationships.to"], select: userProjection
+		relations: ["relationships", "relationships.to"],
+		select: userProjection,
 	});
 
 	var relationship = user.relationships.find((x) => x.to_id === id);
-	const friendRequest = friend.relationships.find((x) => x.to_id === req.user_id);
+	const friendRequest = friend.relationships.find(
+		(x) => x.to_id === req.user_id,
+	);
 
 	// TODO: you can add infinitely many blocked users (should this be prevented?)
 	if (type === RelationshipType.blocked) {
 		if (relationship) {
-			if (relationship.type === RelationshipType.blocked) throw new HTTPError("You already blocked the user");
+			if (relationship.type === RelationshipType.blocked)
+				throw new HTTPError("You already blocked the user");
 			relationship.type = RelationshipType.blocked;
 			await relationship.save();
 		} else {
-			relationship = await Relationship.create({ to_id: id, type: RelationshipType.blocked, from_id: req.user_id }).save();
+			relationship = await Relationship.create({
+				to_id: id,
+				type: RelationshipType.blocked,
+				from_id: req.user_id,
+			}).save();
 		}
 
 		if (friendRequest && friendRequest.type !== RelationshipType.blocked) {
@@ -139,43 +183,56 @@ async function updateRelationship(req: Request, res: Response, friend: User, typ
 				emitEvent({
 					event: "RELATIONSHIP_REMOVE",
 					data: friendRequest.toPublicRelationship(),
-					user_id: id
-				} as RelationshipRemoveEvent)
+					user_id: id,
+				} as RelationshipRemoveEvent),
 			]);
 		}
 
 		await emitEvent({
 			event: "RELATIONSHIP_ADD",
 			data: relationship.toPublicRelationship(),
-			user_id: req.user_id
+			user_id: req.user_id,
 		} as RelationshipAddEvent);
 
 		return res.sendStatus(204);
 	}
 
 	const { maxFriends } = Config.get().limits.user;
-	if (user.relationships.length >= maxFriends) throw DiscordApiErrors.MAXIMUM_FRIENDS.withParams(maxFriends);
+	if (user.relationships.length >= maxFriends)
+		throw DiscordApiErrors.MAXIMUM_FRIENDS.withParams(maxFriends);
 
-	var incoming_relationship = Relationship.create({ nickname: undefined, type: RelationshipType.incoming, to: user, from: friend });
+	var incoming_relationship = Relationship.create({
+		nickname: undefined,
+		type: RelationshipType.incoming,
+		to: user,
+		from: friend,
+	});
 	var outgoing_relationship = Relationship.create({
 		nickname: undefined,
 		type: RelationshipType.outgoing,
 		to: friend,
-		from: user
+		from: user,
 	});
 
 	if (friendRequest) {
-		if (friendRequest.type === RelationshipType.blocked) throw new HTTPError("The user blocked you");
-		if (friendRequest.type === RelationshipType.friends) throw new HTTPError("You are already friends with the user");
+		if (friendRequest.type === RelationshipType.blocked)
+			throw new HTTPError("The user blocked you");
+		if (friendRequest.type === RelationshipType.friends)
+			throw new HTTPError("You are already friends with the user");
 		// accept friend request
 		incoming_relationship = friendRequest;
 		incoming_relationship.type = RelationshipType.friends;
 	}
 
 	if (relationship) {
-		if (relationship.type === RelationshipType.outgoing) throw new HTTPError("You already sent a friend request");
-		if (relationship.type === RelationshipType.blocked) throw new HTTPError("Unblock the user before sending a friend request");
-		if (relationship.type === RelationshipType.friends) throw new HTTPError("You are already friends with the user");
+		if (relationship.type === RelationshipType.outgoing)
+			throw new HTTPError("You already sent a friend request");
+		if (relationship.type === RelationshipType.blocked)
+			throw new HTTPError(
+				"Unblock the user before sending a friend request",
+			);
+		if (relationship.type === RelationshipType.friends)
+			throw new HTTPError("You are already friends with the user");
 		outgoing_relationship = relationship;
 		outgoing_relationship.type = RelationshipType.friends;
 	}
@@ -186,16 +243,16 @@ async function updateRelationship(req: Request, res: Response, friend: User, typ
 		emitEvent({
 			event: "RELATIONSHIP_ADD",
 			data: outgoing_relationship.toPublicRelationship(),
-			user_id: req.user_id
+			user_id: req.user_id,
 		} as RelationshipAddEvent),
 		emitEvent({
 			event: "RELATIONSHIP_ADD",
 			data: {
 				...incoming_relationship.toPublicRelationship(),
-				should_notify: true
+				should_notify: true,
 			},
-			user_id: id
-		} as RelationshipAddEvent)
+			user_id: id,
+		} as RelationshipAddEvent),
 	]);
 
 	return res.sendStatus(204);
diff --git a/src/api/routes/users/@me/settings.ts b/src/api/routes/users/@me/settings.ts
index 9060baf7..30e5969c 100644
--- a/src/api/routes/users/@me/settings.ts
+++ b/src/api/routes/users/@me/settings.ts
@@ -4,25 +4,31 @@ import { route } from "@fosscord/api";
 
 const router = Router();
 
-export interface UserSettingsSchema extends Partial<UserSettings> { }
+export interface UserSettingsSchema extends Partial<UserSettings> {}
 
 router.get("/", route({}), async (req: Request, res: Response) => {
 	const user = await User.findOneOrFail({
 		where: { id: req.user_id },
-		select: ["settings"]
+		select: ["settings"],
 	});
 	return res.json(user.settings);
 });
 
-router.patch("/", route({ body: "UserSettingsSchema" }), async (req: Request, res: Response) => {
-	const body = req.body as UserSettings;
-	if (body.locale === "en") body.locale = "en-US"; // fix discord client crash on unkown locale
+router.patch(
+	"/",
+	route({ body: "UserSettingsSchema" }),
+	async (req: Request, res: Response) => {
+		const body = req.body as UserSettings;
+		if (body.locale === "en") body.locale = "en-US"; // fix discord client crash on unkown locale
 
-	const user = await User.findOneOrFail({ where: { id: req.user_id, bot: false } });
-	user.settings = { ...user.settings, ...body };
-	await user.save();
+		const user = await User.findOneOrFail({
+			where: { id: req.user_id, bot: false },
+		});
+		user.settings = { ...user.settings, ...body };
+		await user.save();
 
-	res.json(user.settings);
-});
+		res.json(user.settings);
+	},
+);
 
 export default router;
diff --git a/src/api/start.ts b/src/api/start.ts
index ccb4d108..fa120e59 100644
--- a/src/api/start.ts
+++ b/src/api/start.ts
@@ -11,7 +11,7 @@ var cores = 1;
 try {
 	cores = Number(process.env.THREADS) || os.cpus().length;
 } catch {
-	console.log("[API] Failed to get thread count! Using 1...")
+	console.log("[API] Failed to get thread count! Using 1...");
 }
 
 if (cluster.isMaster && process.env.NODE_ENV == "production") {
diff --git a/src/api/util/handlers/Message.ts b/src/api/util/handlers/Message.ts
index 0d29c2e6..d44b368f 100644
--- a/src/api/util/handlers/Message.ts
+++ b/src/api/util/handlers/Message.ts
@@ -32,24 +32,32 @@ const allow_empty = false;
 // TODO: check webhook, application, system author, stickers
 // 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;
+const LINK_REGEX =
+	/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/g;
 
 const DEFAULT_FETCH_OPTIONS: any = {
 	redirect: "follow",
 	follow: 1,
 	headers: {
-		"user-agent": "Mozilla/5.0 (compatible; Fosscord/1.0; +https://github.com/fosscord/fosscord)"
+		"user-agent":
+			"Mozilla/5.0 (compatible; Fosscord/1.0; +https://github.com/fosscord/fosscord)",
 	},
 	// size: 1024 * 1024 * 5, 	// grabbed from config later
 	compress: true,
-	method: "GET"
+	method: "GET",
 };
 
 export async function handleMessage(opts: MessageOptions): Promise<Message> {
-	const channel = await Channel.findOneOrFail({ where: { id: opts.channel_id }, relations: ["recipients"] });
-	if (!channel || !opts.channel_id) throw new HTTPError("Channel not found", 404);
+	const channel = await Channel.findOneOrFail({
+		where: { id: opts.channel_id },
+		relations: ["recipients"],
+	});
+	if (!channel || !opts.channel_id)
+		throw new HTTPError("Channel not found", 404);
 
-	const stickers = opts.sticker_ids ? await Sticker.find({ where: { id: In(opts.sticker_ids) } }) : undefined;
+	const stickers = opts.sticker_ids
+		? await Sticker.find({ where: { id: In(opts.sticker_ids) } })
+		: undefined;
 	const message = Message.create({
 		...opts,
 		id: Snowflake.generate(),
@@ -58,11 +66,14 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> {
 		channel_id: opts.channel_id,
 		attachments: opts.attachments || [],
 		embeds: opts.embeds || [],
-		reactions: /*opts.reactions ||*/[],
+		reactions: /*opts.reactions ||*/ [],
 		type: opts.type ?? 0,
 	});
 
-	if (message.content && message.content.length > Config.get().limits.message.maxCharacters) {
+	if (
+		message.content &&
+		message.content.length > Config.get().limits.message.maxCharacters
+	) {
 		throw new HTTPError("Content length over max character limit");
 	}
 
@@ -72,13 +83,21 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> {
 		rights.hasThrow("SEND_MESSAGES");
 	}
 	if (opts.application_id) {
-		message.application = await Application.findOneOrFail({ where: { id: opts.application_id } });
+		message.application = await Application.findOneOrFail({
+			where: { id: opts.application_id },
+		});
 	}
 	if (opts.webhook_id) {
-		message.webhook = await Webhook.findOneOrFail({ where: { id: opts.webhook_id } });
+		message.webhook = await Webhook.findOneOrFail({
+			where: { id: opts.webhook_id },
+		});
 	}
 
-	const permission = await getPermission(opts.author_id, channel.guild_id, opts.channel_id);
+	const permission = await getPermission(
+		opts.author_id,
+		channel.guild_id,
+		opts.channel_id,
+	);
 	permission.hasThrow("SEND_MESSAGES");
 	if (permission.cache.member) {
 		message.member = permission.cache.member;
@@ -89,10 +108,18 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> {
 		permission.hasThrow("READ_MESSAGE_HISTORY");
 		// code below has to be redone when we add custom message routing
 		if (message.guild_id !== null) {
-			const guild = await Guild.findOneOrFail({ where: { id: channel.guild_id } });
+			const guild = await Guild.findOneOrFail({
+				where: { id: channel.guild_id },
+			});
 			if (!guild.features.includes("CROSS_CHANNEL_REPLIES")) {
-				if (opts.message_reference.guild_id !== channel.guild_id) throw new HTTPError("You can only reference messages from this guild");
-				if (opts.message_reference.channel_id !== opts.channel_id) throw new HTTPError("You can only reference messages from this channel");
+				if (opts.message_reference.guild_id !== channel.guild_id)
+					throw new HTTPError(
+						"You can only reference messages from this guild",
+					);
+				if (opts.message_reference.channel_id !== opts.channel_id)
+					throw new HTTPError(
+						"You can only reference messages from this channel",
+					);
 			}
 		}
 		/** Q: should be checked if the referenced message exists? ANSWER: NO
@@ -102,7 +129,13 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> {
 	}
 
 	// TODO: stickers/activity
-	if (!allow_empty && (!opts.content && !opts.embeds?.length && !opts.attachments?.length && !opts.sticker_ids?.length)) {
+	if (
+		!allow_empty &&
+		!opts.content &&
+		!opts.embeds?.length &&
+		!opts.attachments?.length &&
+		!opts.sticker_ids?.length
+	) {
 		throw new HTTPError("Empty messages are not allowed", 50006);
 	}
 
@@ -112,31 +145,42 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> {
 	var mention_user_ids = [] as string[];
 	var mention_everyone = false;
 
-	if (content) { // TODO: explicit-only mentions
+	if (content) {
+		// TODO: explicit-only mentions
 		message.content = content.trim();
 		for (const [_, mention] of content.matchAll(CHANNEL_MENTION)) {
-			if (!mention_channel_ids.includes(mention)) mention_channel_ids.push(mention);
+			if (!mention_channel_ids.includes(mention))
+				mention_channel_ids.push(mention);
 		}
 
 		for (const [_, mention] of content.matchAll(USER_MENTION)) {
-			if (!mention_user_ids.includes(mention)) mention_user_ids.push(mention);
+			if (!mention_user_ids.includes(mention))
+				mention_user_ids.push(mention);
 		}
 
 		await Promise.all(
-			Array.from(content.matchAll(ROLE_MENTION)).map(async ([_, mention]) => {
-				const role = await Role.findOneOrFail({ where: { id: mention, guild_id: channel.guild_id } });
-				if (role.mentionable || permission.has("MANAGE_ROLES")) {
-					mention_role_ids.push(mention);
-				}
-			})
+			Array.from(content.matchAll(ROLE_MENTION)).map(
+				async ([_, mention]) => {
+					const role = await Role.findOneOrFail({
+						where: { id: mention, guild_id: channel.guild_id },
+					});
+					if (role.mentionable || permission.has("MANAGE_ROLES")) {
+						mention_role_ids.push(mention);
+					}
+				},
+			),
 		);
 
 		if (permission.has("MENTION_EVERYONE")) {
-			mention_everyone = !!content.match(EVERYONE_MENTION) || !!content.match(HERE_MENTION);
+			mention_everyone =
+				!!content.match(EVERYONE_MENTION) ||
+				!!content.match(HERE_MENTION);
 		}
 	}
 
-	message.mention_channels = mention_channel_ids.map((x) => Channel.create({ id: x }));
+	message.mention_channels = mention_channel_ids.map((x) =>
+		Channel.create({ id: x }),
+	);
 	message.mention_roles = mention_role_ids.map((x) => Role.create({ id: x }));
 	message.mentions = mention_user_ids.map((x) => User.create({ id: x }));
 	message.mention_everyone = mention_everyone;
@@ -156,7 +200,8 @@ export async function postHandleMessage(message: Message) {
 
 	links = links.slice(0, 20) as RegExpMatchArray; // embed max 20 links — TODO: make this configurable with instance policies
 
-	const { endpointPublic, resizeWidthMax, resizeHeightMax } = Config.get().cdn;
+	const { endpointPublic, resizeWidthMax, resizeHeightMax } =
+		Config.get().cdn;
 
 	for (const link of links) {
 		try {
@@ -176,45 +221,64 @@ export async function postHandleMessage(message: Message) {
 					},
 					image: {
 						// can't be bothered rn
-						proxy_url: `${endpointPublic}/external/resize/${encodeURIComponent(link)}?width=500&height=400`,
+						proxy_url: `${endpointPublic}/external/resize/${encodeURIComponent(
+							link,
+						)}?width=500&height=400`,
 						url: link,
 						width: 500,
-						height: 400
-					}
+						height: 400,
+					},
 				};
 				data.embeds.push(embed);
-			}
-			else {
+			} else {
 				const text = await request.text();
 				const $ = cheerio.load(text);
 
 				const title = $('meta[property="og:title"]').attr("content");
 				const provider_name = $('meta[property="og:site_name"]').text();
-				const author_name = $('meta[property="article:author"]').attr("content");
-				const description = $('meta[property="og:description"]').attr("content") || $('meta[property="description"]').attr("content");
+				const author_name = $('meta[property="article:author"]').attr(
+					"content",
+				);
+				const description =
+					$('meta[property="og:description"]').attr("content") ||
+					$('meta[property="description"]').attr("content");
 
 				const image = $('meta[property="og:image"]').attr("content");
-				const width = parseInt($('meta[property="og:image:width"]').attr("content") || "") || undefined;
-				const height = parseInt($('meta[property="og:image:height"]').attr("content") || "") || undefined;
+				const width =
+					parseInt(
+						$('meta[property="og:image:width"]').attr("content") ||
+							"",
+					) || undefined;
+				const height =
+					parseInt(
+						$('meta[property="og:image:height"]').attr("content") ||
+							"",
+					) || undefined;
 
 				const url = $('meta[property="og:url"]').attr("content");
 				// TODO: color
 				embed = {
 					provider: {
 						url: link,
-						name: provider_name
-					}
+						name: provider_name,
+					},
 				};
 
 				const resizeWidth = Math.min(resizeWidthMax ?? 1, width ?? 100);
-				const resizeHeight = Math.min(resizeHeightMax ?? 1, height ?? 100);
+				const resizeHeight = Math.min(
+					resizeHeightMax ?? 1,
+					height ?? 100,
+				);
 				if (author_name) embed.author = { name: author_name };
-				if (image) embed.thumbnail = {
-					proxy_url: `${endpointPublic}/external/resize/${encodeURIComponent(image)}?width=${resizeWidth}&height=${resizeHeight}`,
-					url: image,
-					width: width,
-					height: height
-				};
+				if (image)
+					embed.thumbnail = {
+						proxy_url: `${endpointPublic}/external/resize/${encodeURIComponent(
+							image,
+						)}?width=${resizeWidth}&height=${resizeHeight}`,
+						url: image,
+						width: width,
+						height: height,
+					};
 				if (title) embed.title = title;
 				if (url) embed.url = url;
 				if (description) embed.description = description;
@@ -227,18 +291,25 @@ export async function postHandleMessage(message: Message) {
 
 				// very bad code below
 				// don't care lol
-				if (embed?.thumbnail?.url && approvedProviders.indexOf(new URL(embed.thumbnail.url).hostname) !== -1) {
+				if (
+					embed?.thumbnail?.url &&
+					approvedProviders.indexOf(
+						new URL(embed.thumbnail.url).hostname,
+					) !== -1
+				) {
 					embed = {
 						provider: {
 							url: link,
 							name: new URL(link).hostname,
 						},
 						image: {
-							proxy_url: `${endpointPublic}/external/resize/${encodeURIComponent(image!)}?width=${resizeWidth}&height=${resizeHeight}`,
+							proxy_url: `${endpointPublic}/external/resize/${encodeURIComponent(
+								image!,
+							)}?width=${resizeWidth}&height=${resizeHeight}`,
 							url: image,
 							width: width,
-							height: height
-						}
+							height: height,
+						},
 					};
 				}
 
@@ -246,16 +317,19 @@ export async function postHandleMessage(message: Message) {
 					data.embeds.push(embed);
 				}
 			}
-		} catch (error) { }
+		} catch (error) {}
 	}
 
 	await Promise.all([
 		emitEvent({
 			event: "MESSAGE_UPDATE",
 			channel_id: message.channel_id,
-			data
+			data,
 		} as MessageUpdateEvent),
-		Message.update({ id: message.id, channel_id: message.channel_id }, { embeds: data.embeds })
+		Message.update(
+			{ id: message.id, channel_id: message.channel_id },
+			{ embeds: data.embeds },
+		),
 	]);
 }
 
@@ -264,10 +338,14 @@ export async function sendMessage(opts: MessageOptions) {
 
 	await Promise.all([
 		Message.insert(message),
-		emitEvent({ event: "MESSAGE_CREATE", channel_id: opts.channel_id, data: message.toJSON() } as MessageCreateEvent)
+		emitEvent({
+			event: "MESSAGE_CREATE",
+			channel_id: opts.channel_id,
+			data: message.toJSON(),
+		} as MessageCreateEvent),
 	]);
 
-	postHandleMessage(message).catch((e) => { }); // no await as it should catch error non-blockingly
+	postHandleMessage(message).catch((e) => {}); // no await as it should catch error non-blockingly
 
 	return message;
 }
diff --git a/src/api/util/handlers/Voice.ts b/src/api/util/handlers/Voice.ts
index 4d60eb91..88e266a1 100644
--- a/src/api/util/handlers/Voice.ts
+++ b/src/api/util/handlers/Voice.ts
@@ -3,7 +3,9 @@ import { distanceBetweenLocations, IPAnalysis } from "../utility/ipAddress";
 
 export async function getVoiceRegions(ipAddress: string, vip: boolean) {
 	const regions = Config.get().regions;
-	const availableRegions = regions.available.filter((ar) => (vip ? true : !ar.vip));
+	const availableRegions = regions.available.filter((ar) =>
+		vip ? true : !ar.vip,
+	);
 	let optimalId = regions.default;
 
 	if (!regions.useDefaultAsOptimal) {
@@ -13,7 +15,10 @@ export async function getVoiceRegions(ipAddress: string, vip: boolean) {
 
 		for (let 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, ar.location || (await IPAnalysis(ar.endpoint)));
+			const dist = distanceBetweenLocations(
+				clientIpAnalysis,
+				ar.location || (await IPAnalysis(ar.endpoint)),
+			);
 
 			if (dist < min) {
 				min = dist;
@@ -27,6 +32,6 @@ export async function getVoiceRegions(ipAddress: string, vip: boolean) {
 		name: ar.name,
 		custom: ar.custom,
 		deprecated: ar.deprecated,
-		optimal: ar.id === optimalId
+		optimal: ar.id === optimalId,
 	}));
 }
diff --git a/src/api/util/handlers/route.ts b/src/api/util/handlers/route.ts
index c245b411..5dcae953 100644
--- a/src/api/util/handlers/route.ts
+++ b/src/api/util/handlers/route.ts
@@ -10,7 +10,7 @@ import {
 	PermissionResolvable,
 	Permissions,
 	RightResolvable,
-	Rights
+	Rights,
 } from "@fosscord/util";
 import { NextFunction, Request, Response } from "express";
 import { AnyValidateFunction } from "ajv/dist/core";
@@ -23,7 +23,11 @@ declare global {
 	}
 }
 
-export type RouteResponse = { status?: number; body?: `${string}Response`; headers?: Record<string, string> };
+export type RouteResponse = {
+	status?: number;
+	body?: `${string}Response`;
+	headers?: Record<string, string>;
+};
 
 export interface RouteOptions {
 	permission?: PermissionResolvable;
@@ -48,11 +52,17 @@ export function route(opts: RouteOptions) {
 	return async (req: Request, res: Response, next: NextFunction) => {
 		if (opts.permission) {
 			const required = new Permissions(opts.permission);
-			req.permission = await getPermission(req.user_id, req.params.guild_id, req.params.channel_id);
+			req.permission = await getPermission(
+				req.user_id,
+				req.params.guild_id,
+				req.params.channel_id,
+			);
 
 			// bitfield comparison: check if user lacks certain permission
 			if (!req.permission.has(required)) {
-				throw DiscordApiErrors.MISSING_PERMISSIONS.withParams(opts.permission as string);
+				throw DiscordApiErrors.MISSING_PERMISSIONS.withParams(
+					opts.permission as string,
+				);
 			}
 		}
 
@@ -61,15 +71,26 @@ export function route(opts: RouteOptions) {
 			req.rights = await getRights(req.user_id);
 
 			if (!req.rights || !req.rights.has(required)) {
-				throw FosscordApiErrors.MISSING_RIGHTS.withParams(opts.right as string);
+				throw FosscordApiErrors.MISSING_RIGHTS.withParams(
+					opts.right as string,
+				);
 			}
 		}
 
 		if (validate) {
 			const valid = validate(normalizeBody(req.body));
 			if (!valid) {
-				const fields: Record<string, { code?: string; message: string }> = {};
-				validate.errors?.forEach((x) => (fields[x.instancePath.slice(1)] = { code: x.keyword, message: x.message || "" }));
+				const fields: Record<
+					string,
+					{ code?: string; message: string }
+				> = {};
+				validate.errors?.forEach(
+					(x) =>
+						(fields[x.instancePath.slice(1)] = {
+							code: x.keyword,
+							message: x.message || "",
+						}),
+				);
 				throw FieldErrors(fields);
 			}
 		}
diff --git a/src/api/util/index.ts b/src/api/util/index.ts
index de6b6064..9f375f72 100644
--- a/src/api/util/index.ts
+++ b/src/api/util/index.ts
@@ -6,4 +6,4 @@ export * from "./utility/RandomInviteID";
 export * from "./handlers/route";
 export * from "./utility/String";
 export * from "./handlers/Voice";
-export * from "./utility/captcha";
\ No newline at end of file
+export * from "./utility/captcha";
diff --git a/src/api/util/utility/Base64.ts b/src/api/util/utility/Base64.ts
index 46cff77a..c10176f2 100644
--- a/src/api/util/utility/Base64.ts
+++ b/src/api/util/utility/Base64.ts
@@ -1,4 +1,5 @@
-const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+";
+const alphabet =
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+";
 
 // binary to string lookup table
 const b2s = alphabet.split("");
diff --git a/src/api/util/utility/RandomInviteID.ts b/src/api/util/utility/RandomInviteID.ts
index 7ea344e0..bfed65bb 100644
--- a/src/api/util/utility/RandomInviteID.ts
+++ b/src/api/util/utility/RandomInviteID.ts
@@ -2,7 +2,8 @@ import { Snowflake } from "@fosscord/util";
 
 export function random(length = 6) {
 	// Declare all characters
-	let chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+	let chars =
+		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
 
 	// Pick characers randomly
 	let str = "";
@@ -15,18 +16,18 @@ export function random(length = 6) {
 
 export function snowflakeBasedInvite() {
 	// Declare all characters
-	let chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+	let chars =
+		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
 	let 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 = "";
-	for (let i=0; i < 10; i++) {
-		
+	for (let i = 0; i < 10; i++) {
 		str.concat(chars.charAt(Number(snowflake % base)));
 		snowflake = snowflake / base;
 	}
-	
-	return str.substr(3,8).split("").reverse().join("");
+
+	return str.substr(3, 8).split("").reverse().join("");
 }
diff --git a/src/api/util/utility/String.ts b/src/api/util/utility/String.ts
index 982b7e11..0913013e 100644
--- a/src/api/util/utility/String.ts
+++ b/src/api/util/utility/String.ts
@@ -2,13 +2,21 @@ import { Request } from "express";
 import { ntob } from "./Base64";
 import { FieldErrors } from "@fosscord/util";
 
-export function checkLength(str: string, min: number, max: number, key: string, req: Request) {
+export function checkLength(
+	str: string,
+	min: number,
+	max: number,
+	key: string,
+	req: Request,
+) {
 	if (str.length < min || str.length > max) {
 		throw FieldErrors({
 			[key]: {
 				code: "BASE_TYPE_BAD_LENGTH",
-				message: req.t("common:field.BASE_TYPE_BAD_LENGTH", { length: `${min} - ${max}` })
-			}
+				message: req.t("common:field.BASE_TYPE_BAD_LENGTH", {
+					length: `${min} - ${max}`,
+				}),
+			},
 		});
 	}
 }
diff --git a/src/api/util/utility/captcha.ts b/src/api/util/utility/captcha.ts
index 739647d2..50e2c91a 100644
--- a/src/api/util/utility/captcha.ts
+++ b/src/api/util/utility/captcha.ts
@@ -7,8 +7,8 @@ export interface hcaptchaResponse {
 	hostname: string;
 	credit: boolean;
 	"error-codes": string[];
-	score: number;	// enterprise only
-	score_reason: string[];	// enterprise only
+	score: number; // enterprise only
+	score_reason: string[]; // enterprise only
 }
 
 export interface recaptchaResponse {
@@ -23,7 +23,7 @@ export interface recaptchaResponse {
 const verifyEndpoints = {
 	hcaptcha: "https://hcaptcha.com/siteverify",
 	recaptcha: "https://www.google.com/recaptcha/api/siteverify",
-}
+};
 
 export async function verifyCaptcha(response: string, ip?: string) {
 	const { security } = Config.get();
@@ -36,11 +36,12 @@ export async function verifyCaptcha(response: string, ip?: string) {
 		headers: {
 			"Content-Type": "application/x-www-form-urlencoded",
 		},
-		body: `response=${encodeURIComponent(response)}`
-			+ `&secret=${encodeURIComponent(secret!)}`
-			+ `&sitekey=${encodeURIComponent(sitekey!)}`
-			+ (ip ? `&remoteip=${encodeURIComponent(ip!)}` : ""),
+		body:
+			`response=${encodeURIComponent(response)}` +
+			`&secret=${encodeURIComponent(secret!)}` +
+			`&sitekey=${encodeURIComponent(sitekey!)}` +
+			(ip ? `&remoteip=${encodeURIComponent(ip!)}` : ""),
 	});
 
-	return await res.json() as hcaptchaResponse | recaptchaResponse;
-}
\ No newline at end of file
+	return (await res.json()) as hcaptchaResponse | recaptchaResponse;
+}
diff --git a/src/api/util/utility/ipAddress.ts b/src/api/util/utility/ipAddress.ts
index f17b145e..d166ebc5 100644
--- a/src/api/util/utility/ipAddress.ts
+++ b/src/api/util/utility/ipAddress.ts
@@ -25,27 +25,27 @@ const exampleData = {
 		name: "",
 		domain: "",
 		route: "",
-		type: "isp"
+		type: "isp",
 	},
 	languages: [
 		{
 			name: "",
-			native: ""
-		}
+			native: "",
+		},
 	],
 	currency: {
 		name: "",
 		code: "",
 		symbol: "",
 		native: "",
-		plural: ""
+		plural: "",
 	},
 	time_zone: {
 		name: "",
 		abbr: "",
 		offset: "",
 		is_dst: true,
-		current_time: ""
+		current_time: "",
 	},
 	threat: {
 		is_tor: false,
@@ -54,10 +54,10 @@ const exampleData = {
 		is_known_attacker: false,
 		is_known_abuser: false,
 		is_threat: false,
-		is_bogon: false
+		is_bogon: false,
 	},
 	count: 0,
-	status: 200
+	status: 200,
 };
 
 //TODO add function that support both ip and domain names
@@ -65,7 +65,9 @@ export async function IPAnalysis(ip: string): Promise<typeof exampleData> {
 	const { ipdataApiKey } = Config.get().security;
 	if (!ipdataApiKey) return { ...exampleData, ip };
 
-	return (await fetch(`https://api.ipdata.co/${ip}?api-key=${ipdataApiKey}`)).json() as any; // TODO: types
+	return (
+		await fetch(`https://api.ipdata.co/${ip}?api-key=${ipdataApiKey}`)
+	).json() as any; // TODO: types
 }
 
 export function isProxy(data: typeof exampleData) {
@@ -77,19 +79,35 @@ export function isProxy(data: typeof exampleData) {
 }
 
 export function getIpAdress(req: Request): string {
-	// @ts-ignore
-	return req.headers[Config.get().security.forwadedFor] || req.socket.remoteAddress;
+	return (
+		// @ts-ignore
+		req.headers[Config.get().security.forwadedFor] ||
+		req.socket.remoteAddress
+	);
 }
 
 export function distanceBetweenLocations(loc1: any, loc2: any): number {
-	return distanceBetweenCoords(loc1.latitude, loc1.longitude, loc2.latitude, loc2.longitude);
+	return distanceBetweenCoords(
+		loc1.latitude,
+		loc1.longitude,
+		loc2.latitude,
+		loc2.longitude,
+	);
 }
 
 //Haversine function
-function distanceBetweenCoords(lat1: number, lon1: number, lat2: number, lon2: number) {
+function distanceBetweenCoords(
+	lat1: number,
+	lon1: number,
+	lat2: number,
+	lon2: number,
+) {
 	const p = 0.017453292519943295; // Math.PI / 180
 	const c = Math.cos;
-	const a = 0.5 - c((lat2 - lat1) * p) / 2 + (c(lat1 * p) * c(lat2 * p) * (1 - c((lon2 - lon1) * p))) / 2;
+	const a =
+		0.5 -
+		c((lat2 - lat1) * p) / 2 +
+		(c(lat1 * p) * c(lat2 * p) * (1 - c((lon2 - lon1) * p))) / 2;
 
 	return 12742 * Math.asin(Math.sqrt(a)); // 2 * R; R = 6371 km
 }
diff --git a/src/api/util/utility/passwordStrength.ts b/src/api/util/utility/passwordStrength.ts
index 439700d0..35c55999 100644
--- a/src/api/util/utility/passwordStrength.ts
+++ b/src/api/util/utility/passwordStrength.ts
@@ -18,7 +18,8 @@ const blocklist: string[] = []; // TODO: update ones passwordblocklist is stored
  * Returns: 0 > pw > 1
  */
 export function checkPassword(password: string): number {
-	const { minLength, minNumbers, minUpperCase, minSymbols } = Config.get().register.password;
+	const { minLength, minNumbers, minUpperCase, minSymbols } =
+		Config.get().register.password;
 	var strength = 0;
 
 	// checks for total password len
@@ -42,19 +43,24 @@ export function checkPassword(password: string): number {
 	}
 
 	// checks if password only consists of numbers or only consists of chars
-	if (password.length == password.count(reNUMBER) || password.length === password.count(reUPPERCASELETTER)) {
+	if (
+		password.length == password.count(reNUMBER) ||
+		password.length === password.count(reUPPERCASELETTER)
+	) {
 		strength = 0;
 	}
-	
+
 	let 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);
-	
-	entropies.map(x => (x / entropyMap.length));
-	strength += entropies.reduceRight((a: number, x: number) => a - (x * Math.log2(x))) / Math.log2(password.length);	
+
+	entropies.map((x) => x / entropyMap.length);
+	strength +=
+		entropies.reduceRight((a: number, x: number) => a - x * Math.log2(x)) /
+		Math.log2(password.length);
 	return strength;
 }
diff --git a/src/bundle/Server.ts b/src/bundle/Server.ts
index c85daf40..dd75e777 100644
--- a/src/bundle/Server.ts
+++ b/src/bundle/Server.ts
@@ -22,7 +22,7 @@ const cdn = new CDNServer({ server, port, production, app });
 const gateway = new Gateway.Server({ server, port, production });
 
 //this is what has been added for the /stop API route
-process.on('SIGTERM', () => {
+process.on("SIGTERM", () => {
 	server.close(() => {
 		console.log("Stop API has been successfully POSTed, SIGTERM sent");
 	});
@@ -66,7 +66,9 @@ async function main() {
 	//Sentry
 	if (Config.get().sentry.enabled) {
 		console.log(
-			`[Bundle] ${yellow("You are using Sentry! This may slightly impact performance on large loads!")}`
+			`[Bundle] ${yellow(
+				"You are using Sentry! This may slightly impact performance on large loads!",
+			)}`,
 		);
 		Sentry.init({
 			dsn: Config.get().sentry.endpoint,
@@ -81,7 +83,10 @@ async function main() {
 
 		Sentry.addGlobalEventProcessor((event, hint) => {
 			if (event.transaction) {
-				event.transaction = event.transaction.split("/").map(x => !parseInt(x) ? x : ":id").join("/");
+				event.transaction = event.transaction
+					.split("/")
+					.map((x) => (!parseInt(x) ? x : ":id"))
+					.join("/");
 			}
 
 			delete event.request?.cookies;
@@ -93,14 +98,20 @@ async function main() {
 			}
 
 			if (event.breadcrumbs) {
-				event.breadcrumbs = event.breadcrumbs.filter(x => {
+				event.breadcrumbs = event.breadcrumbs.filter((x) => {
 					if (x.message?.includes("identified as")) return false;
 					if (x.message?.includes("[WebSocket] closed")) return false;
-					if (x.message?.includes("Got Resume -> cancel not implemented")) return false;
-					if (x.message?.includes("[Gateway] New connection from")) return false;
+					if (
+						x.message?.includes(
+							"Got Resume -> cancel not implemented",
+						)
+					)
+						return false;
+					if (x.message?.includes("[Gateway] New connection from"))
+						return false;
 
 					return true;
-				})
+				});
 			}
 
 			return event;
diff --git a/src/bundle/index.ts b/src/bundle/index.ts
index 960d4dc0..45f084c5 100644
--- a/src/bundle/index.ts
+++ b/src/bundle/index.ts
@@ -1,4 +1,4 @@
 export * from "@fosscord/api";
 export * from "@fosscord/util";
 export * from "@fosscord/gateway";
-export * from "@fosscord/cdn";
\ No newline at end of file
+export * from "@fosscord/cdn";
diff --git a/src/bundle/start.ts b/src/bundle/start.ts
index 2a1e6520..0c85b58d 100644
--- a/src/bundle/start.ts
+++ b/src/bundle/start.ts
@@ -1,5 +1,5 @@
 // process.env.MONGOMS_DEBUG = "true";
-require('module-alias/register');
+require("module-alias/register");
 import "reflect-metadata";
 import cluster, { Worker } from "cluster";
 import os from "os";
@@ -37,18 +37,20 @@ if (cluster.isMaster) {
 ╚═╝      ╚═════╝ ╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝  ╚═╝╚═════╝
 
 		fosscord-server | ${yellow(
-			`Pre-release (${commit !== null
-				? commit.slice(0, 7)
-				: "Unknown (Git cannot be found)"
-			})`
+			`Pre-release (${
+				commit !== null
+					? commit.slice(0, 7)
+					: "Unknown (Git cannot be found)"
+			})`,
 		)}
 
-Commit Hash: ${commit !== null
+Commit Hash: ${
+			commit !== null
 				? `${cyan(commit)} (${yellow(commit.slice(0, 7))})`
 				: "Unknown (Git cannot be found)"
-			}
+		}
 Cores: ${cyan(os.cpus().length)} (Using ${cores} thread(s).)
-`)
+`),
 	);
 
 	if (commit == null) {
@@ -85,8 +87,8 @@ Cores: ${cyan(os.cpus().length)} (Using ${cores} thread(s).)
 		cluster.on("exit", (worker: any, code: any, signal: any) => {
 			console.log(
 				`[Worker] ${red(
-					`died with PID: ${worker.process.pid} , restarting ...`
-				)}`
+					`died with PID: ${worker.process.pid} , restarting ...`,
+				)}`,
 			);
 			cluster.fork();
 		});
diff --git a/src/bundle/stats.ts b/src/bundle/stats.ts
index 0234e0b4..3a9b2d85 100644
--- a/src/bundle/stats.ts
+++ b/src/bundle/stats.ts
@@ -6,18 +6,17 @@ export function initStats() {
 	console.log(`[Path] running in ${__dirname}`);
 	try {
 		console.log(`[CPU] ${osu.cpu.model()} Cores x${osu.cpu.count()}`);
+	} catch {
+		console.log("[CPU] Failed to get cpu model!");
 	}
-	catch {
-		console.log('[CPU] Failed to get cpu model!')
-	}
-	
+
 	console.log(`[System] ${os.platform()} ${os.arch()}`);
 	console.log(`[Process] running with PID: ${process.pid}`);
 	if (process.getuid && process.getuid() === 0) {
 		console.warn(
 			red(
-				`[Process] Warning fosscord is running as root, this highly discouraged and might expose your system vulnerable to attackers. Please run fosscord as a user without root privileges.`
-			)
+				`[Process] Warning fosscord is running as root, this highly discouraged and might expose your system vulnerable to attackers. Please run fosscord as a user without root privileges.`,
+			),
 		);
 	}
 
diff --git a/src/cdn/Server.ts b/src/cdn/Server.ts
index 5b395589..f7e6dbdc 100644
--- a/src/cdn/Server.ts
+++ b/src/cdn/Server.ts
@@ -5,7 +5,7 @@ import avatarsRoute from "./routes/avatars";
 import iconsRoute from "./routes/role-icons";
 import bodyParser from "body-parser";
 
-export interface CDNServerOptions extends ServerOptions { }
+export interface CDNServerOptions extends ServerOptions {}
 
 export class CDNServer extends Server {
 	public declare options: CDNServerOptions;
@@ -22,15 +22,15 @@ export class CDNServer extends Server {
 			// TODO: use better CSP policy
 			res.set(
 				"Content-security-policy",
-				"default-src *  data: blob: filesystem: about: ws: wss: 'unsafe-inline' 'unsafe-eval'; script-src * data: blob: 'unsafe-inline' 'unsafe-eval'; connect-src * data: blob: 'unsafe-inline'; img-src * data: blob: 'unsafe-inline'; frame-src * data: blob: ; style-src * data: blob: 'unsafe-inline'; font-src * data: blob: 'unsafe-inline';"
+				"default-src *  data: blob: filesystem: about: ws: wss: 'unsafe-inline' 'unsafe-eval'; script-src * data: blob: 'unsafe-inline' 'unsafe-eval'; connect-src * data: blob: 'unsafe-inline'; img-src * data: blob: 'unsafe-inline'; frame-src * data: blob: ; style-src * data: blob: 'unsafe-inline'; font-src * data: blob: 'unsafe-inline';",
 			);
 			res.set(
 				"Access-Control-Allow-Headers",
-				req.header("Access-Control-Request-Headers") || "*"
+				req.header("Access-Control-Request-Headers") || "*",
 			);
 			res.set(
 				"Access-Control-Allow-Methods",
-				req.header("Access-Control-Request-Methods") || "*"
+				req.header("Access-Control-Request-Methods") || "*",
 			);
 			next();
 		});
diff --git a/src/cdn/routes/attachments.ts b/src/cdn/routes/attachments.ts
index ae50bc48..2a1b6f09 100644
--- a/src/cdn/routes/attachments.ts
+++ b/src/cdn/routes/attachments.ts
@@ -56,7 +56,7 @@ router.post(
 		};
 
 		return res.json(file);
-	}
+	},
 );
 
 router.get(
@@ -65,7 +65,7 @@ router.get(
 		const { channel_id, id, filename } = req.params;
 
 		const file = await storage.get(
-			`attachments/${channel_id}/${id}/${filename}`
+			`attachments/${channel_id}/${id}/${filename}`,
 		);
 		if (!file) throw new HTTPError("File not found");
 		const type = await FileType.fromBuffer(file);
@@ -79,7 +79,7 @@ router.get(
 		res.set("Cache-Control", "public, max-age=31536000");
 
 		return res.send(file);
-	}
+	},
 );
 
 router.delete(
@@ -94,7 +94,7 @@ router.delete(
 		await storage.delete(path);
 
 		return res.send({ success: true });
-	}
+	},
 );
 
 export default router;
diff --git a/src/cdn/routes/avatars.ts b/src/cdn/routes/avatars.ts
index e5e25a4c..50a76d4b 100644
--- a/src/cdn/routes/avatars.ts
+++ b/src/cdn/routes/avatars.ts
@@ -55,7 +55,7 @@ router.post(
 			size,
 			url: `${endpoint}${req.baseUrl}/${user_id}/${hash}`,
 		});
-	}
+	},
 );
 
 router.get("/:user_id", async (req: Request, res: Response) => {
@@ -86,7 +86,7 @@ export const getAvatar = async (req: Request, res: Response) => {
 	res.set("Cache-Control", "public, max-age=31536000");
 
 	return res.send(file);
-}
+};
 
 router.get("/:user_id/:hash", getAvatar);
 
diff --git a/src/cdn/routes/external.ts b/src/cdn/routes/external.ts
index cb17ff9b..405e665e 100644
--- a/src/cdn/routes/external.ts
+++ b/src/cdn/routes/external.ts
@@ -66,14 +66,14 @@ router.get("/resize/:url", async (req: Request, res: Response) => {
 	const { resizeHeightMax, resizeWidthMax } = Config.get().cdn;
 	const w = Math.min(parseInt(width as string), resizeWidthMax ?? 100);
 	const h = Math.min(parseInt(height as string), resizeHeightMax ?? 100);
-	if (w < 1 || h < 1) throw new HTTPError("Width and height must be greater than 0");
+	if (w < 1 || h < 1)
+		throw new HTTPError("Width and height must be greater than 0");
 
 	let buffer, response;
 	try {
 		response = await fetch(url, DEFAULT_FETCH_OPTIONS);
 		buffer = await response.buffer();
-	}
-	catch (e) {
+	} catch (e) {
 		throw new HTTPError("Couldn't fetch website");
 	}
 
@@ -84,7 +84,10 @@ router.get("/resize/:url", async (req: Request, res: Response) => {
 		.toBuffer();
 
 	res.setHeader("Content-Disposition", "attachment");
-	res.setHeader("Content-Type", response.headers.get("content-type") ?? "image/png");
+	res.setHeader(
+		"Content-Type",
+		response.headers.get("content-type") ?? "image/png",
+	);
 	return res.end(resizedBuffer);
 });
 
diff --git a/src/cdn/routes/guilds.ts b/src/cdn/routes/guilds.ts
index 3c4b646c..6f0719b6 100644
--- a/src/cdn/routes/guilds.ts
+++ b/src/cdn/routes/guilds.ts
@@ -7,4 +7,4 @@ const router = Router();
 router.get("/:guild_id/users/:user_id/avatars/:hash", getAvatar);
 router.get("/:guild_id/users/:user_id/banners/:hash", getAvatar);
 
-export default router;
\ No newline at end of file
+export default router;
diff --git a/src/cdn/routes/role-icons.ts b/src/cdn/routes/role-icons.ts
index 12aae8a4..bdfa0355 100644
--- a/src/cdn/routes/role-icons.ts
+++ b/src/cdn/routes/role-icons.ts
@@ -54,7 +54,7 @@ router.post(
 			size,
 			url: `${endpoint}${req.baseUrl}/${role_id}/${hash}`,
 		});
-	}
+	},
 );
 
 router.get("/:role_id", async (req: Request, res: Response) => {
diff --git a/src/cdn/start.ts b/src/cdn/start.ts
index 1fdea22e..c22984fa 100644
--- a/src/cdn/start.ts
+++ b/src/cdn/start.ts
@@ -1,4 +1,4 @@
-require('module-alias/register')
+require("module-alias/register");
 import dotenv from "dotenv";
 dotenv.config();
 
diff --git a/src/cdn/util/S3Storage.ts b/src/cdn/util/S3Storage.ts
index c4066817..33c11265 100644
--- a/src/cdn/util/S3Storage.ts
+++ b/src/cdn/util/S3Storage.ts
@@ -14,7 +14,7 @@ export class S3Storage implements Storage {
 	public constructor(
 		private client: S3,
 		private bucket: string,
-		private basePath?: string
+		private basePath?: string,
 	) {}
 
 	/**
diff --git a/src/cdn/util/Storage.ts b/src/cdn/util/Storage.ts
index d040f50b..d66cb2dc 100644
--- a/src/cdn/util/Storage.ts
+++ b/src/cdn/util/Storage.ts
@@ -33,14 +33,14 @@ if (process.env.STORAGE_PROVIDER === "file" || !process.env.STORAGE_PROVIDER) {
 
 	if (!region) {
 		console.error(
-			`[CDN] You must provide a region when using the S3 storage provider.`
+			`[CDN] You must provide a region when using the S3 storage provider.`,
 		);
 		process.exit(1);
 	}
 
 	if (!bucket) {
 		console.error(
-			`[CDN] You must provide a bucket when using the S3 storage provider.`
+			`[CDN] You must provide a bucket when using the S3 storage provider.`,
 		);
 		process.exit(1);
 	}
@@ -50,7 +50,7 @@ if (process.env.STORAGE_PROVIDER === "file" || !process.env.STORAGE_PROVIDER) {
 
 	if (!location) {
 		console.warn(
-			`[CDN] STORAGE_LOCATION unconfigured for S3 provider, defaulting to the bucket root...`
+			`[CDN] STORAGE_LOCATION unconfigured for S3 provider, defaulting to the bucket root...`,
 		);
 		location = undefined;
 	}
diff --git a/src/gateway/events/Connection.ts b/src/gateway/events/Connection.ts
index bed3cf44..8747e3ad 100644
--- a/src/gateway/events/Connection.ts
+++ b/src/gateway/events/Connection.ts
@@ -21,10 +21,12 @@ try {
 export async function Connection(
 	this: WS.Server,
 	socket: WebSocket,
-	request: IncomingMessage
+	request: IncomingMessage,
 ) {
 	const forwardedFor = Config.get().security.forwadedFor;
-	const ipAddress = forwardedFor ? request.headers[forwardedFor] as string : request.socket.remoteAddress;
+	const ipAddress = forwardedFor
+		? (request.headers[forwardedFor] as string)
+		: request.socket.remoteAddress;
 
 	socket.ipAddress = ipAddress;
 
@@ -33,7 +35,9 @@ export async function Connection(
 		socket.on("close", Close);
 		// @ts-ignore
 		socket.on("message", Message);
-		console.log(`[Gateway] New connection from ${socket.ipAddress}, total ${this.clients.size}`);
+		console.log(
+			`[Gateway] New connection from ${socket.ipAddress}, total ${this.clients.size}`,
+		);
 
 		const { searchParams } = new URL(`http://localhost${request.url}`);
 		// @ts-ignore
@@ -41,7 +45,7 @@ export async function Connection(
 		if (!["json", "etf"].includes(socket.encoding)) {
 			if (socket.encoding === "etf" && erlpack) {
 				throw new Error(
-					"Erlpack is not installed: 'npm i @yukikaze-bot/erlpack'"
+					"Erlpack is not installed: 'npm i @yukikaze-bot/erlpack'",
 				);
 			}
 			return socket.close(CLOSECODES.Decode_error);
diff --git a/src/gateway/events/Message.ts b/src/gateway/events/Message.ts
index 4699f1af..603f68fa 100644
--- a/src/gateway/events/Message.ts
+++ b/src/gateway/events/Message.ts
@@ -3,7 +3,7 @@ import { WebSocket, Payload } from "@fosscord/gateway";
 var erlpack: any;
 try {
 	erlpack = require("@yukikaze-bot/erlpack");
-} catch (error) { }
+} catch (error) {}
 import OPCodeHandlers from "../opcodes";
 import { Tuple } from "lambert-server";
 import { check } from "../opcodes/instanceOf";
@@ -34,11 +34,9 @@ export async function Message(this: WebSocket, buffer: WS.Data) {
 			}
 		}
 		data = bigIntJson.parse(buffer as string);
-	}
-	else if (typeof buffer == "string") {
+	} else if (typeof buffer == "string") {
 		data = bigIntJson.parse(buffer as string);
-	}
-	else return;
+	} else return;
 
 	check.call(this, PayloadSchema, data);
 
diff --git a/src/gateway/listener/listener.ts b/src/gateway/listener/listener.ts
index 72dd9d5b..1d9caebb 100644
--- a/src/gateway/listener/listener.ts
+++ b/src/gateway/listener/listener.ts
@@ -26,7 +26,7 @@ import { Recipient } from "@fosscord/util";
 
 export function handlePresenceUpdate(
 	this: WebSocket,
-	{ event, acknowledge, data }: EventOpts
+	{ event, acknowledge, data }: EventOpts,
 ) {
 	acknowledge?.();
 	if (event === EVENTEnum.PresenceUpdate) {
@@ -54,14 +54,14 @@ export async function setupListener(this: WebSocket) {
 			where: {
 				from_id: this.user_id,
 				type: RelationshipType.friends,
-			}
+			},
 		}),
 	]);
 
 	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 } = {
 		acknowledge: true,
 	};
 	this.listen_options = opts;
@@ -79,7 +79,7 @@ export async function setupListener(this: WebSocket) {
 		this.events[relationship.to_id] = await listenEvent(
 			relationship.to_id,
 			handlePresenceUpdate.bind(this),
-			opts
+			opts,
 		);
 	});
 
@@ -101,7 +101,7 @@ export async function setupListener(this: WebSocket) {
 				this.events[channel.id] = await listenEvent(
 					channel.id,
 					consumer,
-					opts
+					opts,
 				);
 			}
 		});
@@ -137,7 +137,7 @@ async function consume(this: WebSocket, opts: EventOpts) {
 			this.member_events[data.user.id] = await listenEvent(
 				data.user.id,
 				handlePresenceUpdate.bind(this),
-				this.listen_options
+				this.listen_options,
 			);
 			break;
 		case "GUILD_MEMBER_REMOVE":
@@ -164,7 +164,7 @@ async function consume(this: WebSocket, opts: EventOpts) {
 			this.events[data.user.id] = await listenEvent(
 				data.user.id,
 				handlePresenceUpdate.bind(this),
-				this.listen_options
+				this.listen_options,
 			);
 			break;
 		case "GUILD_CREATE":
diff --git a/src/gateway/opcodes/Identify.ts b/src/gateway/opcodes/Identify.ts
index b4b36075..c5c78f1a 100644
--- a/src/gateway/opcodes/Identify.ts
+++ b/src/gateway/opcodes/Identify.ts
@@ -158,11 +158,13 @@ export async function onIdentify(this: WebSocket, data: Payload) {
 		...x.settings,
 		guild_id: x.guild.id,
 		// disgusting
-		channel_overrides: Object.entries(x.settings.channel_overrides ?? {}).map(y => ({
+		channel_overrides: Object.entries(
+			x.settings.channel_overrides ?? {},
+		).map((y) => ({
 			...y[1],
 			channel_id: y[0],
-		}))
-	})) as any as UserGuildSettings[];	// VERY disgusting. don't care.
+		})),
+	})) as any as UserGuildSettings[]; // VERY disgusting. don't care.
 
 	const channels = recipients.map((x) => {
 		// @ts-ignore
@@ -171,7 +173,7 @@ export async function onIdentify(this: WebSocket, data: Payload) {
 		users = users.concat(x.channel.recipients as unknown as User[]);
 		if (x.channel.isDm()) {
 			x.channel.recipients = x.channel.recipients!.filter(
-				(x) => x.id !== this.user_id
+				(x) => x.id !== this.user_id,
 			);
 		}
 		return x.channel;
@@ -243,7 +245,7 @@ export async function onIdentify(this: WebSocket, data: Payload) {
 		accent_color: user.accent_color,
 		banner: user.banner,
 		bio: user.bio,
-		premium_since: user.premium_since
+		premium_since: user.premium_since,
 	};
 
 	const d: ReadyEventData = {
diff --git a/src/gateway/opcodes/LazyRequest.ts b/src/gateway/opcodes/LazyRequest.ts
index 0f21d087..f5bbad14 100644
--- a/src/gateway/opcodes/LazyRequest.ts
+++ b/src/gateway/opcodes/LazyRequest.ts
@@ -1,5 +1,19 @@
-import { getDatabase, getPermission, listenEvent, Member, Role, Session, LazyRequestSchema } from "@fosscord/util";
-import { WebSocket, Payload, handlePresenceUpdate, OPCODES, Send } from "@fosscord/gateway";
+import {
+	getDatabase,
+	getPermission,
+	listenEvent,
+	Member,
+	Role,
+	Session,
+	LazyRequestSchema,
+} from "@fosscord/util";
+import {
+	WebSocket,
+	Payload,
+	handlePresenceUpdate,
+	OPCODES,
+	Send,
+} from "@fosscord/gateway";
 import { check } from "./instanceOf";
 
 // TODO: only show roles/members that have access to this channel
@@ -14,7 +28,8 @@ async function getMembers(guild_id: string, range: [number, number]) {
 
 	let members: Member[] = [];
 	try {
-		members = await getDatabase()!.getRepository(Member)
+		members = await getDatabase()!
+			.getRepository(Member)
 			.createQueryBuilder("member")
 			.where("member.guild_id = :guild_id", { guild_id })
 			.leftJoinAndSelect("member.roles", "role")
@@ -23,7 +38,7 @@ async function getMembers(guild_id: string, range: [number, number]) {
 			.addSelect("user.settings")
 			.addSelect(
 				"CASE WHEN session.status = 'offline' THEN 0 ELSE 1 END",
-				"_status"
+				"_status",
 			)
 			.orderBy("role.position", "DESC")
 			.addOrderBy("_status", "DESC")
@@ -31,8 +46,7 @@ async function getMembers(guild_id: string, range: [number, number]) {
 			.offset(Number(range[0]) || 0)
 			.limit(Number(range[1]) || 100)
 			.getMany();
-	}
-	catch (e) {
+	} catch (e) {
 		console.error(`LazyRequest`, e);
 	}
 
@@ -51,14 +65,20 @@ async function getMembers(guild_id: string, range: [number, number]) {
 		.map((m) => m.roles)
 		.flat()
 		.unique((r: Role) => r.id);
-	member_roles.push(member_roles.splice(member_roles.findIndex(x => x.id === x.guild_id), 1)[0]);
+	member_roles.push(
+		member_roles.splice(
+			member_roles.findIndex((x) => x.id === x.guild_id),
+			1,
+		)[0],
+	);
 
 	const offlineItems = [];
 
 	for (const role of member_roles) {
 		// @ts-ignore
-		const [role_members, other_members]: Member[][] = partition(members, (m: Member) =>
-			m.roles.find((r) => r.id === role.id)
+		const [role_members, other_members]: Member[][] = partition(
+			members,
+			(m: Member) => m.roles.find((r) => r.id === role.id),
 		);
 		const group = {
 			count: role_members.length,
@@ -74,15 +94,19 @@ async function getMembers(guild_id: string, range: [number, number]) {
 				.map((x: Role) => x.id);
 
 			const statusMap = {
-				"online": 0,
-				"idle": 1,
-				"dnd": 2,
-				"invisible": 3,
-				"offline": 4,
+				online: 0,
+				idle: 1,
+				dnd: 2,
+				invisible: 3,
+				offline: 4,
 			};
 			// sort sessions by relevance
 			const sessions = member.user.sessions.sort((a, b) => {
-				return (statusMap[a.status] - statusMap[b.status]) + ((a.activities.length - b.activities.length) * 2);
+				return (
+					statusMap[a.status] -
+					statusMap[b.status] +
+					(a.activities.length - b.activities.length) * 2
+				);
 			});
 			var session: Session | undefined = sessions.first();
 
@@ -103,7 +127,11 @@ async function getMembers(guild_id: string, range: [number, number]) {
 				},
 			};
 
-			if (!session || session.status == "invisible" || session.status == "offline") {
+			if (
+				!session ||
+				session.status == "invisible" ||
+				session.status == "offline"
+			) {
 				item.member.presence.status = "offline";
 				offlineItems.push(item);
 				group.count--;
@@ -130,7 +158,9 @@ async function getMembers(guild_id: string, range: [number, number]) {
 		items,
 		groups,
 		range,
-		members: items.map((x) => 'member' in x ? x.member : undefined).filter(x => !!x),
+		members: items
+			.map((x) => ("member" in x ? x.member : undefined))
+			.filter((x) => !!x),
 	};
 }
 
@@ -161,7 +191,7 @@ export async function onLazyRequest(this: WebSocket, { d }: Payload) {
 			this.member_events[member.user.id] = await listenEvent(
 				member.user.id,
 				handlePresenceUpdate.bind(this),
-				this.listen_options
+				this.listen_options,
 			);
 		});
 	});
@@ -181,7 +211,9 @@ export async function onLazyRequest(this: WebSocket, { d }: Payload) {
 				op: "SYNC",
 				range: x.range,
 			})),
-			online_count: member_count - (groups.find(x => x.id == "offline")?.count ?? 0),
+			online_count:
+				member_count -
+				(groups.find((x) => x.id == "offline")?.count ?? 0),
 			member_count,
 			id: "everyone",
 			guild_id,
@@ -199,6 +231,6 @@ function partition<T>(array: T[], isValid: Function) {
 				? [[...pass, elem], fail]
 				: [pass, [...fail, elem]];
 		},
-		[[], []]
+		[[], []],
 	);
 }
diff --git a/src/gateway/opcodes/PresenceUpdate.ts b/src/gateway/opcodes/PresenceUpdate.ts
index d17b7dd7..37299213 100644
--- a/src/gateway/opcodes/PresenceUpdate.ts
+++ b/src/gateway/opcodes/PresenceUpdate.ts
@@ -1,5 +1,11 @@
 import { WebSocket, Payload } from "@fosscord/gateway";
-import { emitEvent, PresenceUpdateEvent, Session, User, ActivitySchema } from "@fosscord/util";
+import {
+	emitEvent,
+	PresenceUpdateEvent,
+	Session,
+	User,
+	ActivitySchema,
+} from "@fosscord/util";
 import { check } from "./instanceOf";
 
 export async function onPresenceUpdate(this: WebSocket, { d }: Payload) {
@@ -8,7 +14,7 @@ export async function onPresenceUpdate(this: WebSocket, { d }: Payload) {
 
 	await Session.update(
 		{ session_id: this.session_id },
-		{ status: presence.status, activities: presence.activities }
+		{ status: presence.status, activities: presence.activities },
 	);
 
 	await emitEvent({
diff --git a/src/gateway/opcodes/VoiceStateUpdate.ts b/src/gateway/opcodes/VoiceStateUpdate.ts
index 8e1585ec..17ed7e4f 100644
--- a/src/gateway/opcodes/VoiceStateUpdate.ts
+++ b/src/gateway/opcodes/VoiceStateUpdate.ts
@@ -87,16 +87,18 @@ export async function onVoiceStateUpdate(this: WebSocket, data: Payload) {
 
 	//If it's null it means that we are leaving the channel and this event is not needed
 	if (voiceState.channel_id !== null) {
-		const guild = await Guild.findOne({ where: { id: voiceState.guild_id } });
+		const guild = await Guild.findOne({
+			where: { id: voiceState.guild_id },
+		});
 		const regions = Config.get().regions;
 		let guildRegion: Region;
 		if (guild && guild.region) {
 			guildRegion = regions.available.filter(
-				(r) => r.id === guild.region
+				(r) => r.id === guild.region,
 			)[0];
 		} else {
 			guildRegion = regions.available.filter(
-				(r) => r.id === regions.default
+				(r) => r.id === regions.default,
 			)[0];
 		}
 
diff --git a/src/gateway/start.ts b/src/gateway/start.ts
index 90d7f34e..84de674f 100644
--- a/src/gateway/start.ts
+++ b/src/gateway/start.ts
@@ -1,4 +1,4 @@
-require('module-alias/register');
+require("module-alias/register");
 process.on("uncaughtException", console.error);
 process.on("unhandledRejection", console.error);
 
diff --git a/src/gateway/util/Send.ts b/src/gateway/util/Send.ts
index e1460846..1c0f33c3 100644
--- a/src/gateway/util/Send.ts
+++ b/src/gateway/util/Send.ts
@@ -2,7 +2,9 @@ var erlpack: any;
 try {
 	erlpack = require("@yukikaze-bot/erlpack");
 } catch (error) {
-	console.log("Missing @yukikaze-bot/erlpack, electron-based desktop clients designed for discord.com will not be able to connect!");
+	console.log(
+		"Missing @yukikaze-bot/erlpack, electron-based desktop clients designed for discord.com will not be able to connect!",
+	);
 }
 import { Payload, WebSocket } from "@fosscord/gateway";
 
diff --git a/src/util/dtos/DmChannelDTO.ts b/src/util/dtos/DmChannelDTO.ts
index 226b2f9d..fcc91204 100644
--- a/src/util/dtos/DmChannelDTO.ts
+++ b/src/util/dtos/DmChannelDTO.ts
@@ -11,7 +11,11 @@ export class DmChannelDTO {
 	recipients: MinimalPublicUserDTO[];
 	type: number;
 
-	static async from(channel: Channel, excluded_recipients: string[] = [], origin_channel_id?: string) {
+	static async from(
+		channel: Channel,
+		excluded_recipients: string[] = [],
+		origin_channel_id?: string,
+	) {
 		const obj = new DmChannelDTO();
 		obj.icon = channel.icon || null;
 		obj.id = channel.id;
@@ -23,10 +27,15 @@ export class DmChannelDTO {
 		obj.recipients = (
 			await Promise.all(
 				channel
-					.recipients!.filter((r) => !excluded_recipients.includes(r.user_id))
+					.recipients!.filter(
+						(r) => !excluded_recipients.includes(r.user_id),
+					)
 					.map(async (r) => {
-						return await User.findOneOrFail({ where: { id: r.user_id }, select: PublicUserProjection });
-					})
+						return await User.findOneOrFail({
+							where: { id: r.user_id },
+							select: PublicUserProjection,
+						});
+					}),
 			)
 		).map((u) => new MinimalPublicUserDTO(u));
 		return obj;
@@ -35,7 +44,9 @@ export class DmChannelDTO {
 	excludedRecipients(excluded_recipients: string[]): DmChannelDTO {
 		return {
 			...this,
-			recipients: this.recipients.filter((r) => !excluded_recipients.includes(r.id)),
+			recipients: this.recipients.filter(
+				(r) => !excluded_recipients.includes(r.id),
+			),
 		};
 	}
 }
diff --git a/src/util/entities/Attachment.ts b/src/util/entities/Attachment.ts
index 7b4b17eb..055b6f4b 100644
--- a/src/util/entities/Attachment.ts
+++ b/src/util/entities/Attachment.ts
@@ -1,4 +1,11 @@
-import { BeforeRemove, Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
+import {
+	BeforeRemove,
+	Column,
+	Entity,
+	JoinColumn,
+	ManyToOne,
+	RelationId,
+} from "typeorm";
 import { URL } from "url";
 import { deleteFile } from "../util/cdn";
 import { BaseClass } from "./BaseClass";
@@ -31,9 +38,13 @@ export class Attachment extends BaseClass {
 	message_id: string;
 
 	@JoinColumn({ name: "message_id" })
-	@ManyToOne(() => require("./Message").Message, (message: import("./Message").Message) => message.attachments, {
-		onDelete: "CASCADE",
-	})
+	@ManyToOne(
+		() => require("./Message").Message,
+		(message: import("./Message").Message) => message.attachments,
+		{
+			onDelete: "CASCADE",
+		},
+	)
 	message: import("./Message").Message;
 
 	@BeforeRemove()
diff --git a/src/util/entities/AuditLog.ts b/src/util/entities/AuditLog.ts
index b003e7ba..9cc97742 100644
--- a/src/util/entities/AuditLog.ts
+++ b/src/util/entities/AuditLog.ts
@@ -5,24 +5,24 @@ import { User } from "./User";
 
 export enum AuditLogEvents {
 	// guild level
-	GUILD_UPDATE = 1, 
+	GUILD_UPDATE = 1,
 	GUILD_IMPORT = 2,
 	GUILD_EXPORTED = 3,
 	GUILD_ARCHIVE = 4,
 	GUILD_UNARCHIVE = 5,
 	// join-leave
-	USER_JOIN = 6, 
+	USER_JOIN = 6,
 	USER_LEAVE = 7,
 	// channels
-	CHANNEL_CREATE = 10, 
+	CHANNEL_CREATE = 10,
 	CHANNEL_UPDATE = 11,
 	CHANNEL_DELETE = 12,
 	// permission overrides
-	CHANNEL_OVERWRITE_CREATE = 13, 
+	CHANNEL_OVERWRITE_CREATE = 13,
 	CHANNEL_OVERWRITE_UPDATE = 14,
 	CHANNEL_OVERWRITE_DELETE = 15,
 	// kick and ban
-	MEMBER_KICK = 20, 
+	MEMBER_KICK = 20,
 	MEMBER_PRUNE = 21,
 	MEMBER_BAN_ADD = 22,
 	MEMBER_BAN_REMOVE = 23,
@@ -79,17 +79,17 @@ export enum AuditLogEvents {
 	// application commands
 	APPLICATION_COMMAND_PERMISSION_UPDATE = 121,
 	// automod
-	POLICY_CREATE = 140, 
+	POLICY_CREATE = 140,
 	POLICY_UPDATE = 141,
 	POLICY_DELETE = 142,
-	MESSAGE_BLOCKED_BY_POLICIES = 143,  // in fosscord, blocked messages are stealth-dropped
+	MESSAGE_BLOCKED_BY_POLICIES = 143, // in fosscord, blocked messages are stealth-dropped
 	// instance policies affecting the guild
 	GUILD_AFFECTED_BY_POLICIES = 216,
 	// message moves
 	IN_GUILD_MESSAGE_MOVE = 223,
 	CROSS_GUILD_MESSAGE_MOVE = 224,
 	// message routing
-	ROUTE_CREATE = 225, 
+	ROUTE_CREATE = 225,
 	ROUTE_UPDATE = 226,
 }
 
diff --git a/src/util/entities/BackupCodes.ts b/src/util/entities/BackupCodes.ts
index d532a39a..81cdbb6d 100644
--- a/src/util/entities/BackupCodes.ts
+++ b/src/util/entities/BackupCodes.ts
@@ -24,7 +24,7 @@ export function generateMfaBackupCodes(user_id: string) {
 	for (let i = 0; i < 10; i++) {
 		const code = BackupCode.create({
 			user: { id: user_id },
-			code: crypto.randomBytes(4).toString("hex"),	// 8 characters
+			code: crypto.randomBytes(4).toString("hex"), // 8 characters
 			consumed: false,
 			expired: false,
 		});
@@ -32,4 +32,4 @@ export function generateMfaBackupCodes(user_id: string) {
 	}
 
 	return backup_codes;
-}
\ No newline at end of file
+}
diff --git a/src/util/entities/BaseClass.ts b/src/util/entities/BaseClass.ts
index d5a7c2bf..9942b60e 100644
--- a/src/util/entities/BaseClass.ts
+++ b/src/util/entities/BaseClass.ts
@@ -1,5 +1,12 @@
 import "reflect-metadata";
-import { BaseEntity, BeforeInsert, BeforeUpdate, FindOptionsWhere, ObjectIdColumn, PrimaryColumn } from "typeorm";
+import {
+	BaseEntity,
+	BeforeInsert,
+	BeforeUpdate,
+	FindOptionsWhere,
+	ObjectIdColumn,
+	PrimaryColumn,
+} from "typeorm";
 import { Snowflake } from "../util/Snowflake";
 import "missing-native-js-functions";
 import { getDatabase } from "..";
@@ -22,23 +29,40 @@ export class BaseClassWithoutId extends BaseEntity {
 	toJSON(): any {
 		return Object.fromEntries(
 			this.metadata!.columns // @ts-ignore
-				.map((x) => [x.propertyName, this[x.propertyName]]) // @ts-ignore
-				.concat(this.metadata.relations.map((x) => [x.propertyName, this[x.propertyName]]))
+				.map((x) => [x.propertyName, this[x.propertyName]])
+				.concat(
+					// @ts-ignore
+					this.metadata.relations.map((x) => [
+						x.propertyName,
+						// @ts-ignore
+						this[x.propertyName],
+					]),
+				),
 		);
 	}
 
-	static increment<T extends BaseClass>(conditions: FindOptionsWhere<T>, propertyPath: string, value: number | string) {
+	static increment<T extends BaseClass>(
+		conditions: FindOptionsWhere<T>,
+		propertyPath: string,
+		value: number | string,
+	) {
 		const repository = this.getRepository();
 		return repository.increment(conditions, propertyPath, value);
 	}
 
-	static decrement<T extends BaseClass>(conditions: FindOptionsWhere<T>, propertyPath: string, value: number | string) {
+	static decrement<T extends BaseClass>(
+		conditions: FindOptionsWhere<T>,
+		propertyPath: string,
+		value: number | string,
+	) {
 		const repository = this.getRepository();
 		return repository.decrement(conditions, propertyPath, value);
 	}
 }
 
-export const PrimaryIdColumn = process.env.DATABASE?.startsWith("mongodb") ? ObjectIdColumn : PrimaryColumn;
+export const PrimaryIdColumn = process.env.DATABASE?.startsWith("mongodb")
+	? ObjectIdColumn
+	: PrimaryColumn;
 
 export class BaseClass extends BaseClassWithoutId {
 	@PrimaryIdColumn()
diff --git a/src/util/entities/Categories.ts b/src/util/entities/Categories.ts
index 81fbc303..f12b237d 100644
--- a/src/util/entities/Categories.ts
+++ b/src/util/entities/Categories.ts
@@ -1,4 +1,4 @@
-import { PrimaryColumn, Column, Entity} from "typeorm";
+import { PrimaryColumn, Column, Entity } from "typeorm";
 import { BaseClassWithoutId } from "./BaseClass";
 
 // TODO: categories:
@@ -16,18 +16,18 @@ import { BaseClassWithoutId } from "./BaseClass";
 // Also populate discord default categories
 
 @Entity("categories")
-export class Categories extends BaseClassWithoutId { // Not using snowflake
-    
-    @PrimaryColumn()
-	id: number;
+export class Categories extends BaseClassWithoutId {
+	// Not using snowflake
 
-    @Column({ nullable: true })
-    name: string;
+	@PrimaryColumn()
+	id: number;
 
-    @Column({ type: "simple-json" })
-    localizations: string;
+	@Column({ nullable: true })
+	name: string;
 
-    @Column({ nullable: true })
-    is_primary: boolean;
+	@Column({ type: "simple-json" })
+	localizations: string;
 
-}
\ No newline at end of file
+	@Column({ nullable: true })
+	is_primary: boolean;
+}
diff --git a/src/util/entities/Channel.ts b/src/util/entities/Channel.ts
index 2200bfa3..14f36857 100644
--- a/src/util/entities/Channel.ts
+++ b/src/util/entities/Channel.ts
@@ -1,389 +1,457 @@
-import { Column, Entity, JoinColumn, ManyToOne, OneToMany, RelationId } 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, ChannelTypes } from "../util";

-import { ChannelCreateEvent, ChannelRecipientRemoveEvent } from "../interfaces";

-import { Recipient } from "./Recipient";

-import { Message } from "./Message";

-import { ReadState } from "./ReadState";

-import { Invite } from "./Invite";

-import { VoiceState } from "./VoiceState";

-import { Webhook } from "./Webhook";

-import { DmChannelDTO } from "../dtos";

-

-export enum ChannelType {

-	GUILD_TEXT = 0, // a text channel within a guild

-	DM = 1, // a direct message between users

-	GUILD_VOICE = 2, // a voice channel within a guild

-	GROUP_DM = 3, // a direct message between multiple users

-	GUILD_CATEGORY = 4, // an organizational category that contains zero or more channels

-	GUILD_NEWS = 5, // a channel that users can follow and crosspost into a guild or route

-	GUILD_STORE = 6, // a channel in which game developers can sell their things

-	ENCRYPTED = 7, // end-to-end encrypted channel

-	ENCRYPTED_THREAD = 8, // end-to-end encrypted thread channel

-	TRANSACTIONAL = 9, // event chain style transactional channel

-	GUILD_NEWS_THREAD = 10, // a temporary sub-channel within a GUILD_NEWS channel

-	GUILD_PUBLIC_THREAD = 11, // a temporary sub-channel within a GUILD_TEXT channel

-	GUILD_PRIVATE_THREAD = 12, // a temporary sub-channel within a GUILD_TEXT channel that is only viewable by those invited and those with the MANAGE_THREADS permission

-	GUILD_STAGE_VOICE = 13, // a voice channel for hosting events with an audience

-	DIRECTORY = 14, // guild directory listing channel

-	GUILD_FORUM = 15, // forum composed of IM threads

-	TICKET_TRACKER = 33, // ticket tracker, individual ticket items shall have type 12

-	KANBAN = 34, // confluence like kanban board

-	VOICELESS_WHITEBOARD = 35, // whiteboard but without voice (whiteboard + voice is the same as stage)

-	CUSTOM_START = 64, // start custom channel types from here

-	UNHANDLED = 255 // unhandled unowned pass-through channel type

-}

-

-@Entity("channels")

-export class Channel extends BaseClass {

-	@Column()

-	created_at: Date;

-

-	@Column({ nullable: true })

-	name?: string;

-

-	@Column({ type: "text", nullable: true })

-	icon?: string | null;

-

-	@Column({ type: "int" })

-	type: ChannelType;

-

-	@OneToMany(() => Recipient, (recipient: Recipient) => recipient.channel, {

-		cascade: true,

-		orphanedRowAction: "delete",

-	})

-	recipients?: Recipient[];

-

-	@Column({ nullable: true })

-	last_message_id?: string;

-

-	@Column({ nullable: true })

-	@RelationId((channel: Channel) => channel.guild)

-	guild_id?: string;

-

-	@JoinColumn({ name: "guild_id" })

-	@ManyToOne(() => Guild, {

-		onDelete: "CASCADE",

-	})

-	guild: Guild;

-

-	@Column({ nullable: true })

-	@RelationId((channel: Channel) => channel.parent)

-	parent_id: string;

-

-	@JoinColumn({ name: "parent_id" })

-	@ManyToOne(() => Channel)

-	parent?: Channel;

-

-	// for group DMs and owned custom channel types

-	@Column({ nullable: true })

-	@RelationId((channel: Channel) => channel.owner)

-	owner_id?: string;

-

-	@JoinColumn({ name: "owner_id" })

-	@ManyToOne(() => User)

-	owner: User;

-

-	@Column({ nullable: true })

-	last_pin_timestamp?: number;

-

-	@Column({ nullable: true })

-	default_auto_archive_duration?: number;

-

-	@Column({ nullable: true })

-	position?: number;

-

-	@Column({ type: "simple-json", nullable: true })

-	permission_overwrites?: ChannelPermissionOverwrite[];

-

-	@Column({ nullable: true })

-	video_quality_mode?: number;

-

-	@Column({ nullable: true })

-	bitrate?: number;

-

-	@Column({ nullable: true })

-	user_limit?: number;

-

-	@Column()

-	nsfw: boolean = false;

-

-	@Column({ nullable: true })

-	rate_limit_per_user?: number;

-

-	@Column({ nullable: true })

-	topic?: string;

-

-	@OneToMany(() => Invite, (invite: Invite) => invite.channel, {

-		cascade: true,

-		orphanedRowAction: "delete",

-	})

-	invites?: Invite[];

-

-	@Column({ nullable: true })

-	retention_policy_id?: string;

-

-	@OneToMany(() => Message, (message: Message) => message.channel, {

-		cascade: true,

-		orphanedRowAction: "delete",

-	})

-	messages?: Message[];

-

-	@OneToMany(() => VoiceState, (voice_state: VoiceState) => voice_state.channel, {

-		cascade: true,

-		orphanedRowAction: "delete",

-	})

-	voice_states?: VoiceState[];

-

-	@OneToMany(() => ReadState, (read_state: ReadState) => read_state.channel, {

-		cascade: true,

-		orphanedRowAction: "delete",

-	})

-	read_states?: ReadState[];

-

-	@OneToMany(() => Webhook, (webhook: Webhook) => webhook.channel, {

-		cascade: true,

-		orphanedRowAction: "delete",

-	})

-	webhooks?: Webhook[];

-

-	// TODO: DM channel

-	static async createChannel(

-		channel: Partial<Channel>,

-		user_id: string = "0",

-		opts?: {

-			keepId?: boolean;

-			skipExistsCheck?: boolean;

-			skipPermissionCheck?: boolean;

-			skipEventEmit?: boolean;

-			skipNameChecks?: boolean;

-		}

-	) {

-		if (!opts?.skipPermissionCheck) {

-			// Always check if user has permission first

-			const permissions = await getPermission(user_id, channel.guild_id);

-			permissions.hasThrow("MANAGE_CHANNELS");

-		}

-

-		if (!opts?.skipNameChecks) {

-			const guild = await Guild.findOneOrFail({ where: { id: channel.guild_id } });

-			if (!guild.features.includes("ALLOW_INVALID_CHANNEL_NAMES") && channel.name) {

-				for (var character of InvisibleCharacters)

-					if (channel.name.includes(character))

-						throw new HTTPError("Channel name cannot include invalid characters", 403);

-

-				// Categories skip these checks on discord.com

-				if (channel.type !== ChannelType.GUILD_CATEGORY) {

-					if (channel.name.includes(" "))

-						throw new HTTPError("Channel name cannot include invalid characters", 403);

-

-					if (channel.name.match(/\-\-+/g))

-						throw new HTTPError("Channel name cannot include multiple adjacent dashes.", 403);

-

-					if (channel.name.charAt(0) === "-" ||

-						channel.name.charAt(channel.name.length - 1) === "-")

-						throw new HTTPError("Channel name cannot start/end with dash.", 403);

-				}

-				else

-					channel.name = channel.name.trim();	//category names are trimmed client side on discord.com

-			}

-

-			if (!guild.features.includes("ALLOW_UNNAMED_CHANNELS")) {

-				if (!channel.name)

-					throw new HTTPError("Channel name cannot be empty.", 403);

-			}

-		}

-

-		switch (channel.type) {

-			case ChannelType.GUILD_TEXT:

-			case ChannelType.GUILD_NEWS:

-			case ChannelType.GUILD_VOICE:

-				if (channel.parent_id && !opts?.skipExistsCheck) {

-					const exists = await Channel.findOneOrFail({ where: { id: channel.parent_id } });

-					if (!exists) throw new HTTPError("Parent id channel doesn't exist", 400);

-					if (exists.guild_id !== channel.guild_id)

-						throw new HTTPError("The category channel needs to be in the guild");

-				}

-				break;

-			case ChannelType.GUILD_CATEGORY:

-			case ChannelType.UNHANDLED:

-				break;

-			case ChannelType.DM:

-			case ChannelType.GROUP_DM:

-				throw new HTTPError("You can't create a dm channel in a guild");

-			case ChannelType.GUILD_STORE:

-			default:

-				throw new HTTPError("Not yet supported");

-		}

-

-		if (!channel.permission_overwrites) channel.permission_overwrites = [];

-		// TODO: eagerly auto generate position of all guild channels

-

-		channel = {

-			...channel,

-			...(!opts?.keepId && { id: Snowflake.generate() }),

-			created_at: new Date(),

-			position: (channel.type === ChannelType.UNHANDLED ? 0 : channel.position) || 0,

-		};

-

-		await Promise.all([

-			Channel.create(channel).save(),

-			!opts?.skipEventEmit

-				? emitEvent({

-					event: "CHANNEL_CREATE",

-					data: channel,

-					guild_id: channel.guild_id,

-				} as ChannelCreateEvent)

-				: Promise.resolve(),

-		]);

-

-		return channel;

-	}

-

-	static async createDMChannel(recipients: string[], creator_user_id: string, name?: string) {

-		recipients = recipients.unique().filter((x) => x !== creator_user_id);

-		// TODO: check config for max number of recipients

-		/** if you want to disallow note to self channels, uncomment the conditional below

-

-		const otherRecipientsUsers = await User.find({ where: recipients.map((x) => ({ id: x })) });

-		if (otherRecipientsUsers.length !== recipients.length) {

-			throw new HTTPError("Recipient/s not found");

-		}

-		**/

-

-		const type = recipients.length > 1 ? ChannelType.GROUP_DM : ChannelType.DM;

-

-		let channel = null;

-

-		const channelRecipients = [...recipients, creator_user_id];

-

-		const userRecipients = await Recipient.find({

-			where: { user_id: creator_user_id },

-			relations: ["channel", "channel.recipients"],

-		});

-

-		for (let ur of userRecipients) {

-			let re = ur.channel.recipients!.map((r) => r.user_id);

-			if (re.length === channelRecipients.length) {

-				if (containsAll(re, channelRecipients)) {

-					if (channel == null) {

-						channel = ur.channel;

-						await ur.assign({ closed: false }).save();

-					}

-				}

-			}

-		}

-

-		if (channel == null) {

-			name = trimSpecial(name);

-

-			channel = await Channel.create({

-				name,

-				type,

-				owner_id: undefined,

-				created_at: new Date(),

-				last_message_id: undefined,

-				recipients: channelRecipients.map(

-					(x) =>

-						Recipient.create({ user_id: x, closed: !(type === ChannelType.GROUP_DM || x === creator_user_id) })

-				),

-				nsfw: false,

-			}).save();

-		}

-

-		const channel_dto = await DmChannelDTO.from(channel);

-

-		if (type === ChannelType.GROUP_DM) {

-			for (let recipient of channel.recipients!) {

-				await emitEvent({

-					event: "CHANNEL_CREATE",

-					data: channel_dto.excludedRecipients([recipient.user_id]),

-					user_id: recipient.user_id,

-				});

-			}

-		} else {

-			await emitEvent({ event: "CHANNEL_CREATE", data: channel_dto, user_id: creator_user_id });

-		}

-

-		if (recipients.length === 1) return channel_dto;

-		else return channel_dto.excludedRecipients([creator_user_id]);

-	}

-

-	static async removeRecipientFromChannel(channel: Channel, user_id: string) {

-		await Recipient.delete({ channel_id: channel.id, user_id: user_id });

-		channel.recipients = channel.recipients?.filter((r) => r.user_id !== user_id);

-

-		if (channel.recipients?.length === 0) {

-			await Channel.deleteChannel(channel);

-			await emitEvent({

-				event: "CHANNEL_DELETE",

-				data: await DmChannelDTO.from(channel, [user_id]),

-				user_id: user_id,

-			});

-			return;

-		}

-

-		await emitEvent({

-			event: "CHANNEL_DELETE",

-			data: await DmChannelDTO.from(channel, [user_id]),

-			user_id: user_id,

-		});

-

-		//If the owner leave the server user is the new owner

-		if (channel.owner_id === user_id) {

-			channel.owner_id = "1"; // The channel is now owned by the server user

-			await emitEvent({

-				event: "CHANNEL_UPDATE",

-				data: await DmChannelDTO.from(channel, [user_id]),

-				channel_id: channel.id,

-			});

-		}

-

-		await channel.save();

-

-		await emitEvent({

-			event: "CHANNEL_RECIPIENT_REMOVE",

-			data: {

-				channel_id: channel.id,

-				user: await User.findOneOrFail({ where: { id: user_id }, select: PublicUserProjection }),

-			},

-			channel_id: channel.id,

-		} as ChannelRecipientRemoveEvent);

-	}

-

-	static async deleteChannel(channel: Channel) {

-		await Message.delete({ channel_id: channel.id }); //TODO we should also delete the attachments from the cdn but to do that we need to move cdn.ts in util

-		//TODO before deleting the channel we should check and delete other relations

-		await Channel.delete({ id: channel.id });

-	}

-

-	isDm() {

-		return this.type === ChannelType.DM || this.type === ChannelType.GROUP_DM;

-	}

-

-	// Does the channel support sending messages ( eg categories do not )

-	isWritable() {

-		const disallowedChannelTypes = [

-			ChannelType.GUILD_CATEGORY,

-			ChannelType.GUILD_STAGE_VOICE,

-			ChannelType.VOICELESS_WHITEBOARD,

-		];

-		return disallowedChannelTypes.indexOf(this.type) == -1;

-	}

-}

-

-export interface ChannelPermissionOverwrite {

-	allow: string;

-	deny: string;

-	id: string;

-	type: ChannelPermissionOverwriteType;

-}

-

-export enum ChannelPermissionOverwriteType {

-	role = 0,

-	member = 1,

-	group = 2,

-}

+import {
+	Column,
+	Entity,
+	JoinColumn,
+	ManyToOne,
+	OneToMany,
+	RelationId,
+} 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,
+	ChannelTypes,
+} from "../util";
+import { ChannelCreateEvent, ChannelRecipientRemoveEvent } from "../interfaces";
+import { Recipient } from "./Recipient";
+import { Message } from "./Message";
+import { ReadState } from "./ReadState";
+import { Invite } from "./Invite";
+import { VoiceState } from "./VoiceState";
+import { Webhook } from "./Webhook";
+import { DmChannelDTO } from "../dtos";
+
+export enum ChannelType {
+	GUILD_TEXT = 0, // a text channel within a guild
+	DM = 1, // a direct message between users
+	GUILD_VOICE = 2, // a voice channel within a guild
+	GROUP_DM = 3, // a direct message between multiple users
+	GUILD_CATEGORY = 4, // an organizational category that contains zero or more channels
+	GUILD_NEWS = 5, // a channel that users can follow and crosspost into a guild or route
+	GUILD_STORE = 6, // a channel in which game developers can sell their things
+	ENCRYPTED = 7, // end-to-end encrypted channel
+	ENCRYPTED_THREAD = 8, // end-to-end encrypted thread channel
+	TRANSACTIONAL = 9, // event chain style transactional channel
+	GUILD_NEWS_THREAD = 10, // a temporary sub-channel within a GUILD_NEWS channel
+	GUILD_PUBLIC_THREAD = 11, // a temporary sub-channel within a GUILD_TEXT channel
+	GUILD_PRIVATE_THREAD = 12, // a temporary sub-channel within a GUILD_TEXT channel that is only viewable by those invited and those with the MANAGE_THREADS permission
+	GUILD_STAGE_VOICE = 13, // a voice channel for hosting events with an audience
+	DIRECTORY = 14, // guild directory listing channel
+	GUILD_FORUM = 15, // forum composed of IM threads
+	TICKET_TRACKER = 33, // ticket tracker, individual ticket items shall have type 12
+	KANBAN = 34, // confluence like kanban board
+	VOICELESS_WHITEBOARD = 35, // whiteboard but without voice (whiteboard + voice is the same as stage)
+	CUSTOM_START = 64, // start custom channel types from here
+	UNHANDLED = 255, // unhandled unowned pass-through channel type
+}
+
+@Entity("channels")
+export class Channel extends BaseClass {
+	@Column()
+	created_at: Date;
+
+	@Column({ nullable: true })
+	name?: string;
+
+	@Column({ type: "text", nullable: true })
+	icon?: string | null;
+
+	@Column({ type: "int" })
+	type: ChannelType;
+
+	@OneToMany(() => Recipient, (recipient: Recipient) => recipient.channel, {
+		cascade: true,
+		orphanedRowAction: "delete",
+	})
+	recipients?: Recipient[];
+
+	@Column({ nullable: true })
+	last_message_id?: string;
+
+	@Column({ nullable: true })
+	@RelationId((channel: Channel) => channel.guild)
+	guild_id?: string;
+
+	@JoinColumn({ name: "guild_id" })
+	@ManyToOne(() => Guild, {
+		onDelete: "CASCADE",
+	})
+	guild: Guild;
+
+	@Column({ nullable: true })
+	@RelationId((channel: Channel) => channel.parent)
+	parent_id: string;
+
+	@JoinColumn({ name: "parent_id" })
+	@ManyToOne(() => Channel)
+	parent?: Channel;
+
+	// for group DMs and owned custom channel types
+	@Column({ nullable: true })
+	@RelationId((channel: Channel) => channel.owner)
+	owner_id?: string;
+
+	@JoinColumn({ name: "owner_id" })
+	@ManyToOne(() => User)
+	owner: User;
+
+	@Column({ nullable: true })
+	last_pin_timestamp?: number;
+
+	@Column({ nullable: true })
+	default_auto_archive_duration?: number;
+
+	@Column({ nullable: true })
+	position?: number;
+
+	@Column({ type: "simple-json", nullable: true })
+	permission_overwrites?: ChannelPermissionOverwrite[];
+
+	@Column({ nullable: true })
+	video_quality_mode?: number;
+
+	@Column({ nullable: true })
+	bitrate?: number;
+
+	@Column({ nullable: true })
+	user_limit?: number;
+
+	@Column()
+	nsfw: boolean = false;
+
+	@Column({ nullable: true })
+	rate_limit_per_user?: number;
+
+	@Column({ nullable: true })
+	topic?: string;
+
+	@OneToMany(() => Invite, (invite: Invite) => invite.channel, {
+		cascade: true,
+		orphanedRowAction: "delete",
+	})
+	invites?: Invite[];
+
+	@Column({ nullable: true })
+	retention_policy_id?: string;
+
+	@OneToMany(() => Message, (message: Message) => message.channel, {
+		cascade: true,
+		orphanedRowAction: "delete",
+	})
+	messages?: Message[];
+
+	@OneToMany(
+		() => VoiceState,
+		(voice_state: VoiceState) => voice_state.channel,
+		{
+			cascade: true,
+			orphanedRowAction: "delete",
+		},
+	)
+	voice_states?: VoiceState[];
+
+	@OneToMany(() => ReadState, (read_state: ReadState) => read_state.channel, {
+		cascade: true,
+		orphanedRowAction: "delete",
+	})
+	read_states?: ReadState[];
+
+	@OneToMany(() => Webhook, (webhook: Webhook) => webhook.channel, {
+		cascade: true,
+		orphanedRowAction: "delete",
+	})
+	webhooks?: Webhook[];
+
+	// TODO: DM channel
+	static async createChannel(
+		channel: Partial<Channel>,
+		user_id: string = "0",
+		opts?: {
+			keepId?: boolean;
+			skipExistsCheck?: boolean;
+			skipPermissionCheck?: boolean;
+			skipEventEmit?: boolean;
+			skipNameChecks?: boolean;
+		},
+	) {
+		if (!opts?.skipPermissionCheck) {
+			// Always check if user has permission first
+			const permissions = await getPermission(user_id, channel.guild_id);
+			permissions.hasThrow("MANAGE_CHANNELS");
+		}
+
+		if (!opts?.skipNameChecks) {
+			const guild = await Guild.findOneOrFail({
+				where: { id: channel.guild_id },
+			});
+			if (
+				!guild.features.includes("ALLOW_INVALID_CHANNEL_NAMES") &&
+				channel.name
+			) {
+				for (var character of InvisibleCharacters)
+					if (channel.name.includes(character))
+						throw new HTTPError(
+							"Channel name cannot include invalid characters",
+							403,
+						);
+
+				// Categories skip these checks on discord.com
+				if (channel.type !== ChannelType.GUILD_CATEGORY) {
+					if (channel.name.includes(" "))
+						throw new HTTPError(
+							"Channel name cannot include invalid characters",
+							403,
+						);
+
+					if (channel.name.match(/\-\-+/g))
+						throw new HTTPError(
+							"Channel name cannot include multiple adjacent dashes.",
+							403,
+						);
+
+					if (
+						channel.name.charAt(0) === "-" ||
+						channel.name.charAt(channel.name.length - 1) === "-"
+					)
+						throw new HTTPError(
+							"Channel name cannot start/end with dash.",
+							403,
+						);
+				} else channel.name = channel.name.trim(); //category names are trimmed client side on discord.com
+			}
+
+			if (!guild.features.includes("ALLOW_UNNAMED_CHANNELS")) {
+				if (!channel.name)
+					throw new HTTPError("Channel name cannot be empty.", 403);
+			}
+		}
+
+		switch (channel.type) {
+			case ChannelType.GUILD_TEXT:
+			case ChannelType.GUILD_NEWS:
+			case ChannelType.GUILD_VOICE:
+				if (channel.parent_id && !opts?.skipExistsCheck) {
+					const exists = await Channel.findOneOrFail({
+						where: { id: channel.parent_id },
+					});
+					if (!exists)
+						throw new HTTPError(
+							"Parent id channel doesn't exist",
+							400,
+						);
+					if (exists.guild_id !== channel.guild_id)
+						throw new HTTPError(
+							"The category channel needs to be in the guild",
+						);
+				}
+				break;
+			case ChannelType.GUILD_CATEGORY:
+			case ChannelType.UNHANDLED:
+				break;
+			case ChannelType.DM:
+			case ChannelType.GROUP_DM:
+				throw new HTTPError("You can't create a dm channel in a guild");
+			case ChannelType.GUILD_STORE:
+			default:
+				throw new HTTPError("Not yet supported");
+		}
+
+		if (!channel.permission_overwrites) channel.permission_overwrites = [];
+		// TODO: eagerly auto generate position of all guild channels
+
+		channel = {
+			...channel,
+			...(!opts?.keepId && { id: Snowflake.generate() }),
+			created_at: new Date(),
+			position:
+				(channel.type === ChannelType.UNHANDLED
+					? 0
+					: channel.position) || 0,
+		};
+
+		await Promise.all([
+			Channel.create(channel).save(),
+			!opts?.skipEventEmit
+				? emitEvent({
+						event: "CHANNEL_CREATE",
+						data: channel,
+						guild_id: channel.guild_id,
+				  } as ChannelCreateEvent)
+				: Promise.resolve(),
+		]);
+
+		return channel;
+	}
+
+	static async createDMChannel(
+		recipients: string[],
+		creator_user_id: string,
+		name?: string,
+	) {
+		recipients = recipients.unique().filter((x) => x !== creator_user_id);
+		// TODO: check config for max number of recipients
+		/** if you want to disallow note to self channels, uncomment the conditional below
+
+		const otherRecipientsUsers = await User.find({ where: recipients.map((x) => ({ id: x })) });
+		if (otherRecipientsUsers.length !== recipients.length) {
+			throw new HTTPError("Recipient/s not found");
+		}
+		**/
+
+		const type =
+			recipients.length > 1 ? ChannelType.GROUP_DM : ChannelType.DM;
+
+		let channel = null;
+
+		const channelRecipients = [...recipients, creator_user_id];
+
+		const userRecipients = await Recipient.find({
+			where: { user_id: creator_user_id },
+			relations: ["channel", "channel.recipients"],
+		});
+
+		for (let ur of userRecipients) {
+			let re = ur.channel.recipients!.map((r) => r.user_id);
+			if (re.length === channelRecipients.length) {
+				if (containsAll(re, channelRecipients)) {
+					if (channel == null) {
+						channel = ur.channel;
+						await ur.assign({ closed: false }).save();
+					}
+				}
+			}
+		}
+
+		if (channel == null) {
+			name = trimSpecial(name);
+
+			channel = await Channel.create({
+				name,
+				type,
+				owner_id: undefined,
+				created_at: new Date(),
+				last_message_id: undefined,
+				recipients: channelRecipients.map((x) =>
+					Recipient.create({
+						user_id: x,
+						closed: !(
+							type === ChannelType.GROUP_DM ||
+							x === creator_user_id
+						),
+					}),
+				),
+				nsfw: false,
+			}).save();
+		}
+
+		const channel_dto = await DmChannelDTO.from(channel);
+
+		if (type === ChannelType.GROUP_DM) {
+			for (let recipient of channel.recipients!) {
+				await emitEvent({
+					event: "CHANNEL_CREATE",
+					data: channel_dto.excludedRecipients([recipient.user_id]),
+					user_id: recipient.user_id,
+				});
+			}
+		} else {
+			await emitEvent({
+				event: "CHANNEL_CREATE",
+				data: channel_dto,
+				user_id: creator_user_id,
+			});
+		}
+
+		if (recipients.length === 1) return channel_dto;
+		else return channel_dto.excludedRecipients([creator_user_id]);
+	}
+
+	static async removeRecipientFromChannel(channel: Channel, user_id: string) {
+		await Recipient.delete({ channel_id: channel.id, user_id: user_id });
+		channel.recipients = channel.recipients?.filter(
+			(r) => r.user_id !== user_id,
+		);
+
+		if (channel.recipients?.length === 0) {
+			await Channel.deleteChannel(channel);
+			await emitEvent({
+				event: "CHANNEL_DELETE",
+				data: await DmChannelDTO.from(channel, [user_id]),
+				user_id: user_id,
+			});
+			return;
+		}
+
+		await emitEvent({
+			event: "CHANNEL_DELETE",
+			data: await DmChannelDTO.from(channel, [user_id]),
+			user_id: user_id,
+		});
+
+		//If the owner leave the server user is the new owner
+		if (channel.owner_id === user_id) {
+			channel.owner_id = "1"; // The channel is now owned by the server user
+			await emitEvent({
+				event: "CHANNEL_UPDATE",
+				data: await DmChannelDTO.from(channel, [user_id]),
+				channel_id: channel.id,
+			});
+		}
+
+		await channel.save();
+
+		await emitEvent({
+			event: "CHANNEL_RECIPIENT_REMOVE",
+			data: {
+				channel_id: channel.id,
+				user: await User.findOneOrFail({
+					where: { id: user_id },
+					select: PublicUserProjection,
+				}),
+			},
+			channel_id: channel.id,
+		} as ChannelRecipientRemoveEvent);
+	}
+
+	static async deleteChannel(channel: Channel) {
+		await Message.delete({ channel_id: channel.id }); //TODO we should also delete the attachments from the cdn but to do that we need to move cdn.ts in util
+		//TODO before deleting the channel we should check and delete other relations
+		await Channel.delete({ id: channel.id });
+	}
+
+	isDm() {
+		return (
+			this.type === ChannelType.DM || this.type === ChannelType.GROUP_DM
+		);
+	}
+
+	// Does the channel support sending messages ( eg categories do not )
+	isWritable() {
+		const disallowedChannelTypes = [
+			ChannelType.GUILD_CATEGORY,
+			ChannelType.GUILD_STAGE_VOICE,
+			ChannelType.VOICELESS_WHITEBOARD,
+		];
+		return disallowedChannelTypes.indexOf(this.type) == -1;
+	}
+}
+
+export interface ChannelPermissionOverwrite {
+	allow: string;
+	deny: string;
+	id: string;
+	type: ChannelPermissionOverwriteType;
+}
+
+export enum ChannelPermissionOverwriteType {
+	role = 0,
+	member = 1,
+	group = 2,
+}
diff --git a/src/util/entities/ClientRelease.ts b/src/util/entities/ClientRelease.ts
index c5afd307..2723ab67 100644
--- a/src/util/entities/ClientRelease.ts
+++ b/src/util/entities/ClientRelease.ts
@@ -1,4 +1,4 @@
-import { Column, Entity} from "typeorm";
+import { Column, Entity } from "typeorm";
 import { BaseClass } from "./BaseClass";
 
 @Entity("client_release")
diff --git a/src/util/entities/Config.ts b/src/util/entities/Config.ts
index 9aabc1a8..cd7a6923 100644
--- a/src/util/entities/Config.ts
+++ b/src/util/entities/Config.ts
@@ -191,17 +191,17 @@ export interface ConfigValue {
 		allowTemplateCreation: Boolean;
 		allowDiscordTemplates: Boolean;
 		allowRaws: Boolean;
-	},
+	};
 	client: {
 		useTestClient: Boolean;
 		releases: {
 			useLocalRelease: Boolean; //TODO
 			upstreamVersion: string;
 		};
-	},
+	};
 	metrics: {
 		timeout: number;
-	},
+	};
 	sentry: {
 		enabled: boolean;
 		endpoint: string;
@@ -230,7 +230,8 @@ export const DefaultConfigOptions: ConfigValue = {
 	},
 	general: {
 		instanceName: "Fosscord Instance",
-		instanceDescription: "This is a Fosscord instance made in pre-release days",
+		instanceDescription:
+			"This is a Fosscord instance made in pre-release days",
 		frontPage: null,
 		tosPage: null,
 		correspondenceEmail: "noreply@localhost.local",
@@ -318,8 +319,9 @@ export const DefaultConfigOptions: ConfigValue = {
 			sitekey: null,
 			secret: null,
 		},
-		ipdataApiKey: "eca677b284b3bac29eb72f5e496aa9047f26543605efe99ff2ce35c9",
-		defaultRights: "30644591655936",	// See util/scripts/rights.js
+		ipdataApiKey:
+			"eca677b284b3bac29eb72f5e496aa9047f26543605efe99ff2ce35c9",
+		defaultRights: "30644591655936", // See util/scripts/rights.js
 	},
 	login: {
 		requireCaptcha: false,
@@ -395,22 +397,23 @@ export const DefaultConfigOptions: ConfigValue = {
 		enabled: true,
 		allowTemplateCreation: true,
 		allowDiscordTemplates: true,
-		allowRaws: false
+		allowRaws: false,
 	},
 	client: {
 		useTestClient: true,
 		releases: {
 			useLocalRelease: true,
-			upstreamVersion: "0.0.264"
-		}
+			upstreamVersion: "0.0.264",
+		},
 	},
 	metrics: {
-		timeout: 30000
+		timeout: 30000,
 	},
 	sentry: {
 		enabled: false,
-		endpoint: "https://05e8e3d005f34b7d97e920ae5870a5e5@sentry.thearcanebrony.net/6",
+		endpoint:
+			"https://05e8e3d005f34b7d97e920ae5870a5e5@sentry.thearcanebrony.net/6",
 		traceSampleRate: 1.0,
-		environment: hostname()
-	}
-};
\ No newline at end of file
+		environment: hostname(),
+	},
+};
diff --git a/src/util/entities/ConnectedAccount.ts b/src/util/entities/ConnectedAccount.ts
index 09ae30ab..a893ff34 100644
--- a/src/util/entities/ConnectedAccount.ts
+++ b/src/util/entities/ConnectedAccount.ts
@@ -2,7 +2,8 @@ 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 interface PublicConnectedAccount
+	extends 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 a3615b7d..0aa640b5 100644
--- a/src/util/entities/Emoji.ts
+++ b/src/util/entities/Emoji.ts
@@ -40,7 +40,7 @@ export class Emoji extends BaseClass {
 
 	@Column({ type: "simple-array" })
 	roles: string[]; // roles this emoji is whitelisted to (new discord feature?)
-	
+
 	@Column({ type: "simple-array", nullable: true })
 	groups: string[]; // user groups this emoji is whitelisted to (Fosscord extension)
 }
diff --git a/src/util/entities/Encryption.ts b/src/util/entities/Encryption.ts
index b597b90a..4c427b32 100644
--- a/src/util/entities/Encryption.ts
+++ b/src/util/entities/Encryption.ts
@@ -1,9 +1,23 @@
-import { Column, Entity, JoinColumn, ManyToOne, OneToMany, RelationId } from "typeorm";
+import {
+	Column,
+	Entity,
+	JoinColumn,
+	ManyToOne,
+	OneToMany,
+	RelationId,
+} 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 {
+	containsAll,
+	emitEvent,
+	getPermission,
+	Snowflake,
+	trimSpecial,
+	InvisibleCharacters,
+} from "../util";
 import { BitField, BitFieldResolvable, BitFlag } from "../util/BitField";
 import { Recipient } from "./Recipient";
 import { Message } from "./Message";
@@ -13,7 +27,6 @@ import { DmChannelDTO } from "../dtos";
 
 @Entity("security_settings")
 export class SecuritySettings extends BaseClass {
-
 	@Column({ nullable: true })
 	guild_id: string;
 
@@ -31,5 +44,4 @@ export class SecuritySettings extends BaseClass {
 
 	@Column({ nullable: true })
 	used_since_message: string;
-
 }
diff --git a/src/util/entities/Guild.ts b/src/util/entities/Guild.ts
index 2ce7c213..8854fec0 100644
--- a/src/util/entities/Guild.ts
+++ b/src/util/entities/Guild.ts
@@ -1,4 +1,13 @@
-import { Column, Entity, JoinColumn, ManyToMany, ManyToOne, OneToMany, OneToOne, RelationId } from "typeorm";
+import {
+	Column,
+	Entity,
+	JoinColumn,
+	ManyToMany,
+	ManyToOne,
+	OneToMany,
+	OneToOne,
+	RelationId,
+} from "typeorm";
 import { Config, handleFile, Snowflake } from "..";
 import { Ban } from "./Ban";
 import { BaseClass } from "./BaseClass";
@@ -86,7 +95,7 @@ export class Guild extends BaseClass {
 	//TODO: https://discord.com/developers/docs/resources/guild#guild-object-guild-features
 
 	@Column({ nullable: true })
-	primary_category_id?: string;	// TODO: this was number?
+	primary_category_id?: string; // TODO: this was number?
 
 	@Column({ nullable: true })
 	icon?: string;
@@ -269,7 +278,7 @@ export class Guild extends BaseClass {
 
 	@Column()
 	nsfw: boolean;
-	
+
 	// TODO: nested guilds
 	@Column({ nullable: true })
 	parent?: string;
@@ -332,10 +341,13 @@ export class Guild extends BaseClass {
 			permissions: String("2251804225"),
 			position: 0,
 			icon: undefined,
-			unicode_emoji: undefined
+			unicode_emoji: undefined,
 		}).save();
 
-		if (!body.channels || !body.channels.length) body.channels = [{ id: "01", type: 0, name: "general", nsfw: false }];
+		if (!body.channels || !body.channels.length)
+			body.channels = [
+				{ id: "01", type: 0, name: "general", nsfw: false },
+			];
 
 		const ids = new Map();
 
@@ -345,17 +357,23 @@ export class Guild extends BaseClass {
 			}
 		});
 
-		for (const channel of body.channels?.sort((a, b) => (a.parent_id ? 1 : -1))) {
+		for (const channel of body.channels?.sort((a, b) =>
+			a.parent_id ? 1 : -1,
+		)) {
 			var id = ids.get(channel.id) || Snowflake.generate();
 
 			var parent_id = ids.get(channel.parent_id);
 
-			await Channel.createChannel({ ...channel, guild_id, id, parent_id }, body.owner_id, {
-				keepId: true,
-				skipExistsCheck: true,
-				skipPermissionCheck: true,
-				skipEventEmit: true,
-			});
+			await Channel.createChannel(
+				{ ...channel, guild_id, id, parent_id },
+				body.owner_id,
+				{
+					keepId: true,
+					skipExistsCheck: true,
+					skipPermissionCheck: true,
+					skipEventEmit: true,
+				},
+			);
 		}
 
 		return guild;
diff --git a/src/util/entities/Invite.ts b/src/util/entities/Invite.ts
index 4f36f247..90dec92a 100644
--- a/src/util/entities/Invite.ts
+++ b/src/util/entities/Invite.ts
@@ -1,4 +1,11 @@
-import { Column, Entity, JoinColumn, ManyToOne, RelationId, PrimaryColumn } from "typeorm";
+import {
+	Column,
+	Entity,
+	JoinColumn,
+	ManyToOne,
+	RelationId,
+	PrimaryColumn,
+} from "typeorm";
 import { Member } from "./Member";
 import { BaseClassWithoutId } from "./BaseClass";
 import { Channel } from "./Channel";
@@ -76,7 +83,8 @@ export class Invite extends BaseClassWithoutId {
 
 	static async joinGuild(user_id: string, code: string) {
 		const invite = await Invite.findOneOrFail({ where: { code } });
-		if (invite.uses++ >= invite.max_uses && invite.max_uses !== 0) await Invite.delete({ code });
+		if (invite.uses++ >= invite.max_uses && invite.max_uses !== 0)
+			await Invite.delete({ code });
 		else await invite.save();
 
 		await Member.addToGuild(user_id, invite.guild_id);
diff --git a/src/util/entities/Member.ts b/src/util/entities/Member.ts
index 7d1346ba..f2762adc 100644
--- a/src/util/entities/Member.ts
+++ b/src/util/entities/Member.ts
@@ -22,7 +22,6 @@ import {
 	GuildMemberRemoveEvent,
 	GuildMemberUpdateEvent,
 	MessageCreateEvent,
-
 } from "../interfaces";
 import { HTTPError } from "lambert-server";
 import { Role } from "./Role";
@@ -126,19 +125,34 @@ export class Member extends BaseClassWithoutId {
 		if (this.nick) {
 			this.nick = this.nick.split("\n").join("");
 			this.nick = this.nick.split("\t").join("");
-			if (BannedWords.find(this.nick)) throw FieldErrors({ nick: { message: "Bad nickname", code: "INVALID_NICKNAME" } });
+			if (BannedWords.find(this.nick))
+				throw FieldErrors({
+					nick: { message: "Bad nickname", code: "INVALID_NICKNAME" },
+				});
 		}
 	}
 
 	static async IsInGuildOrFail(user_id: string, guild_id: string) {
-		if (await Member.count({ where: { id: user_id, guild: { id: guild_id } } })) return true;
+		if (
+			await Member.count({
+				where: { id: user_id, guild: { id: guild_id } },
+			})
+		)
+			return true;
 		throw new HTTPError("You are not member of this guild", 403);
 	}
 
 	static async removeFromGuild(user_id: string, guild_id: string) {
-		const guild = await Guild.findOneOrFail({ select: ["owner_id"], where: { id: guild_id } });
-		if (guild.owner_id === user_id) throw new Error("The owner cannot be removed of the guild");
-		const member = await Member.findOneOrFail({ where: { id: user_id, guild_id }, relations: ["user"] });
+		const guild = await Guild.findOneOrFail({
+			select: ["owner_id"],
+			where: { id: guild_id },
+		});
+		if (guild.owner_id === user_id)
+			throw new Error("The owner cannot be removed of the guild");
+		const member = await Member.findOneOrFail({
+			where: { id: user_id, guild_id },
+			relations: ["user"],
+		});
 
 		// use promise all to execute all promises at the same time -> save time
 		return Promise.all([
@@ -169,9 +183,12 @@ export class Member extends BaseClassWithoutId {
 				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", "roles.id"], // TODO fix type
+			}),
+			Role.findOneOrFail({
+				where: { id: role_id, guild_id },
+				select: ["id"],
 			}),
-			Role.findOneOrFail({ where: { id: role_id, guild_id }, select: ["id"] }),
 		]);
 		member.roles.push(Role.create({ id: role_id }));
 
@@ -189,7 +206,11 @@ export class Member extends BaseClassWithoutId {
 		]);
 	}
 
-	static async removeRole(user_id: string, guild_id: string, role_id: string) {
+	static async removeRole(
+		user_id: string,
+		guild_id: string,
+		role_id: string,
+	) {
 		const [member] = await Promise.all([
 			Member.findOneOrFail({
 				where: { id: user_id, guild_id },
@@ -215,7 +236,11 @@ export class Member extends BaseClassWithoutId {
 		]);
 	}
 
-	static async changeNickname(user_id: string, guild_id: string, nickname: string) {
+	static async changeNickname(
+		user_id: string,
+		guild_id: string,
+		nickname: string,
+	) {
 		const member = await Member.findOneOrFail({
 			where: {
 				id: user_id,
@@ -249,7 +274,10 @@ export class Member extends BaseClassWithoutId {
 		const { maxGuilds } = Config.get().limits.user;
 		const guild_count = await Member.count({ where: { id: user_id } });
 		if (guild_count >= maxGuilds) {
-			throw new HTTPError(`You are at the ${maxGuilds} server limit.`, 403);
+			throw new HTTPError(
+				`You are at the ${maxGuilds} server limit.`,
+				403,
+			);
 		}
 
 		const guild = await Guild.findOneOrFail({
@@ -259,7 +287,11 @@ export class Member extends BaseClassWithoutId {
 			relations: [...PublicGuildRelations, "system_channel"],
 		});
 
-		if (await Member.count({ where: { id: user.id, guild: { id: guild_id } } }))
+		if (
+			await Member.count({
+				where: { id: user.id, guild: { id: guild_id } },
+			})
+		)
 			throw new HTTPError("You are already a member of this guild", 400);
 
 		const member = {
@@ -268,7 +300,7 @@ export class Member extends BaseClassWithoutId {
 			nick: undefined,
 			roles: [guild_id], // @everyone role
 			joined_at: new Date(),
-			premium_since: (new Date()).getTime(),
+			premium_since: new Date().getTime(),
 			deaf: false,
 			mute: false,
 			pending: false,
@@ -339,7 +371,11 @@ export class Member extends BaseClassWithoutId {
 			});
 			await Promise.all([
 				message.save(),
-				emitEvent({ event: "MESSAGE_CREATE", channel_id: message.channel_id, data: message } as MessageCreateEvent)
+				emitEvent({
+					event: "MESSAGE_CREATE",
+					channel_id: message.channel_id,
+					data: message,
+				} as MessageCreateEvent),
 			]);
 		}
 	}
@@ -362,7 +398,7 @@ export interface UserGuildSettings {
 
 	channel_overrides: {
 		[channel_id: string]: ChannelOverride;
-	} | null,
+	} | null;
 	message_notifications: number;
 	mobile_push: boolean;
 	mute_config: MuteConfig | null;
@@ -389,7 +425,7 @@ export const DefaultUserGuildSettings: UserGuildSettings = {
 	notify_highlights: 0,
 	suppress_everyone: false,
 	suppress_roles: false,
-	version: 453,	// ?
+	version: 453, // ?
 	guild_id: null,
 };
 
diff --git a/src/util/entities/Message.ts b/src/util/entities/Message.ts
index be790502..a52b4785 100644
--- a/src/util/entities/Message.ts
+++ b/src/util/entities/Message.ts
@@ -51,7 +51,7 @@ export enum MessageType {
 	SELF_COMMAND_SCRIPT = 43, // self command scripts
 	ENCRYPTION = 50,
 	CUSTOM_START = 63,
-	UNHANDLED = 255
+	UNHANDLED = 255,
 }
 
 @Entity("messages")
@@ -115,7 +115,10 @@ export class Message extends BaseClass {
 	@ManyToOne(() => Application)
 	application?: Application;
 
-	@Column({ nullable: true, type: process.env.PRODUCTION ? "longtext" : undefined })
+	@Column({
+		nullable: true,
+		type: process.env.PRODUCTION ? "longtext" : undefined,
+	})
 	content?: string;
 
 	@Column()
@@ -147,10 +150,14 @@ export class Message extends BaseClass {
 	@ManyToMany(() => Sticker, { cascade: true, onDelete: "CASCADE" })
 	sticker_items?: Sticker[];
 
-	@OneToMany(() => Attachment, (attachment: Attachment) => attachment.message, {
-		cascade: true,
-		orphanedRowAction: "delete",
-	})
+	@OneToMany(
+		() => Attachment,
+		(attachment: Attachment) => attachment.message,
+		{
+			cascade: true,
+			orphanedRowAction: "delete",
+		},
+	)
 	attachments?: Attachment[];
 
 	@Column({ type: "simple-json" })
@@ -176,7 +183,7 @@ export class Message extends BaseClass {
 
 	@Column({ nullable: true })
 	flags?: string;
-	
+
 	@Column({ type: "simple-json", nullable: true })
 	message_reference?: {
 		message_id: string;
@@ -204,7 +211,11 @@ export class Message extends BaseClass {
 	@BeforeInsert()
 	validate() {
 		if (this.content) {
-			if (BannedWords.find(this.content)) throw new HTTPError("Message was blocked by automatic moderation", 200000);
+			if (BannedWords.find(this.content))
+				throw new HTTPError(
+					"Message was blocked by automatic moderation",
+					200000,
+				);
 		}
 	}
 }
diff --git a/src/util/entities/Migration.ts b/src/util/entities/Migration.ts
index 3f39ae72..f4e54eae 100644
--- a/src/util/entities/Migration.ts
+++ b/src/util/entities/Migration.ts
@@ -1,7 +1,14 @@
-import { Column, Entity, ObjectIdColumn, PrimaryGeneratedColumn } from "typeorm";
+import {
+	Column,
+	Entity,
+	ObjectIdColumn,
+	PrimaryGeneratedColumn,
+} from "typeorm";
 import { BaseClassWithoutId } from ".";
 
-export const PrimaryIdAutoGenerated = process.env.DATABASE?.startsWith("mongodb")
+export const PrimaryIdAutoGenerated = process.env.DATABASE?.startsWith(
+	"mongodb",
+)
 	? ObjectIdColumn
 	: PrimaryGeneratedColumn;
 
diff --git a/src/util/entities/Note.ts b/src/util/entities/Note.ts
index 36017c5e..b3ac45ee 100644
--- a/src/util/entities/Note.ts
+++ b/src/util/entities/Note.ts
@@ -15,4 +15,4 @@ export class Note extends BaseClass {
 
 	@Column()
 	content: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/entities/ReadState.ts b/src/util/entities/ReadState.ts
index b915573b..53ed5589 100644
--- a/src/util/entities/ReadState.ts
+++ b/src/util/entities/ReadState.ts
@@ -1,4 +1,11 @@
-import { Column, Entity, Index, JoinColumn, ManyToOne, RelationId } from "typeorm";
+import {
+	Column,
+	Entity,
+	Index,
+	JoinColumn,
+	ManyToOne,
+	RelationId,
+} from "typeorm";
 import { BaseClass } from "./BaseClass";
 import { Channel } from "./Channel";
 import { Message } from "./Message";
@@ -33,8 +40,8 @@ export class ReadState extends BaseClass {
 
 	// fully read marker
 	@Column({ nullable: true })
-	last_message_id: string; 
-	
+	last_message_id: string;
+
 	// public read receipt
 	@Column({ nullable: true })
 	public_ack: string;
diff --git a/src/util/entities/Relationship.ts b/src/util/entities/Relationship.ts
index c3592c76..25b52757 100644
--- a/src/util/entities/Relationship.ts
+++ b/src/util/entities/Relationship.ts
@@ -1,4 +1,11 @@
-import { Column, Entity, Index, JoinColumn, ManyToOne, RelationId } from "typeorm";
+import {
+	Column,
+	Entity,
+	Index,
+	JoinColumn,
+	ManyToOne,
+	RelationId,
+} from "typeorm";
 import { BaseClass } from "./BaseClass";
 import { User } from "./User";
 
diff --git a/src/util/entities/StickerPack.ts b/src/util/entities/StickerPack.ts
index ec8c69a2..04d74bac 100644
--- a/src/util/entities/StickerPack.ts
+++ b/src/util/entities/StickerPack.ts
@@ -1,4 +1,12 @@
-import { Column, Entity, JoinColumn, ManyToOne, OneToMany, OneToOne, RelationId } from "typeorm";
+import {
+	Column,
+	Entity,
+	JoinColumn,
+	ManyToOne,
+	OneToMany,
+	OneToOne,
+	RelationId,
+} from "typeorm";
 import { Sticker } from ".";
 import { BaseClass } from "./BaseClass";
 
diff --git a/src/util/entities/Team.ts b/src/util/entities/Team.ts
index 22140b7f..8f410bb4 100644
--- a/src/util/entities/Team.ts
+++ b/src/util/entities/Team.ts
@@ -1,4 +1,12 @@
-import { Column, Entity, JoinColumn, ManyToMany, ManyToOne, OneToMany, RelationId } from "typeorm";
+import {
+	Column,
+	Entity,
+	JoinColumn,
+	ManyToMany,
+	ManyToOne,
+	OneToMany,
+	RelationId,
+} from "typeorm";
 import { BaseClass } from "./BaseClass";
 import { TeamMember } from "./TeamMember";
 import { User } from "./User";
diff --git a/src/util/entities/TeamMember.ts b/src/util/entities/TeamMember.ts
index b726e1e8..3f4a0422 100644
--- a/src/util/entities/TeamMember.ts
+++ b/src/util/entities/TeamMember.ts
@@ -20,9 +20,13 @@ export class TeamMember extends BaseClass {
 	team_id: string;
 
 	@JoinColumn({ name: "team_id" })
-	@ManyToOne(() => require("./Team").Team, (team: import("./Team").Team) => team.members, {
-		onDelete: "CASCADE",
-	})
+	@ManyToOne(
+		() => require("./Team").Team,
+		(team: import("./Team").Team) => team.members,
+		{
+			onDelete: "CASCADE",
+		},
+	)
 	team: import("./Team").Team;
 
 	@Column({ nullable: true })
diff --git a/src/util/entities/User.ts b/src/util/entities/User.ts
index 84a8a674..1389a424 100644
--- a/src/util/entities/User.ts
+++ b/src/util/entities/User.ts
@@ -1,9 +1,24 @@
-import { BeforeInsert, BeforeUpdate, Column, Entity, FindOneOptions, JoinColumn, OneToMany } from "typeorm";
+import {
+	BeforeInsert,
+	BeforeUpdate,
+	Column,
+	Entity,
+	FindOneOptions,
+	JoinColumn,
+	OneToMany,
+} from "typeorm";
 import { BaseClass } from "./BaseClass";
 import { BitField } from "../util/BitField";
 import { Relationship } from "./Relationship";
 import { ConnectedAccount } from "./ConnectedAccount";
-import { Config, FieldErrors, Snowflake, trimSpecial, BannedWords, adjustEmail } from "..";
+import {
+	Config,
+	FieldErrors,
+	Snowflake,
+	trimSpecial,
+	BannedWords,
+	adjustEmail,
+} from "..";
 import { Member, Session } from ".";
 
 export enum PublicUserEnum {
@@ -38,7 +53,7 @@ export enum PrivateUserEnum {
 export type PrivateUserKeys = keyof typeof PrivateUserEnum | PublicUserKeys;
 
 export const PublicUserProjection = Object.values(PublicUserEnum).filter(
-	(x) => typeof x === "string"
+	(x) => typeof x === "string",
 ) as PublicUserKeys[];
 export const PrivateUserProjection = [
 	...PublicUserProjection,
@@ -48,7 +63,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 interface UserPublic extends Pick<User, PublicUserKeys> {}
 
 export interface UserPrivate extends Pick<User, PrivateUserKeys> {
 	locale: string;
@@ -144,17 +159,25 @@ export class User extends BaseClass {
 	sessions: Session[];
 
 	@JoinColumn({ name: "relationship_ids" })
-	@OneToMany(() => Relationship, (relationship: Relationship) => relationship.from, {
-		cascade: true,
-		orphanedRowAction: "delete",
-	})
+	@OneToMany(
+		() => Relationship,
+		(relationship: Relationship) => relationship.from,
+		{
+			cascade: true,
+			orphanedRowAction: "delete",
+		},
+	)
 	relationships: Relationship[];
 
 	@JoinColumn({ name: "connected_account_ids" })
-	@OneToMany(() => ConnectedAccount, (account: ConnectedAccount) => account.user, {
-		cascade: true,
-		orphanedRowAction: "delete",
-	})
+	@OneToMany(
+		() => ConnectedAccount,
+		(account: ConnectedAccount) => account.user,
+		{
+			cascade: true,
+			orphanedRowAction: "delete",
+		},
+	)
 	connected_accounts: ConnectedAccount[];
 
 	@Column({ type: "simple-json", select: false })
@@ -177,16 +200,43 @@ export class User extends BaseClass {
 	@BeforeInsert()
 	validate() {
 		this.email = adjustEmail(this.email);
-		if (!this.email) throw FieldErrors({ email: { message: "Invalid email", code: "EMAIL_INVALID" } });
-		if (!this.email.match(/([a-z\d.-]{3,})@([a-z\d.-]+).([a-z]{2,})/g)) throw FieldErrors({ email: { message: "Invalid email", code: "EMAIL_INVALID" } });
+		if (!this.email)
+			throw FieldErrors({
+				email: { message: "Invalid email", code: "EMAIL_INVALID" },
+			});
+		if (!this.email.match(/([a-z\d.-]{3,})@([a-z\d.-]+).([a-z]{2,})/g))
+			throw FieldErrors({
+				email: { message: "Invalid email", code: "EMAIL_INVALID" },
+			});
 
 		const discrim = Number(this.discriminator);
-		if (this.discriminator.length > 4) throw FieldErrors({ email: { message: "Discriminator cannot be more than 4 digits.", code: "DISCRIMINATOR_INVALID" } });
-		if (isNaN(discrim)) throw FieldErrors({ email: { message: "Discriminator must be a number.", code: "DISCRIMINATOR_INVALID" } });
-		if (discrim <= 0 || discrim >= 10000) throw FieldErrors({ email: { message: "Discriminator must be a number.", code: "DISCRIMINATOR_INVALID" } });
+		if (this.discriminator.length > 4)
+			throw FieldErrors({
+				email: {
+					message: "Discriminator cannot be more than 4 digits.",
+					code: "DISCRIMINATOR_INVALID",
+				},
+			});
+		if (isNaN(discrim))
+			throw FieldErrors({
+				email: {
+					message: "Discriminator must be a number.",
+					code: "DISCRIMINATOR_INVALID",
+				},
+			});
+		if (discrim <= 0 || discrim >= 10000)
+			throw FieldErrors({
+				email: {
+					message: "Discriminator must be a number.",
+					code: "DISCRIMINATOR_INVALID",
+				},
+			});
 		this.discriminator = discrim.toString().padStart(4, "0");
 
-		if (BannedWords.find(this.username)) throw FieldErrors({ username: { message: "Bad username", code: "INVALID_USERNAME" } });
+		if (BannedWords.find(this.username))
+			throw FieldErrors({
+				username: { message: "Bad username", code: "INVALID_USERNAME" },
+			});
 	}
 
 	toPublicUser() {
@@ -202,17 +252,25 @@ export class User extends BaseClass {
 			where: { id: user_id },
 			...opts,
 			//@ts-ignore
-			select: [...PublicUserProjection, ...(opts?.select || [])],	// TODO: fix
+			select: [...PublicUserProjection, ...(opts?.select || [])], // TODO: fix
 		});
 	}
 
-	private static async generateDiscriminator(username: string): Promise<string | undefined> {
+	private static async generateDiscriminator(
+		username: string,
+	): Promise<string | undefined> {
 		if (Config.get().register.incrementingDiscriminators) {
 			// discriminator will be incrementally generated
 
 			// First we need to figure out the currently highest discrimnator for the given username and then increment it
-			const users = await User.find({ where: { username }, select: ["discriminator"] });
-			const highestDiscriminator = Math.max(0, ...users.map((u) => Number(u.discriminator)));
+			const users = await User.find({
+				where: { username },
+				select: ["discriminator"],
+			});
+			const highestDiscriminator = Math.max(
+				0,
+				...users.map((u) => Number(u.discriminator)),
+			);
 
 			const discriminator = highestDiscriminator + 1;
 			if (discriminator >= 10000) {
@@ -226,8 +284,13 @@ export class User extends BaseClass {
 			// randomly generates a discriminator between 1 and 9999 and checks max five times if it already exists
 			// TODO: is there any better way to generate a random discriminator only once, without checking if it already exists in the database?
 			for (let tries = 0; tries < 5; tries++) {
-				const discriminator = Math.randomIntBetween(1, 9999).toString().padStart(4, "0");
-				const exists = await User.findOne({ where: { discriminator, username: username }, select: ["id"] });
+				const discriminator = Math.randomIntBetween(1, 9999)
+					.toString()
+					.padStart(4, "0");
+				const exists = await User.findOne({
+					where: { discriminator, username: username },
+					select: ["id"],
+				});
 				if (!exists) return discriminator;
 			}
 
@@ -265,7 +328,8 @@ export class User extends BaseClass {
 		// TODO: save date_of_birth
 		// 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";
+		const language =
+			req.language === "en" ? "en-US" : req.language || "en-US";
 
 		const user = User.create({
 			created_at: new Date(),
@@ -295,8 +359,8 @@ export class User extends BaseClass {
 			},
 			settings: { ...defaultSettings, locale: language },
 			purchased_flags: 5, // TODO: idk what the values for this are
-			premium_usage_flags: 2,  // TODO: idk what the values for this are
-			extended_settings: "",	// TODO: was {}
+			premium_usage_flags: 2, // TODO: idk what the values for this are
+			extended_settings: "", // TODO: was {}
 			fingerprints: [],
 		});
 
@@ -305,7 +369,7 @@ 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) => {});
 				}
 			}
 		});
@@ -372,7 +436,7 @@ export interface UserSettings {
 	disable_games_tab: boolean;
 	enable_tts_command: boolean;
 	explicit_content_filter: number;
-	friend_source_flags: { all: boolean; };
+	friend_source_flags: { all: boolean };
 	gateway_connected: boolean;
 	gif_auto_play: boolean;
 	// every top guild is displayed as a "folder"
diff --git a/src/util/entities/index.ts b/src/util/entities/index.ts
index 49793810..c439a4b7 100644
--- a/src/util/entities/index.ts
+++ b/src/util/entities/index.ts
@@ -29,4 +29,4 @@ export * from "./VoiceState";
 export * from "./Webhook";
 export * from "./ClientRelease";
 export * from "./BackupCodes";
-export * from "./Note";
\ No newline at end of file
+export * from "./Note";
diff --git a/src/util/imports/OrmUtils.ts b/src/util/imports/OrmUtils.ts
index 68a1932c..26652db0 100644
--- a/src/util/imports/OrmUtils.ts
+++ b/src/util/imports/OrmUtils.ts
@@ -9,7 +9,12 @@ export class OrmUtils {
 		return !item.constructor || item.constructor === Object;
 	}
 
-	private static mergeArrayKey(target: any, key: number, value: any, memo: Map<any, any>) {
+	private static mergeArrayKey(
+		target: any,
+		key: number,
+		value: any,
+		memo: Map<any, any>,
+	) {
 		// Have we seen this before?  Prevent infinite recursion.
 		if (memo.has(value)) {
 			target[key] = memo.get(value);
@@ -38,7 +43,12 @@ export class OrmUtils {
 		memo.delete(value);
 	}
 
-	private static mergeObjectKey(target: any, key: string, value: any, memo: Map<any, any>) {
+	private static mergeObjectKey(
+		target: any,
+		key: string,
+		value: any,
+		memo: Map<any, any>,
+	) {
 		// Have we seen this before?  Prevent infinite recursion.
 		if (memo.has(value)) {
 			Object.assign(target, { [key]: memo.get(value) });
@@ -67,7 +77,11 @@ export class OrmUtils {
 		memo.delete(value);
 	}
 
-	private static merge(target: any, source: any, memo: Map<any, any> = new Map()): any {
+	private static merge(
+		target: any,
+		source: any,
+		memo: Map<any, any> = new Map(),
+	): any {
 		if (Array.isArray(target) && Array.isArray(source)) {
 			for (let key = 0; key < source.length; key++) {
 				this.mergeArrayKey(target, key, source[key], memo);
@@ -93,4 +107,4 @@ export class OrmUtils {
 
 		return target;
 	}
-}
\ No newline at end of file
+}
diff --git a/src/util/imports/index.ts b/src/util/imports/index.ts
index 5d9bfb5f..823151d9 100644
--- a/src/util/imports/index.ts
+++ b/src/util/imports/index.ts
@@ -1 +1 @@
-export * from "./OrmUtils";
\ No newline at end of file
+export * from "./OrmUtils";
diff --git a/src/util/index.ts b/src/util/index.ts
index 385070a3..3773c275 100644
--- a/src/util/index.ts
+++ b/src/util/index.ts
@@ -5,4 +5,4 @@ export * from "./interfaces/index";
 export * from "./entities/index";
 export * from "./dtos/index";
 export * from "./schemas";
-export * from "./imports";
\ No newline at end of file
+export * from "./imports";
diff --git a/src/util/interfaces/Activity.ts b/src/util/interfaces/Activity.ts
index 9912e197..279ee40f 100644
--- a/src/util/interfaces/Activity.ts
+++ b/src/util/interfaces/Activity.ts
@@ -36,7 +36,8 @@ export interface Activity {
 
 	id?: string;
 	sync_id?: string;
-	metadata?: { // spotify
+	metadata?: {
+		// spotify
 		context_uri?: string;
 		album_id: string;
 		artist_ids: string[];
diff --git a/src/util/interfaces/Event.ts b/src/util/interfaces/Event.ts
index 59f995db..472fd572 100644
--- a/src/util/interfaces/Event.ts
+++ b/src/util/interfaces/Event.ts
@@ -75,7 +75,7 @@ export interface ReadyEventData {
 		number,
 		[[number, { e: number; s: number }[]]],
 		[number, [[number, [number, number]]]],
-		{ b: number; k: bigint[] }[]
+		{ b: number; k: bigint[] }[],
 	][];
 	guild_join_requests?: any[]; // ? what is this? this is new
 	shard?: [number, number];
diff --git a/src/util/migrations/1633864260873-EmojiRoles.ts b/src/util/migrations/1633864260873-EmojiRoles.ts
index f0d709f2..31ced96b 100644
--- a/src/util/migrations/1633864260873-EmojiRoles.ts
+++ b/src/util/migrations/1633864260873-EmojiRoles.ts
@@ -4,10 +4,14 @@ export class EmojiRoles1633864260873 implements MigrationInterface {
 	name = "EmojiRoles1633864260873";
 
 	public async up(queryRunner: QueryRunner): Promise<void> {
-		await queryRunner.query(`ALTER TABLE "emojis" ADD "roles" text NOT NULL DEFAULT ''`);
+		await queryRunner.query(
+			`ALTER TABLE "emojis" ADD "roles" text NOT NULL DEFAULT ''`,
+		);
 	}
 
 	public async down(queryRunner: QueryRunner): Promise<void> {
-		await queryRunner.query(`ALTER TABLE "emojis" DROP COLUMN column_name "roles"`);
+		await queryRunner.query(
+			`ALTER TABLE "emojis" DROP COLUMN column_name "roles"`,
+		);
 	}
 }
diff --git a/src/util/migrations/1633864669243-EmojiUser.ts b/src/util/migrations/1633864669243-EmojiUser.ts
index 982405d7..9610216b 100644
--- a/src/util/migrations/1633864669243-EmojiUser.ts
+++ b/src/util/migrations/1633864669243-EmojiUser.ts
@@ -7,17 +7,21 @@ export class EmojiUser1633864669243 implements MigrationInterface {
 		await queryRunner.query(`ALTER TABLE "emojis" ADD "user_id" varchar`);
 		try {
 			await queryRunner.query(
-				`ALTER TABLE "emojis" ADD CONSTRAINT FK_fa7ddd5f9a214e28ce596548421 FOREIGN KEY (user_id) REFERENCES users(id)`
+				`ALTER TABLE "emojis" ADD CONSTRAINT FK_fa7ddd5f9a214e28ce596548421 FOREIGN KEY (user_id) REFERENCES users(id)`,
 			);
 		} catch (error) {
 			console.error(
-				"sqlite doesn't support altering foreign keys: https://stackoverflow.com/questions/1884818/how-do-i-add-a-foreign-key-to-an-existing-sqlite-table"
+				"sqlite doesn't support altering foreign keys: https://stackoverflow.com/questions/1884818/how-do-i-add-a-foreign-key-to-an-existing-sqlite-table",
 			);
 		}
 	}
 
 	public async down(queryRunner: QueryRunner): Promise<void> {
-		await queryRunner.query(`ALTER TABLE "emojis" DROP COLUMN column_name "user_id"`);
-		await queryRunner.query(`ALTER TABLE "emojis" DROP CONSTRAINT FK_fa7ddd5f9a214e28ce596548421`);
+		await queryRunner.query(
+			`ALTER TABLE "emojis" DROP COLUMN column_name "user_id"`,
+		);
+		await queryRunner.query(
+			`ALTER TABLE "emojis" DROP CONSTRAINT FK_fa7ddd5f9a214e28ce596548421`,
+		);
 	}
 }
diff --git a/src/util/migrations/1633881705509-VanityInvite.ts b/src/util/migrations/1633881705509-VanityInvite.ts
index 45485310..16072473 100644
--- a/src/util/migrations/1633881705509-VanityInvite.ts
+++ b/src/util/migrations/1633881705509-VanityInvite.ts
@@ -5,15 +5,21 @@ export class VanityInvite1633881705509 implements MigrationInterface {
 
 	public async up(queryRunner: QueryRunner): Promise<void> {
 		try {
-			await queryRunner.query(`ALTER TABLE "emojis" DROP COLUMN vanity_url_code`);
-			await queryRunner.query(`ALTER TABLE "emojis" DROP CONSTRAINT FK_c2c1809d79eb120ea0cb8d342ad`);
+			await queryRunner.query(
+				`ALTER TABLE "emojis" DROP COLUMN vanity_url_code`,
+			);
+			await queryRunner.query(
+				`ALTER TABLE "emojis" DROP CONSTRAINT FK_c2c1809d79eb120ea0cb8d342ad`,
+			);
 		} catch (error) {}
 	}
 
 	public async down(queryRunner: QueryRunner): Promise<void> {
-		await queryRunner.query(`ALTER TABLE "emojis" ADD vanity_url_code varchar`);
 		await queryRunner.query(
-			`ALTER TABLE "emojis" ADD CONSTRAINT FK_c2c1809d79eb120ea0cb8d342ad FOREIGN KEY ("vanity_url_code") REFERENCES "invites"("code") ON DELETE NO ACTION ON UPDATE NO ACTION`
+			`ALTER TABLE "emojis" ADD vanity_url_code varchar`,
+		);
+		await queryRunner.query(
+			`ALTER TABLE "emojis" ADD CONSTRAINT FK_c2c1809d79eb120ea0cb8d342ad FOREIGN KEY ("vanity_url_code") REFERENCES "invites"("code") ON DELETE NO ACTION ON UPDATE NO ACTION`,
 		);
 	}
 }
diff --git a/src/util/migrations/1634308884591-Stickers.ts b/src/util/migrations/1634308884591-Stickers.ts
index fbc4649f..f7b83242 100644
--- a/src/util/migrations/1634308884591-Stickers.ts
+++ b/src/util/migrations/1634308884591-Stickers.ts
@@ -1,35 +1,64 @@
-import { MigrationInterface, QueryRunner, Table, TableColumn, TableForeignKey } from "typeorm";
+import {
+	MigrationInterface,
+	QueryRunner,
+	Table,
+	TableColumn,
+	TableForeignKey,
+} from "typeorm";
 
 export class Stickers1634308884591 implements MigrationInterface {
 	name = "Stickers1634308884591";
 
 	public async up(queryRunner: QueryRunner): Promise<void> {
-		await queryRunner.dropForeignKey("read_states", "FK_6f255d873cfbfd7a93849b7ff74");
+		await queryRunner.dropForeignKey(
+			"read_states",
+			"FK_6f255d873cfbfd7a93849b7ff74",
+		);
 		await queryRunner.changeColumn(
 			"stickers",
 			"tags",
-			new TableColumn({ name: "tags", type: "varchar", isNullable: true })
+			new TableColumn({
+				name: "tags",
+				type: "varchar",
+				isNullable: true,
+			}),
 		);
 		await queryRunner.changeColumn(
 			"stickers",
 			"pack_id",
-			new TableColumn({ name: "pack_id", type: "varchar", isNullable: true })
+			new TableColumn({
+				name: "pack_id",
+				type: "varchar",
+				isNullable: true,
+			}),
+		);
+		await queryRunner.changeColumn(
+			"stickers",
+			"type",
+			new TableColumn({ name: "type", type: "integer" }),
 		);
-		await queryRunner.changeColumn("stickers", "type", new TableColumn({ name: "type", type: "integer" }));
 		await queryRunner.changeColumn(
 			"stickers",
 			"format_type",
-			new TableColumn({ name: "format_type", type: "integer" })
+			new TableColumn({ name: "format_type", type: "integer" }),
 		);
 		await queryRunner.changeColumn(
 			"stickers",
 			"available",
-			new TableColumn({ name: "available", type: "boolean", isNullable: true })
+			new TableColumn({
+				name: "available",
+				type: "boolean",
+				isNullable: true,
+			}),
 		);
 		await queryRunner.changeColumn(
 			"stickers",
 			"user_id",
-			new TableColumn({ name: "user_id", type: "boolean", isNullable: true })
+			new TableColumn({
+				name: "user_id",
+				type: "boolean",
+				isNullable: true,
+			}),
 		);
 		await queryRunner.createForeignKey(
 			"stickers",
@@ -39,17 +68,33 @@ export class Stickers1634308884591 implements MigrationInterface {
 				referencedColumnNames: ["id"],
 				referencedTableName: "users",
 				onDelete: "CASCADE",
-			})
+			}),
 		);
 		await queryRunner.createTable(
 			new Table({
 				name: "sticker_packs",
 				columns: [
-					new TableColumn({ name: "id", type: "varchar", isPrimary: true }),
+					new TableColumn({
+						name: "id",
+						type: "varchar",
+						isPrimary: true,
+					}),
 					new TableColumn({ name: "name", type: "varchar" }),
-					new TableColumn({ name: "description", type: "varchar", isNullable: true }),
-					new TableColumn({ name: "banner_asset_id", type: "varchar", isNullable: true }),
-					new TableColumn({ name: "cover_sticker_id", type: "varchar", isNullable: true }),
+					new TableColumn({
+						name: "description",
+						type: "varchar",
+						isNullable: true,
+					}),
+					new TableColumn({
+						name: "banner_asset_id",
+						type: "varchar",
+						isNullable: true,
+					}),
+					new TableColumn({
+						name: "cover_sticker_id",
+						type: "varchar",
+						isNullable: true,
+					}),
 				],
 				foreignKeys: [
 					new TableForeignKey({
@@ -58,7 +103,7 @@ export class Stickers1634308884591 implements MigrationInterface {
 						referencedTableName: "stickers",
 					}),
 				],
-			})
+			}),
 		);
 	}
 
diff --git a/src/util/migrations/1634424361103-Presence.ts b/src/util/migrations/1634424361103-Presence.ts
index 729955b8..a71cb253 100644
--- a/src/util/migrations/1634424361103-Presence.ts
+++ b/src/util/migrations/1634424361103-Presence.ts
@@ -4,7 +4,10 @@ export class Presence1634424361103 implements MigrationInterface {
 	name = "Presence1634424361103";
 
 	public async up(queryRunner: QueryRunner): Promise<void> {
-		queryRunner.addColumn("sessions", new TableColumn({ name: "activites", type: "text" }));
+		queryRunner.addColumn(
+			"sessions",
+			new TableColumn({ name: "activites", type: "text" }),
+		);
 	}
 
 	public async down(queryRunner: QueryRunner): Promise<void> {}
diff --git a/src/util/migrations/1634426540271-MigrationTimestamp.ts b/src/util/migrations/1634426540271-MigrationTimestamp.ts
index 3208b25b..fb596906 100644
--- a/src/util/migrations/1634426540271-MigrationTimestamp.ts
+++ b/src/util/migrations/1634426540271-MigrationTimestamp.ts
@@ -7,7 +7,11 @@ export class MigrationTimestamp1634426540271 implements MigrationInterface {
 		await queryRunner.changeColumn(
 			"migrations",
 			"timestamp",
-			new TableColumn({ name: "timestampe", type: "bigint", isNullable: false })
+			new TableColumn({
+				name: "timestampe",
+				type: "bigint",
+				isNullable: false,
+			}),
 		);
 	}
 
diff --git a/src/util/migrations/1660678870706-opencordFixes.ts b/src/util/migrations/1660678870706-opencordFixes.ts
index 1f10c212..53c561ce 100644
--- a/src/util/migrations/1660678870706-opencordFixes.ts
+++ b/src/util/migrations/1660678870706-opencordFixes.ts
@@ -1,53 +1,52 @@
 import { MigrationInterface, QueryRunner } from "typeorm";
 
 export class opencordFixes1660678870706 implements MigrationInterface {
-    name = 'opencordFixes1660678870706'
+	name = "opencordFixes1660678870706";
 
-    public async up(queryRunner: QueryRunner): Promise<void> {
-        await queryRunner.query(`
+	public async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
             ALTER TABLE \`users\`
             ADD \`purchased_flags\` int NOT NULL
         `);
-        await queryRunner.query(`
+		await queryRunner.query(`
             ALTER TABLE \`users\`
             ADD \`premium_usage_flags\` int NOT NULL
         `);
-        await queryRunner.query(`
+		await queryRunner.query(`
             ALTER TABLE \`user_settings\`
             ADD \`friend_discovery_flags\` int NOT NULL
         `);
-        await queryRunner.query(`
+		await queryRunner.query(`
             ALTER TABLE \`user_settings\`
             ADD \`view_nsfw_guilds\` tinyint NOT NULL
         `);
-        await queryRunner.query(`
+		await queryRunner.query(`
             ALTER TABLE \`user_settings\`
             ADD \`passwordless\` tinyint NOT NULL
         `);
-        await queryRunner.query(`
+		await queryRunner.query(`
             ALTER TABLE \`users\` CHANGE \`mfa_enabled\` \`mfa_enabled\` tinyint NOT NULL
         `);
-    }
+	}
 
-    public async down(queryRunner: QueryRunner): Promise<void> {
-        await queryRunner.query(`
+	public async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
             ALTER TABLE \`users\` CHANGE \`mfa_enabled\` \`mfa_enabled\` tinyint NULL
         `);
-        await queryRunner.query(`
+		await queryRunner.query(`
             ALTER TABLE \`user_settings\` DROP COLUMN \`passwordless\`
         `);
-        await queryRunner.query(`
+		await queryRunner.query(`
             ALTER TABLE \`user_settings\` DROP COLUMN \`view_nsfw_guilds\`
         `);
-        await queryRunner.query(`
+		await queryRunner.query(`
             ALTER TABLE \`user_settings\` DROP COLUMN \`friend_discovery_flags\`
         `);
-        await queryRunner.query(`
+		await queryRunner.query(`
             ALTER TABLE \`users\` DROP COLUMN \`premium_usage_flags\`
         `);
-        await queryRunner.query(`
+		await queryRunner.query(`
             ALTER TABLE \`users\` DROP COLUMN \`purchased_flags\`
         `);
-    }
-
-}
\ No newline at end of file
+	}
+}
diff --git a/src/util/migrations/1660689892073-mobileFixes2.ts b/src/util/migrations/1660689892073-mobileFixes2.ts
index bd28694e..63e7e032 100644
--- a/src/util/migrations/1660689892073-mobileFixes2.ts
+++ b/src/util/migrations/1660689892073-mobileFixes2.ts
@@ -1,37 +1,36 @@
 import { MigrationInterface, QueryRunner } from "typeorm";
 
 export class mobileFixes21660689892073 implements MigrationInterface {
-    name = 'mobileFixes21660689892073'
+	name = "mobileFixes21660689892073";
 
-    public async up(queryRunner: QueryRunner): Promise<void> {
-        await queryRunner.query(`
+	public async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
             ALTER TABLE \`user_settings\`
             ADD \`banner_color\` varchar(255) NULL
         `);
 		await queryRunner.query(`
 			UPDATE \`channels\` SET \`nsfw\` = 0 WHERE \`nsfw\` = NULL
 		`);
-        await queryRunner.query(`
+		await queryRunner.query(`
             ALTER TABLE \`channels\` CHANGE \`nsfw\` \`nsfw\` tinyint NOT NULL
         `);
 		await queryRunner.query(`
 			UPDATE \`guilds\` SET \`nsfw\` = 0 WHERE \`nsfw\` = NULL
 		`);
-        await queryRunner.query(`
+		await queryRunner.query(`
             ALTER TABLE \`guilds\` CHANGE \`nsfw\` \`nsfw\` tinyint NOT NULL
         `);
-    }
+	}
 
-    public async down(queryRunner: QueryRunner): Promise<void> {
-        await queryRunner.query(`
+	public async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
             ALTER TABLE \`guilds\` CHANGE \`nsfw\` \`nsfw\` tinyint NULL
         `);
-        await queryRunner.query(`
+		await queryRunner.query(`
             ALTER TABLE \`channels\` CHANGE \`nsfw\` \`nsfw\` tinyint NULL
         `);
-        await queryRunner.query(`
+		await queryRunner.query(`
             ALTER TABLE \`user_settings\` DROP COLUMN \`banner_color\`
         `);
-    }
-
-}
\ No newline at end of file
+	}
+}
diff --git a/src/util/schemas/ActivitySchema.ts b/src/util/schemas/ActivitySchema.ts
index d316420e..5a3d205b 100644
--- a/src/util/schemas/ActivitySchema.ts
+++ b/src/util/schemas/ActivitySchema.ts
@@ -41,7 +41,8 @@ export const ActivitySchema = {
 
 			$id: String,
 			$sync_id: String,
-			$metadata: { // spotify
+			$metadata: {
+				// spotify
 				$context_uri: String,
 				album_id: String,
 				artist_ids: [String],
@@ -57,4 +58,4 @@ export interface ActivitySchema {
 	status: Status;
 	activities?: Activity[];
 	since?: number; // unix time (in milliseconds) of when the client went idle, or null if the client is not idle
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/BackupCodesChallengeSchema.ts b/src/util/schemas/BackupCodesChallengeSchema.ts
index d6b519b7..8e2f0649 100644
--- a/src/util/schemas/BackupCodesChallengeSchema.ts
+++ b/src/util/schemas/BackupCodesChallengeSchema.ts
@@ -1,3 +1,3 @@
 export interface BackupCodesChallengeSchema {
 	password: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/BanCreateSchema.ts b/src/util/schemas/BanCreateSchema.ts
index 876b2a89..834577dc 100644
--- a/src/util/schemas/BanCreateSchema.ts
+++ b/src/util/schemas/BanCreateSchema.ts
@@ -1,4 +1,4 @@
 export interface BanCreateSchema {
 	delete_message_days?: string;
 	reason?: string;
-};
\ No newline at end of file
+}
diff --git a/src/util/schemas/BanModeratorSchema.ts b/src/util/schemas/BanModeratorSchema.ts
index 8efa2402..afb76433 100644
--- a/src/util/schemas/BanModeratorSchema.ts
+++ b/src/util/schemas/BanModeratorSchema.ts
@@ -4,4 +4,4 @@ export interface BanModeratorSchema {
 	guild_id: string;
 	executor_id: string;
 	reason?: string | undefined;
-};
\ No newline at end of file
+}
diff --git a/src/util/schemas/BanRegistrySchema.ts b/src/util/schemas/BanRegistrySchema.ts
index 8680d3db..501f94dc 100644
--- a/src/util/schemas/BanRegistrySchema.ts
+++ b/src/util/schemas/BanRegistrySchema.ts
@@ -5,4 +5,4 @@ export interface BanRegistrySchema {
 	executor_id: string;
 	ip?: string;
 	reason?: string | undefined;
-};
\ No newline at end of file
+}
diff --git a/src/util/schemas/BulkDeleteSchema.ts b/src/util/schemas/BulkDeleteSchema.ts
index 6a71e052..bfc4df65 100644
--- a/src/util/schemas/BulkDeleteSchema.ts
+++ b/src/util/schemas/BulkDeleteSchema.ts
@@ -1,3 +1,3 @@
 export interface BulkDeleteSchema {
 	messages: string[];
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/ChannelModifySchema.ts b/src/util/schemas/ChannelModifySchema.ts
index 835ea2d7..9a07f983 100644
--- a/src/util/schemas/ChannelModifySchema.ts
+++ b/src/util/schemas/ChannelModifySchema.ts
@@ -27,4 +27,4 @@ export interface ChannelModifySchema {
 	flags?: number;
 	default_thread_rate_limit_per_user?: number;
 	video_quality_mode?: number;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/CodesVerificationSchema.ts b/src/util/schemas/CodesVerificationSchema.ts
index e8e2e7b4..73c371eb 100644
--- a/src/util/schemas/CodesVerificationSchema.ts
+++ b/src/util/schemas/CodesVerificationSchema.ts
@@ -2,4 +2,4 @@ export interface CodesVerificationSchema {
 	key: string;
 	nonce: string;
 	regenerate?: boolean;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/DmChannelCreateSchema.ts b/src/util/schemas/DmChannelCreateSchema.ts
index 04b8ff69..1b0fe86d 100644
--- a/src/util/schemas/DmChannelCreateSchema.ts
+++ b/src/util/schemas/DmChannelCreateSchema.ts
@@ -1,4 +1,4 @@
 export interface DmChannelCreateSchema {
 	name?: string;
 	recipients: string[];
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/EmojiCreateSchema.ts b/src/util/schemas/EmojiCreateSchema.ts
index 8e2a2307..34084713 100644
--- a/src/util/schemas/EmojiCreateSchema.ts
+++ b/src/util/schemas/EmojiCreateSchema.ts
@@ -3,4 +3,4 @@ export interface EmojiCreateSchema {
 	image: string;
 	require_colons?: boolean | null;
 	roles?: string[];
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/EmojiModifySchema.ts b/src/util/schemas/EmojiModifySchema.ts
index cd5b7e3e..05d2d395 100644
--- a/src/util/schemas/EmojiModifySchema.ts
+++ b/src/util/schemas/EmojiModifySchema.ts
@@ -1,4 +1,4 @@
 export interface EmojiModifySchema {
 	name?: string;
 	roles?: string[];
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/GuildCreateSchema.ts b/src/util/schemas/GuildCreateSchema.ts
index 9b5f7dc2..f3de7007 100644
--- a/src/util/schemas/GuildCreateSchema.ts
+++ b/src/util/schemas/GuildCreateSchema.ts
@@ -11,4 +11,4 @@ export interface GuildCreateSchema {
 	guild_template_code?: string;
 	system_channel_id?: string;
 	rules_channel_id?: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/GuildTemplateCreateSchema.ts b/src/util/schemas/GuildTemplateCreateSchema.ts
index 7caefcb8..59db8428 100644
--- a/src/util/schemas/GuildTemplateCreateSchema.ts
+++ b/src/util/schemas/GuildTemplateCreateSchema.ts
@@ -1,4 +1,4 @@
 export interface GuildTemplateCreateSchema {
 	name: string;
 	avatar?: string | null;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/GuildUpdateWelcomeScreenSchema.ts b/src/util/schemas/GuildUpdateWelcomeScreenSchema.ts
index 0022da6e..e271b83e 100644
--- a/src/util/schemas/GuildUpdateWelcomeScreenSchema.ts
+++ b/src/util/schemas/GuildUpdateWelcomeScreenSchema.ts
@@ -7,4 +7,4 @@ export interface GuildUpdateWelcomeScreenSchema {
 	}[];
 	enabled?: boolean;
 	description?: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/InviteCreateSchema.ts b/src/util/schemas/InviteCreateSchema.ts
index 83ae22dd..cac11147 100644
--- a/src/util/schemas/InviteCreateSchema.ts
+++ b/src/util/schemas/InviteCreateSchema.ts
@@ -8,4 +8,4 @@ export interface InviteCreateSchema {
 	unique?: boolean;
 	target_user?: string;
 	target_user_type?: number;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/LoginSchema.ts b/src/util/schemas/LoginSchema.ts
index 543d236c..dc889d94 100644
--- a/src/util/schemas/LoginSchema.ts
+++ b/src/util/schemas/LoginSchema.ts
@@ -5,4 +5,4 @@ export interface LoginSchema {
 	captcha_key?: string;
 	login_source?: string;
 	gift_code_sku_id?: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/MemberChangeSchema.ts b/src/util/schemas/MemberChangeSchema.ts
index 566d7e20..2367bef3 100644
--- a/src/util/schemas/MemberChangeSchema.ts
+++ b/src/util/schemas/MemberChangeSchema.ts
@@ -1,4 +1,4 @@
 export interface MemberChangeSchema {
 	roles?: string[];
 	nick?: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/MemberNickChangeSchema.ts b/src/util/schemas/MemberNickChangeSchema.ts
index ed9fdb7b..d863038c 100644
--- a/src/util/schemas/MemberNickChangeSchema.ts
+++ b/src/util/schemas/MemberNickChangeSchema.ts
@@ -1,3 +1,3 @@
 export interface MemberNickChangeSchema {
 	nick: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/MessageAcknowledgeSchema.ts b/src/util/schemas/MessageAcknowledgeSchema.ts
index 1e7fb80d..194bb4b4 100644
--- a/src/util/schemas/MessageAcknowledgeSchema.ts
+++ b/src/util/schemas/MessageAcknowledgeSchema.ts
@@ -1,4 +1,4 @@
 export interface MessageAcknowledgeSchema {
 	manual?: boolean;
 	mention_count?: number;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/MessageCreateSchema.ts b/src/util/schemas/MessageCreateSchema.ts
index 9d77c485..bf3470bb 100644
--- a/src/util/schemas/MessageCreateSchema.ts
+++ b/src/util/schemas/MessageCreateSchema.ts
@@ -30,4 +30,4 @@ export interface MessageCreateSchema {
 	**/
 	attachments?: any[];
 	sticker_ids?: string[];
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/MfaCodesSchema.ts b/src/util/schemas/MfaCodesSchema.ts
index 226c43f1..ac05b9a4 100644
--- a/src/util/schemas/MfaCodesSchema.ts
+++ b/src/util/schemas/MfaCodesSchema.ts
@@ -1,4 +1,4 @@
 export interface MfaCodesSchema {
 	password: string;
 	regenerate?: boolean;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/ModifyGuildStickerSchema.ts b/src/util/schemas/ModifyGuildStickerSchema.ts
index 06bf4ffe..159cc44f 100644
--- a/src/util/schemas/ModifyGuildStickerSchema.ts
+++ b/src/util/schemas/ModifyGuildStickerSchema.ts
@@ -12,4 +12,4 @@ export interface ModifyGuildStickerSchema {
 	 * @maxLength 200
 	 */
 	tags: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/PruneSchema.ts b/src/util/schemas/PruneSchema.ts
index 60601d81..bea5e2b4 100644
--- a/src/util/schemas/PruneSchema.ts
+++ b/src/util/schemas/PruneSchema.ts
@@ -3,4 +3,4 @@ export interface PruneSchema {
 	 * @min 0
 	 */
 	days: number;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/PurgeSchema.ts b/src/util/schemas/PurgeSchema.ts
index 8916be92..f5ab0a20 100644
--- a/src/util/schemas/PurgeSchema.ts
+++ b/src/util/schemas/PurgeSchema.ts
@@ -1,4 +1,4 @@
 export interface PurgeSchema {
 	before: string;
 	after: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/RegisterSchema.ts b/src/util/schemas/RegisterSchema.ts
index c0cc3805..865f55b3 100644
--- a/src/util/schemas/RegisterSchema.ts
+++ b/src/util/schemas/RegisterSchema.ts
@@ -24,4 +24,4 @@ export interface RegisterSchema {
 	captcha_key?: string;
 
 	promotional_email_opt_in?: boolean;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/RelationshipPostSchema.ts b/src/util/schemas/RelationshipPostSchema.ts
index 3ff6eade..774c67f6 100644
--- a/src/util/schemas/RelationshipPostSchema.ts
+++ b/src/util/schemas/RelationshipPostSchema.ts
@@ -1,4 +1,4 @@
 export interface RelationshipPostSchema {
 	discriminator: string;
 	username: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/RelationshipPutSchema.ts b/src/util/schemas/RelationshipPutSchema.ts
index 455f854e..0a7f9720 100644
--- a/src/util/schemas/RelationshipPutSchema.ts
+++ b/src/util/schemas/RelationshipPutSchema.ts
@@ -2,4 +2,4 @@ import { RelationshipType } from "@fosscord/util";
 
 export interface RelationshipPutSchema {
 	type?: RelationshipType;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/RoleModifySchema.ts b/src/util/schemas/RoleModifySchema.ts
index adb0c1a6..f3f4a20e 100644
--- a/src/util/schemas/RoleModifySchema.ts
+++ b/src/util/schemas/RoleModifySchema.ts
@@ -7,4 +7,4 @@ export interface RoleModifySchema {
 	position?: number;
 	icon?: string;
 	unicode_emoji?: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/SelectProtocolSchema.ts b/src/util/schemas/SelectProtocolSchema.ts
index 92958e97..0ba0c23b 100644
--- a/src/util/schemas/SelectProtocolSchema.ts
+++ b/src/util/schemas/SelectProtocolSchema.ts
@@ -1,12 +1,12 @@
 export interface SelectProtocolSchema {
 	protocol: "webrtc" | "udp";
 	data:
-	| string
-	| {
-		address: string;
-		port: number;
-		mode: string;
-	};
+		| string
+		| {
+				address: string;
+				port: number;
+				mode: string;
+		  };
 	sdp?: string;
 	codecs?: {
 		name: "opus" | "VP8" | "VP9" | "H264";
@@ -16,4 +16,4 @@ export interface SelectProtocolSchema {
 		rtx_payload_type?: number | null;
 	}[];
 	rtc_connection_id?: string; // uuid
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/TemplateCreateSchema.ts b/src/util/schemas/TemplateCreateSchema.ts
index 3f98f692..160934f5 100644
--- a/src/util/schemas/TemplateCreateSchema.ts
+++ b/src/util/schemas/TemplateCreateSchema.ts
@@ -1,4 +1,4 @@
 export interface TemplateCreateSchema {
 	name: string;
 	description?: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/TemplateModifySchema.ts b/src/util/schemas/TemplateModifySchema.ts
index 3e6efb74..f9c9d14b 100644
--- a/src/util/schemas/TemplateModifySchema.ts
+++ b/src/util/schemas/TemplateModifySchema.ts
@@ -1,4 +1,4 @@
 export interface TemplateModifySchema {
 	name: string;
 	description?: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/TotpDisableSchema.ts b/src/util/schemas/TotpDisableSchema.ts
index 05192bfa..51446e1c 100644
--- a/src/util/schemas/TotpDisableSchema.ts
+++ b/src/util/schemas/TotpDisableSchema.ts
@@ -1,3 +1,3 @@
 export interface TotpDisableSchema {
 	code: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/TotpEnableSchema.ts b/src/util/schemas/TotpEnableSchema.ts
index 7f6fb5a9..4e3551d9 100644
--- a/src/util/schemas/TotpEnableSchema.ts
+++ b/src/util/schemas/TotpEnableSchema.ts
@@ -2,4 +2,4 @@ export interface TotpEnableSchema {
 	password: string;
 	code?: string;
 	secret?: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/TotpSchema.ts b/src/util/schemas/TotpSchema.ts
index 889cb443..941a92ec 100644
--- a/src/util/schemas/TotpSchema.ts
+++ b/src/util/schemas/TotpSchema.ts
@@ -1,6 +1,6 @@
 export interface TotpSchema {
-	code: string,
-	ticket: string,
-	gift_code_sku_id?: string | null,
-	login_source?: string | null,
-}
\ No newline at end of file
+	code: string;
+	ticket: string;
+	gift_code_sku_id?: string | null;
+	login_source?: string | null;
+}
diff --git a/src/util/schemas/UserModifySchema.ts b/src/util/schemas/UserModifySchema.ts
index 34e0f135..5327e34b 100644
--- a/src/util/schemas/UserModifySchema.ts
+++ b/src/util/schemas/UserModifySchema.ts
@@ -16,4 +16,4 @@ export interface UserModifySchema {
 	code?: string;
 	email?: string;
 	discriminator?: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/Validator.ts b/src/util/schemas/Validator.ts
index b71bf6a1..e85cdf7b 100644
--- a/src/util/schemas/Validator.ts
+++ b/src/util/schemas/Validator.ts
@@ -3,7 +3,14 @@ import addFormats from "ajv-formats";
 import fs from "fs";
 import path from "path";
 
-const SchemaPath = path.join(__dirname, "..", "..", "..", "assets", "schemas.json");
+const SchemaPath = path.join(
+	__dirname,
+	"..",
+	"..",
+	"..",
+	"assets",
+	"schemas.json",
+);
 const schemas = JSON.parse(fs.readFileSync(SchemaPath, { encoding: "utf8" }));
 
 export const ajv = new Ajv({
@@ -14,7 +21,7 @@ export const ajv = new Ajv({
 	coerceTypes: true,
 	messages: true,
 	strict: true,
-	strictRequired: true
+	strictRequired: true,
 });
 
 addFormats(ajv);
@@ -41,7 +48,14 @@ export const normalizeBody = (body: any = {}) => {
 		} else {
 			for (const [key, value] of Object.entries(object)) {
 				if (value == null) {
-					if (key === "icon" || key === "avatar" || key === "banner" || key === "splash" || key === "discovery_splash") continue;
+					if (
+						key === "icon" ||
+						key === "avatar" ||
+						key === "banner" ||
+						key === "splash" ||
+						key === "discovery_splash"
+					)
+						continue;
 					delete object[key];
 				} else if (typeof value === "object") {
 					normalizeObject(value);
@@ -51,4 +65,4 @@ export const normalizeBody = (body: any = {}) => {
 	};
 	normalizeObject(body);
 	return body;
-};
\ No newline at end of file
+};
diff --git a/src/util/schemas/VanityUrlSchema.ts b/src/util/schemas/VanityUrlSchema.ts
index 28bf7f2b..4dd9b9da 100644
--- a/src/util/schemas/VanityUrlSchema.ts
+++ b/src/util/schemas/VanityUrlSchema.ts
@@ -4,4 +4,4 @@ export interface VanityUrlSchema {
 	 * @maxLength 20
 	 */
 	code?: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/VoiceIdentifySchema.ts b/src/util/schemas/VoiceIdentifySchema.ts
index d48de347..df023713 100644
--- a/src/util/schemas/VoiceIdentifySchema.ts
+++ b/src/util/schemas/VoiceIdentifySchema.ts
@@ -9,4 +9,4 @@ export interface VoiceIdentifySchema {
 		rid: string;
 		quality: number;
 	}[];
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/VoiceStateUpdateSchema.ts b/src/util/schemas/VoiceStateUpdateSchema.ts
index 5f805f4d..79e93b07 100644
--- a/src/util/schemas/VoiceStateUpdateSchema.ts
+++ b/src/util/schemas/VoiceStateUpdateSchema.ts
@@ -15,8 +15,8 @@ export const VoiceStateUpdateSchema = {
 	$channel_id: String,
 	self_mute: Boolean,
 	self_deaf: Boolean,
-	$self_video: Boolean,	//required in docs but bots don't always send it
+	$self_video: Boolean, //required in docs but bots don't always send it
 	$preferred_region: String,
 	$request_to_speak_timestamp: Date,
 	$suppress: Boolean,
-};
\ No newline at end of file
+};
diff --git a/src/util/schemas/VoiceVideoSchema.ts b/src/util/schemas/VoiceVideoSchema.ts
index 837ee1e7..0ba519e1 100644
--- a/src/util/schemas/VoiceVideoSchema.ts
+++ b/src/util/schemas/VoiceVideoSchema.ts
@@ -12,6 +12,6 @@ export interface VoiceVideoSchema {
 		rtx_ssrc: number;
 		max_bitrate: number;
 		max_framerate: number;
-		max_resolution: { type: string; width: number; height: number; };
+		max_resolution: { type: string; width: number; height: number };
 	}[];
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/WebhookCreateSchema.ts b/src/util/schemas/WebhookCreateSchema.ts
index c32b642d..99f6a12f 100644
--- a/src/util/schemas/WebhookCreateSchema.ts
+++ b/src/util/schemas/WebhookCreateSchema.ts
@@ -5,4 +5,4 @@ export interface WebhookCreateSchema {
 	 */
 	name: string;
 	avatar: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/WidgetModifySchema.ts b/src/util/schemas/WidgetModifySchema.ts
index 3c84b3a1..26d4504f 100644
--- a/src/util/schemas/WidgetModifySchema.ts
+++ b/src/util/schemas/WidgetModifySchema.ts
@@ -1,4 +1,4 @@
 export interface WidgetModifySchema {
 	enabled: boolean; // whether the widget is enabled
 	channel_id: string; // the widget channel id
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/index.ts b/src/util/schemas/index.ts
index f86552f3..ae80de71 100644
--- a/src/util/schemas/index.ts
+++ b/src/util/schemas/index.ts
@@ -38,4 +38,4 @@ export * from "./VoiceStateUpdateSchema";
 export * from "./VoiceVideoSchema";
 export * from "./IdentifySchema";
 export * from "./ActivitySchema";
-export * from "./LazyRequestSchema";
\ No newline at end of file
+export * from "./LazyRequestSchema";
diff --git a/src/util/util/ApiError.ts b/src/util/util/ApiError.ts
index f1a9b4f6..0fce6882 100644
--- a/src/util/util/ApiError.ts
+++ b/src/util/util/ApiError.ts
@@ -3,23 +3,34 @@ export class ApiError extends Error {
 		readonly message: string,
 		public readonly code: number,
 		public readonly httpStatus: number = 400,
-		public readonly defaultParams?: string[]
+		public readonly defaultParams?: string[],
 	) {
 		super(message);
 	}
 
 	withDefaultParams(): ApiError {
 		if (this.defaultParams)
-			return new ApiError(applyParamsToString(this.message, this.defaultParams), this.code, this.httpStatus);
+			return new ApiError(
+				applyParamsToString(this.message, this.defaultParams),
+				this.code,
+				this.httpStatus,
+			);
 		return this;
 	}
 
 	withParams(...params: (string | number)[]): ApiError {
-		return new ApiError(applyParamsToString(this.message, params), this.code, this.httpStatus);
+		return new ApiError(
+			applyParamsToString(this.message, params),
+			this.code,
+			this.httpStatus,
+		);
 	}
 }
 
-export function applyParamsToString(s: string, params: (string | number)[]): string {
+export function applyParamsToString(
+	s: string,
+	params: (string | number)[],
+): string {
 	let newString = s;
 	params.forEach((a) => {
 		newString = newString.replace("{}", "" + a);
diff --git a/src/util/util/AutoUpdate.ts b/src/util/util/AutoUpdate.ts
index fd65ecf5..769d959f 100644
--- a/src/util/util/AutoUpdate.ts
+++ b/src/util/util/AutoUpdate.ts
@@ -1,6 +1,6 @@
 import "missing-native-js-functions";
 import fetch from "node-fetch";
-import ProxyAgent from 'proxy-agent';
+import ProxyAgent from "proxy-agent";
 import readline from "readline";
 import fs from "fs/promises";
 import path from "path";
@@ -19,14 +19,17 @@ export function enableAutoUpdate(opts: {
 }) {
 	if (!opts.checkInterval) return;
 	var interval = 1000 * 60 * 60 * 24;
-	if (typeof opts.checkInterval === "number") opts.checkInterval = 1000 * interval;
+	if (typeof opts.checkInterval === "number")
+		opts.checkInterval = 1000 * interval;
 
 	const i = setInterval(async () => {
 		const currentVersion = await getCurrentVersion(opts.path);
 		const latestVersion = await getLatestVersion(opts.packageJsonLink);
 		if (currentVersion !== latestVersion) {
 			clearInterval(i);
-			console.log(`[Auto Update] Current version (${currentVersion}) is out of date, updating ...`);
+			console.log(
+				`[Auto Update] Current version (${currentVersion}) is out of date, updating ...`,
+			);
 			await download(opts.downloadUrl, opts.path);
 		}
 	}, interval);
@@ -43,7 +46,7 @@ export function enableAutoUpdate(opts: {
 					} else {
 						console.log(`[Auto update] aborted`);
 					}
-				}
+				},
 			);
 		}
 	});
@@ -65,7 +68,9 @@ async function download(url: string, dir: string) {
 
 async function getCurrentVersion(dir: string) {
 	try {
-		const content = await fs.readFile(path.join(dir, "package.json"), { encoding: "utf8" });
+		const content = await fs.readFile(path.join(dir, "package.json"), {
+			encoding: "utf8",
+		});
 		return JSON.parse(content).version;
 	} catch (error) {
 		throw new Error("[Auto update] couldn't get current version in " + dir);
@@ -76,7 +81,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()) as any; // TODO: types
 		return content.version;
 	} catch (error) {
 		throw new Error("[Auto update] check failed for " + url);
diff --git a/src/util/util/BannedWords.ts b/src/util/util/BannedWords.ts
index 891a5980..74a82efe 100644
--- a/src/util/util/BannedWords.ts
+++ b/src/util/util/BannedWords.ts
@@ -6,7 +6,9 @@ var words: string[];
 export const BannedWords = {
 	init: async function init() {
 		if (words) return words;
-		const file = (await fs.readFile(path.join(process.cwd(), "bannedWords"))).toString();
+		const file = (
+			await fs.readFile(path.join(process.cwd(), "bannedWords"))
+		).toString();
 		if (!file) {
 			words = [];
 			return [];
@@ -18,6 +20,6 @@ export const BannedWords = {
 	get: () => words,
 
 	find: (val: string) => {
-		return words.some(x => val.indexOf(x) != -1);
-	}
-};
\ No newline at end of file
+		return words.some((x) => val.indexOf(x) != -1);
+	},
+};
diff --git a/src/util/util/BitField.ts b/src/util/util/BitField.ts
index fb887e05..4e606660 100644
--- a/src/util/util/BitField.ts
+++ b/src/util/util/BitField.ts
@@ -3,7 +3,12 @@
 // https://github.com/discordjs/discord.js/blob/master/src/util/BitField.js
 // Apache License Version 2.0 Copyright 2015 - 2021 Amish Shah
 
-export type BitFieldResolvable = number | BigInt | BitField | string | BitFieldResolvable[];
+export type BitFieldResolvable =
+	| number
+	| BigInt
+	| BitField
+	| string
+	| BitFieldResolvable[];
 
 /**
  * Data structure that makes it easy to interact with a bitfield.
@@ -91,7 +96,8 @@ export class BitField {
 	 */
 	serialize() {
 		const serialized: Record<string, boolean> = {};
-		for (const [flag, bit] of Object.entries(BitField.FLAGS)) serialized[flag] = this.has(bit);
+		for (const [flag, bit] of Object.entries(BitField.FLAGS))
+			serialized[flag] = this.has(bit);
 		return serialized;
 	}
 
@@ -130,14 +136,21 @@ export class BitField {
 	static resolve(bit: BitFieldResolvable = BigInt(0)): bigint {
 		// @ts-ignore
 		const FLAGS = this.FLAGS || this.constructor?.FLAGS;
-		if ((typeof bit === "number" || typeof bit === "bigint") && bit >= BigInt(0)) return BigInt(bit);
+		if (
+			(typeof bit === "number" || typeof bit === "bigint") &&
+			bit >= BigInt(0)
+		)
+			return BigInt(bit);
 		if (bit instanceof BitField) return bit.bitfield;
 		if (Array.isArray(bit)) {
 			// @ts-ignore
 			const resolve = this.constructor?.resolve || this.resolve;
-			return bit.map((p) => resolve.call(this, p)).reduce((prev, p) => BigInt(prev) | BigInt(p), BigInt(0));
+			return bit
+				.map((p) => resolve.call(this, p))
+				.reduce((prev, p) => BigInt(prev) | BigInt(p), BigInt(0));
 		}
-		if (typeof bit === "string" && typeof FLAGS[bit] !== "undefined") return FLAGS[bit];
+		if (typeof bit === "string" && typeof FLAGS[bit] !== "undefined")
+			return FLAGS[bit];
 		throw new RangeError("BITFIELD_INVALID: " + bit);
 	}
 }
diff --git a/src/util/util/Categories.ts b/src/util/util/Categories.ts
index a3c69da7..cd706a8a 100644
--- a/src/util/util/Categories.ts
+++ b/src/util/util/Categories.ts
@@ -1 +1 @@
-//TODO: populate default discord categories + init, get and set methods
\ No newline at end of file
+//TODO: populate default discord categories + init, get and set methods
diff --git a/src/util/util/Config.ts b/src/util/util/Config.ts
index 31b8d97c..7fab7f90 100644
--- a/src/util/util/Config.ts
+++ b/src/util/util/Config.ts
@@ -1,5 +1,9 @@
 import "missing-native-js-functions";
-import { ConfigValue, ConfigEntity, DefaultConfigOptions } from "../entities/Config";
+import {
+	ConfigValue,
+	ConfigEntity,
+	DefaultConfigOptions,
+} from "../entities/Config";
 import path from "path";
 import fs from "fs";
 
@@ -42,7 +46,11 @@ export const Config = {
 function applyConfig(val: ConfigValue) {
 	async function apply(obj: any, key = ""): Promise<any> {
 		if (typeof obj === "object" && obj !== null)
-			return Promise.all(Object.keys(obj).map((k) => apply(obj[k], key ? `${key}_${k}` : k)));
+			return Promise.all(
+				Object.keys(obj).map((k) =>
+					apply(obj[k], key ? `${key}_${k}` : k),
+				),
+			);
 
 		let pair = pairs.find((x) => x.key === key);
 		if (!pair) pair = new ConfigEntity();
@@ -67,7 +75,8 @@ function pairsToConfig(pairs: ConfigEntity[]) {
 		let i = 0;
 
 		for (const key of keys) {
-			if (!isNaN(Number(key)) && !prevObj[prev]?.length) prevObj[prev] = obj = [];
+			if (!isNaN(Number(key)) && !prevObj[prev]?.length)
+				prevObj[prev] = obj = [];
 			if (i++ === keys.length - 1) obj[key] = p.value;
 			else if (!obj[key]) obj[key] = {};
 
diff --git a/src/util/util/Constants.ts b/src/util/util/Constants.ts
index 81a7165d..7c5b7dcb 100644
--- a/src/util/util/Constants.ts
+++ b/src/util/util/Constants.ts
@@ -77,9 +77,9 @@ export const VoiceOPCodes = {
 	RESUME: 7,
 	HELLO: 8,
 	RESUMED: 9,
-	CLIENT_CONNECT: 12,		// incorrect, op 12 is probably used for video
-	CLIENT_DISCONNECT: 13,	// incorrect
-	VERSION: 16,	//not documented
+	CLIENT_CONNECT: 12, // incorrect, op 12 is probably used for video
+	CLIENT_DISCONNECT: 13, // incorrect
+	VERSION: 16, //not documented
 };
 
 export const Events = {
@@ -160,7 +160,13 @@ export const ShardEvents = {
  * sidebar for more information.</warn>
  * @typedef {string} PartialType
  */
-export const PartialTypes = keyMirror(["USER", "CHANNEL", "GUILD_MEMBER", "MESSAGE", "REACTION"]);
+export const PartialTypes = keyMirror([
+	"USER",
+	"CHANNEL",
+	"GUILD_MEMBER",
+	"MESSAGE",
+	"REACTION",
+]);
 
 /**
  * The type of a websocket message event, e.g. `MESSAGE_CREATE`. Here are the available events:
@@ -291,7 +297,7 @@ export const MessageTypes = [
  * @typedef {string} SystemMessageType
  */
 export const SystemMessageTypes = MessageTypes.filter(
-	(type: string | null) => type && type !== "DEFAULT" && type !== "REPLY"
+	(type: string | null) => type && type !== "DEFAULT" && type !== "REPLY",
 );
 
 /**
@@ -305,7 +311,14 @@ export const SystemMessageTypes = MessageTypes.filter(
  * * COMPETING
  * @typedef {string} ActivityType
  */
-export const ActivityTypes = ["PLAYING", "STREAMING", "LISTENING", "WATCHING", "CUSTOM_STATUS", "COMPETING"];
+export const ActivityTypes = [
+	"PLAYING",
+	"STREAMING",
+	"LISTENING",
+	"WATCHING",
+	"CUSTOM_STATUS",
+	"COMPETING",
+];
 
 export const ChannelTypes = {
 	TEXT: 0,
@@ -361,7 +374,11 @@ export const Colors = {
  * * ALL_MEMBERS
  * @typedef {string} ExplicitContentFilterLevel
  */
-export const ExplicitContentFilterLevels = ["DISABLED", "MEMBERS_WITHOUT_ROLES", "ALL_MEMBERS"];
+export const ExplicitContentFilterLevels = [
+	"DISABLED",
+	"MEMBERS_WITHOUT_ROLES",
+	"ALL_MEMBERS",
+];
 
 /**
  * The value set for the verification levels for a guild:
@@ -372,7 +389,13 @@ export const ExplicitContentFilterLevels = ["DISABLED", "MEMBERS_WITHOUT_ROLES",
  * * VERY_HIGH
  * @typedef {string} VerificationLevel
  */
-export const VerificationLevels = ["NONE", "LOW", "MEDIUM", "HIGH", "VERY_HIGH"];
+export const VerificationLevels = [
+	"NONE",
+	"LOW",
+	"MEDIUM",
+	"HIGH",
+	"VERY_HIGH",
+];
 
 /**
  * An error encountered while performing an API request. Here are the potential errors:
@@ -517,7 +540,10 @@ export const VerificationLevels = ["NONE", "LOW", "MEDIUM", "HIGH", "VERY_HIGH"]
  */
 export const DiscordApiErrors = {
 	//https://discord.com/developers/docs/topics/opcodes-and-status-codes#json-json-error-codes
-	GENERAL_ERROR: new ApiError("General error (such as a malformed request body, amongst other things)", 0),
+	GENERAL_ERROR: new ApiError(
+		"General error (such as a malformed request body, amongst other things)",
+		0,
+	),
 	UNKNOWN_ACCOUNT: new ApiError("Unknown account", 10001),
 	UNKNOWN_APPLICATION: new ApiError("Unknown application", 10002),
 	UNKNOWN_CHANNEL: new ApiError("Unknown channel", 10003),
@@ -542,185 +568,410 @@ export const DiscordApiErrors = {
 	UNKNOWN_BUILD: new ApiError("Unknown build", 10030),
 	UNKNOWN_LOBBY: new ApiError("Unknown lobby", 10031),
 	UNKNOWN_BRANCH: new ApiError("Unknown branch", 10032),
-	UNKNOWN_STORE_DIRECTORY_LAYOUT: new ApiError("Unknown store directory layout", 10033),
+	UNKNOWN_STORE_DIRECTORY_LAYOUT: new ApiError(
+		"Unknown store directory layout",
+		10033,
+	),
 	UNKNOWN_REDISTRIBUTABLE: new ApiError("Unknown redistributable", 10036),
 	UNKNOWN_GIFT_CODE: new ApiError("Unknown gift code", 10038),
 	UNKNOWN_STREAM: new ApiError("Unknown stream", 10049),
-	UNKNOWN_PREMIUM_SERVER_SUBSCRIBE_COOLDOWN: new ApiError("Unknown premium server subscribe cooldown", 10050),
+	UNKNOWN_PREMIUM_SERVER_SUBSCRIBE_COOLDOWN: new ApiError(
+		"Unknown premium server subscribe cooldown",
+		10050,
+	),
 	UNKNOWN_GUILD_TEMPLATE: new ApiError("Unknown guild template", 10057),
-	UNKNOWN_DISCOVERABLE_SERVER_CATEGORY: new ApiError("Unknown discoverable server category", 10059),
+	UNKNOWN_DISCOVERABLE_SERVER_CATEGORY: new ApiError(
+		"Unknown discoverable server category",
+		10059,
+	),
 	UNKNOWN_STICKER: new ApiError("Unknown sticker", 10060),
 	UNKNOWN_INTERACTION: new ApiError("Unknown interaction", 10062),
-	UNKNOWN_APPLICATION_COMMAND: new ApiError("Unknown application command", 10063),
-	UNKNOWN_APPLICATION_COMMAND_PERMISSIONS: new ApiError("Unknown application command permissions", 10066),
+	UNKNOWN_APPLICATION_COMMAND: new ApiError(
+		"Unknown application command",
+		10063,
+	),
+	UNKNOWN_APPLICATION_COMMAND_PERMISSIONS: new ApiError(
+		"Unknown application command permissions",
+		10066,
+	),
 	UNKNOWN_STAGE_INSTANCE: new ApiError("Unknown Stage Instance", 10067),
-	UNKNOWN_GUILD_MEMBER_VERIFICATION_FORM: new ApiError("Unknown Guild Member Verification Form", 10068),
-	UNKNOWN_GUILD_WELCOME_SCREEN: new ApiError("Unknown Guild Welcome Screen", 10069),
-	UNKNOWN_GUILD_SCHEDULED_EVENT: new ApiError("Unknown Guild Scheduled Event", 10070),
-	UNKNOWN_GUILD_SCHEDULED_EVENT_USER: new ApiError("Unknown Guild Scheduled Event User", 10071),
-	BOT_PROHIBITED_ENDPOINT: new ApiError("Bots cannot use this endpoint", 20001),
+	UNKNOWN_GUILD_MEMBER_VERIFICATION_FORM: new ApiError(
+		"Unknown Guild Member Verification Form",
+		10068,
+	),
+	UNKNOWN_GUILD_WELCOME_SCREEN: new ApiError(
+		"Unknown Guild Welcome Screen",
+		10069,
+	),
+	UNKNOWN_GUILD_SCHEDULED_EVENT: new ApiError(
+		"Unknown Guild Scheduled Event",
+		10070,
+	),
+	UNKNOWN_GUILD_SCHEDULED_EVENT_USER: new ApiError(
+		"Unknown Guild Scheduled Event User",
+		10071,
+	),
+	BOT_PROHIBITED_ENDPOINT: new ApiError(
+		"Bots cannot use this endpoint",
+		20001,
+	),
 	BOT_ONLY_ENDPOINT: new ApiError("Only bots can use this endpoint", 20002),
 	EXPLICIT_CONTENT_CANNOT_BE_SENT_TO_RECIPIENT: new ApiError(
 		"Explicit content cannot be sent to the desired recipient(s)",
-		20009
+		20009,
 	),
 	ACTION_NOT_AUTHORIZED_ON_APPLICATION: new ApiError(
 		"You are not authorized to perform this action on this application",
-		20012
+		20012,
+	),
+	SLOWMODE_RATE_LIMIT: new ApiError(
+		"This action cannot be performed due to slowmode rate limit",
+		20016,
+	),
+	ONLY_OWNER: new ApiError(
+		"Only the owner of this account can perform this action",
+		20018,
+	),
+	ANNOUNCEMENT_RATE_LIMITS: new ApiError(
+		"This message cannot be edited due to announcement rate limits",
+		20022,
+	),
+	CHANNEL_WRITE_RATELIMIT: new ApiError(
+		"The channel you are writing has hit the write rate limit",
+		20028,
 	),
-	SLOWMODE_RATE_LIMIT: new ApiError("This action cannot be performed due to slowmode rate limit", 20016),
-	ONLY_OWNER: new ApiError("Only the owner of this account can perform this action", 20018),
-	ANNOUNCEMENT_RATE_LIMITS: new ApiError("This message cannot be edited due to announcement rate limits", 20022),
-	CHANNEL_WRITE_RATELIMIT: new ApiError("The channel you are writing has hit the write rate limit", 20028),
 	WORDS_NOT_ALLOWED: new ApiError(
 		"Your Stage topic, server name, server description, or channel names contain words that are not allowed",
-		20031
-	),
-	GUILD_PREMIUM_LEVEL_TOO_LOW: new ApiError("Guild premium subscription level too low", 20035),
-	MAXIMUM_GUILDS: new ApiError("Maximum number of guilds reached ({})", 30001, undefined, ["100"]),
-	MAXIMUM_FRIENDS: new ApiError("Maximum number of friends reached ({})", 30002, undefined, ["1000"]),
-	MAXIMUM_PINS: new ApiError("Maximum number of pins reached for the channel ({})", 30003, undefined, ["50"]),
-	MAXIMUM_NUMBER_OF_RECIPIENTS_REACHED: new ApiError("Maximum number of recipients reached ({})", 30004, undefined, [
-		"10",
-	]),
-	MAXIMUM_ROLES: new ApiError("Maximum number of guild roles reached ({})", 30005, undefined, ["250"]),
-	MAXIMUM_WEBHOOKS: new ApiError("Maximum number of webhooks reached ({})", 30007, undefined, ["10"]),
-	MAXIMUM_NUMBER_OF_EMOJIS_REACHED: new ApiError("Maximum number of emojis reached", 30008),
-	MAXIMUM_REACTIONS: new ApiError("Maximum number of reactions reached ({})", 30010, undefined, ["20"]),
-	MAXIMUM_CHANNELS: new ApiError("Maximum number of guild channels reached ({})", 30013, undefined, ["500"]),
-	MAXIMUM_ATTACHMENTS: new ApiError("Maximum number of attachments in a message reached ({})", 30015, undefined, [
-		"10",
-	]),
-	MAXIMUM_INVITES: new ApiError("Maximum number of invites reached ({})", 30016, undefined, ["1000"]),
-	MAXIMUM_ANIMATED_EMOJIS: new ApiError("Maximum number of animated emojis reached", 30018),
-	MAXIMUM_SERVER_MEMBERS: new ApiError("Maximum number of server members reached", 30019),
+		20031,
+	),
+	GUILD_PREMIUM_LEVEL_TOO_LOW: new ApiError(
+		"Guild premium subscription level too low",
+		20035,
+	),
+	MAXIMUM_GUILDS: new ApiError(
+		"Maximum number of guilds reached ({})",
+		30001,
+		undefined,
+		["100"],
+	),
+	MAXIMUM_FRIENDS: new ApiError(
+		"Maximum number of friends reached ({})",
+		30002,
+		undefined,
+		["1000"],
+	),
+	MAXIMUM_PINS: new ApiError(
+		"Maximum number of pins reached for the channel ({})",
+		30003,
+		undefined,
+		["50"],
+	),
+	MAXIMUM_NUMBER_OF_RECIPIENTS_REACHED: new ApiError(
+		"Maximum number of recipients reached ({})",
+		30004,
+		undefined,
+		["10"],
+	),
+	MAXIMUM_ROLES: new ApiError(
+		"Maximum number of guild roles reached ({})",
+		30005,
+		undefined,
+		["250"],
+	),
+	MAXIMUM_WEBHOOKS: new ApiError(
+		"Maximum number of webhooks reached ({})",
+		30007,
+		undefined,
+		["10"],
+	),
+	MAXIMUM_NUMBER_OF_EMOJIS_REACHED: new ApiError(
+		"Maximum number of emojis reached",
+		30008,
+	),
+	MAXIMUM_REACTIONS: new ApiError(
+		"Maximum number of reactions reached ({})",
+		30010,
+		undefined,
+		["20"],
+	),
+	MAXIMUM_CHANNELS: new ApiError(
+		"Maximum number of guild channels reached ({})",
+		30013,
+		undefined,
+		["500"],
+	),
+	MAXIMUM_ATTACHMENTS: new ApiError(
+		"Maximum number of attachments in a message reached ({})",
+		30015,
+		undefined,
+		["10"],
+	),
+	MAXIMUM_INVITES: new ApiError(
+		"Maximum number of invites reached ({})",
+		30016,
+		undefined,
+		["1000"],
+	),
+	MAXIMUM_ANIMATED_EMOJIS: new ApiError(
+		"Maximum number of animated emojis reached",
+		30018,
+	),
+	MAXIMUM_SERVER_MEMBERS: new ApiError(
+		"Maximum number of server members reached",
+		30019,
+	),
 	MAXIMUM_SERVER_CATEGORIES: new ApiError(
 		"Maximum number of server categories has been reached ({})",
 		30030,
 		undefined,
-		["5"]
+		["5"],
+	),
+	GUILD_ALREADY_HAS_TEMPLATE: new ApiError(
+		"Guild already has a template",
+		30031,
+	),
+	MAXIMUM_THREAD_PARTICIPANTS: new ApiError(
+		"Max number of thread participants has been reached",
+		30033,
 	),
-	GUILD_ALREADY_HAS_TEMPLATE: new ApiError("Guild already has a template", 30031),
-	MAXIMUM_THREAD_PARTICIPANTS: new ApiError("Max number of thread participants has been reached", 30033),
 	MAXIMUM_BANS_FOR_NON_GUILD_MEMBERS: new ApiError(
 		"Maximum number of bans for non-guild members have been exceeded",
-		30035
+		30035,
+	),
+	MAXIMUM_BANS_FETCHES: new ApiError(
+		"Maximum number of bans fetches has been reached",
+		30037,
 	),
-	MAXIMUM_BANS_FETCHES: new ApiError("Maximum number of bans fetches has been reached", 30037),
 	MAXIMUM_STICKERS: new ApiError("Maximum number of stickers reached", 30039),
-	MAXIMUM_PRUNE_REQUESTS: new ApiError("Maximum number of prune requests has been reached. Try again later", 30040),
-	UNAUTHORIZED: new ApiError("Unauthorized. Provide a valid token and try again", 40001),
+	MAXIMUM_PRUNE_REQUESTS: new ApiError(
+		"Maximum number of prune requests has been reached. Try again later",
+		30040,
+	),
+	UNAUTHORIZED: new ApiError(
+		"Unauthorized. Provide a valid token and try again",
+		40001,
+	),
 	ACCOUNT_VERIFICATION_REQUIRED: new ApiError(
 		"You need to verify your account in order to perform this action",
-		40002
+		40002,
+	),
+	OPENING_DIRECT_MESSAGES_TOO_FAST: new ApiError(
+		"You are opening direct messages too fast",
+		40003,
+	),
+	REQUEST_ENTITY_TOO_LARGE: new ApiError(
+		"Request entity too large. Try sending something smaller in size",
+		40005,
+	),
+	FEATURE_TEMPORARILY_DISABLED: new ApiError(
+		"This feature has been temporarily disabled server-side",
+		40006,
 	),
-	OPENING_DIRECT_MESSAGES_TOO_FAST: new ApiError("You are opening direct messages too fast", 40003),
-	REQUEST_ENTITY_TOO_LARGE: new ApiError("Request entity too large. Try sending something smaller in size", 40005),
-	FEATURE_TEMPORARILY_DISABLED: new ApiError("This feature has been temporarily disabled server-side", 40006),
 	USER_BANNED: new ApiError("The user is banned from this guild", 40007),
-	TARGET_USER_IS_NOT_CONNECTED_TO_VOICE: new ApiError("Target user is not connected to voice", 40032),
-	ALREADY_CROSSPOSTED: new ApiError("This message has already been crossposted", 40033),
-	APPLICATION_COMMAND_ALREADY_EXISTS: new ApiError("An application command with that name already exists", 40041),
+	TARGET_USER_IS_NOT_CONNECTED_TO_VOICE: new ApiError(
+		"Target user is not connected to voice",
+		40032,
+	),
+	ALREADY_CROSSPOSTED: new ApiError(
+		"This message has already been crossposted",
+		40033,
+	),
+	APPLICATION_COMMAND_ALREADY_EXISTS: new ApiError(
+		"An application command with that name already exists",
+		40041,
+	),
 	MISSING_ACCESS: new ApiError("Missing access", 50001),
 	INVALID_ACCOUNT_TYPE: new ApiError("Invalid account type", 50002),
-	CANNOT_EXECUTE_ON_DM: new ApiError("Cannot execute action on a DM channel", 50003),
+	CANNOT_EXECUTE_ON_DM: new ApiError(
+		"Cannot execute action on a DM channel",
+		50003,
+	),
 	EMBED_DISABLED: new ApiError("Guild widget disabled", 50004),
-	CANNOT_EDIT_MESSAGE_BY_OTHER: new ApiError("Cannot edit a message authored by another user", 50005),
-	CANNOT_SEND_EMPTY_MESSAGE: new ApiError("Cannot send an empty message", 50006),
-	CANNOT_MESSAGE_USER: new ApiError("Cannot send messages to this user", 50007),
-	CANNOT_SEND_MESSAGES_IN_VOICE_CHANNEL: new ApiError("Cannot send messages in a voice channel", 50008),
+	CANNOT_EDIT_MESSAGE_BY_OTHER: new ApiError(
+		"Cannot edit a message authored by another user",
+		50005,
+	),
+	CANNOT_SEND_EMPTY_MESSAGE: new ApiError(
+		"Cannot send an empty message",
+		50006,
+	),
+	CANNOT_MESSAGE_USER: new ApiError(
+		"Cannot send messages to this user",
+		50007,
+	),
+	CANNOT_SEND_MESSAGES_IN_VOICE_CHANNEL: new ApiError(
+		"Cannot send messages in a voice channel",
+		50008,
+	),
 	CHANNEL_VERIFICATION_LEVEL_TOO_HIGH: new ApiError(
 		"Channel verification level is too high for you to gain access",
-		50009
+		50009,
+	),
+	OAUTH2_APPLICATION_BOT_ABSENT: new ApiError(
+		"OAuth2 application does not have a bot",
+		50010,
+	),
+	MAXIMUM_OAUTH2_APPLICATIONS: new ApiError(
+		"OAuth2 application limit reached",
+		50011,
 	),
-	OAUTH2_APPLICATION_BOT_ABSENT: new ApiError("OAuth2 application does not have a bot", 50010),
-	MAXIMUM_OAUTH2_APPLICATIONS: new ApiError("OAuth2 application limit reached", 50011),
 	INVALID_OAUTH_STATE: new ApiError("Invalid OAuth2 state", 50012),
-	MISSING_PERMISSIONS: new ApiError("You lack permissions to perform that action ({})", 50013, undefined, [""]),
-	INVALID_AUTHENTICATION_TOKEN: new ApiError("Invalid authentication token provided", 50014),
+	MISSING_PERMISSIONS: new ApiError(
+		"You lack permissions to perform that action ({})",
+		50013,
+		undefined,
+		[""],
+	),
+	INVALID_AUTHENTICATION_TOKEN: new ApiError(
+		"Invalid authentication token provided",
+		50014,
+	),
 	NOTE_TOO_LONG: new ApiError("Note was too long", 50015),
 	INVALID_BULK_DELETE_QUANTITY: new ApiError(
 		"Provided too few or too many messages to delete. Must provide at least {} and fewer than {} messages to delete",
 		50016,
 		undefined,
-		["2", "100"]
+		["2", "100"],
 	),
 	CANNOT_PIN_MESSAGE_IN_OTHER_CHANNEL: new ApiError(
 		"A message can only be pinned to the channel it was sent in",
-		50019
-	),
-	INVALID_OR_TAKEN_INVITE_CODE: new ApiError("Invite code was either invalid or taken", 50020),
-	CANNOT_EXECUTE_ON_SYSTEM_MESSAGE: new ApiError("Cannot execute action on a system message", 50021),
-	CANNOT_EXECUTE_ON_THIS_CHANNEL_TYPE: new ApiError("Cannot execute action on this channel type", 50024),
-	INVALID_OAUTH_TOKEN: new ApiError("Invalid OAuth2 access token provided", 50025),
-	MISSING_REQUIRED_OAUTH2_SCOPE: new ApiError("Missing required OAuth2 scope", 50026),
-	INVALID_WEBHOOK_TOKEN_PROVIDED: new ApiError("Invalid webhook token provided", 50027),
+		50019,
+	),
+	INVALID_OR_TAKEN_INVITE_CODE: new ApiError(
+		"Invite code was either invalid or taken",
+		50020,
+	),
+	CANNOT_EXECUTE_ON_SYSTEM_MESSAGE: new ApiError(
+		"Cannot execute action on a system message",
+		50021,
+	),
+	CANNOT_EXECUTE_ON_THIS_CHANNEL_TYPE: new ApiError(
+		"Cannot execute action on this channel type",
+		50024,
+	),
+	INVALID_OAUTH_TOKEN: new ApiError(
+		"Invalid OAuth2 access token provided",
+		50025,
+	),
+	MISSING_REQUIRED_OAUTH2_SCOPE: new ApiError(
+		"Missing required OAuth2 scope",
+		50026,
+	),
+	INVALID_WEBHOOK_TOKEN_PROVIDED: new ApiError(
+		"Invalid webhook token provided",
+		50027,
+	),
 	INVALID_ROLE: new ApiError("Invalid role", 50028),
 	INVALID_RECIPIENT: new ApiError("Invalid Recipient(s)", 50033),
-	BULK_DELETE_MESSAGE_TOO_OLD: new ApiError("A message provided was too old to bulk delete", 50034),
+	BULK_DELETE_MESSAGE_TOO_OLD: new ApiError(
+		"A message provided was too old to bulk delete",
+		50034,
+	),
 	INVALID_FORM_BODY: new ApiError(
 		"Invalid form body (returned for both application/json and multipart/form-data bodies), or invalid Content-Type provided",
-		50035
+		50035,
 	),
 	INVITE_ACCEPTED_TO_GUILD_NOT_CONTAINING_BOT: new ApiError(
 		"An invite was accepted to a guild the application's bot is not in",
-		50036
+		50036,
 	),
 	INVALID_API_VERSION: new ApiError("Invalid API version provided", 50041),
-	FILE_EXCEEDS_MAXIMUM_SIZE: new ApiError("File uploaded exceeds the maximum size", 50045),
+	FILE_EXCEEDS_MAXIMUM_SIZE: new ApiError(
+		"File uploaded exceeds the maximum size",
+		50045,
+	),
 	INVALID_FILE_UPLOADED: new ApiError("Invalid file uploaded", 50046),
-	CANNOT_SELF_REDEEM_GIFT: new ApiError("Cannot self-redeem this gift", 50054),
-	PAYMENT_SOURCE_REQUIRED: new ApiError("Payment source required to redeem gift", 50070),
+	CANNOT_SELF_REDEEM_GIFT: new ApiError(
+		"Cannot self-redeem this gift",
+		50054,
+	),
+	PAYMENT_SOURCE_REQUIRED: new ApiError(
+		"Payment source required to redeem gift",
+		50070,
+	),
 	CANNOT_DELETE_COMMUNITY_REQUIRED_CHANNEL: new ApiError(
 		"Cannot delete a channel required for Community guilds",
-		50074
+		50074,
 	),
 	INVALID_STICKER_SENT: new ApiError("Invalid sticker sent", 50081),
 	CANNOT_EDIT_ARCHIVED_THREAD: new ApiError(
 		"Tried to perform an operation on an archived thread, such as editing a message or adding a user to the thread",
-		50083
+		50083,
+	),
+	INVALID_THREAD_NOTIFICATION_SETTINGS: new ApiError(
+		"Invalid thread notification settings",
+		50084,
 	),
-	INVALID_THREAD_NOTIFICATION_SETTINGS: new ApiError("Invalid thread notification settings", 50084),
 	BEFORE_EARLIER_THAN_THREAD_CREATION_DATE: new ApiError(
 		"before value is earlier than the thread creation date",
-		50085
+		50085,
+	),
+	SERVER_NOT_AVAILABLE_IN_YOUR_LOCATION: new ApiError(
+		"This server is not available in your location",
+		50095,
 	),
-	SERVER_NOT_AVAILABLE_IN_YOUR_LOCATION: new ApiError("This server is not available in your location", 50095),
 	SERVER_NEEDS_MONETIZATION_ENABLED: new ApiError(
 		"This server needs monetization enabled in order to perform this action",
-		50097
+		50097,
+	),
+	TWO_FACTOR_REQUIRED: new ApiError(
+		"Two factor is required for this operation",
+		60003,
+	),
+	NO_USERS_WITH_DISCORDTAG_EXIST: new ApiError(
+		"No users with DiscordTag exist",
+		80004,
 	),
-	TWO_FACTOR_REQUIRED: new ApiError("Two factor is required for this operation", 60003),
-	NO_USERS_WITH_DISCORDTAG_EXIST: new ApiError("No users with DiscordTag exist", 80004),
 	REACTION_BLOCKED: new ApiError("Reaction was blocked", 90001),
-	RESOURCE_OVERLOADED: new ApiError("API resource is currently overloaded. Try again a little later", 130000),
+	RESOURCE_OVERLOADED: new ApiError(
+		"API resource is currently overloaded. Try again a little later",
+		130000,
+	),
 	STAGE_ALREADY_OPEN: new ApiError("The Stage is already open", 150006),
-	THREAD_ALREADY_CREATED_FOR_THIS_MESSAGE: new ApiError("A thread has already been created for this message", 160004),
+	THREAD_ALREADY_CREATED_FOR_THIS_MESSAGE: new ApiError(
+		"A thread has already been created for this message",
+		160004,
+	),
 	THREAD_IS_LOCKED: new ApiError("Thread is locked", 160005),
-	MAXIMUM_NUMBER_OF_ACTIVE_THREADS: new ApiError("Maximum number of active threads reached", 160006),
+	MAXIMUM_NUMBER_OF_ACTIVE_THREADS: new ApiError(
+		"Maximum number of active threads reached",
+		160006,
+	),
 	MAXIMUM_NUMBER_OF_ACTIVE_ANNOUNCEMENT_THREADS: new ApiError(
 		"Maximum number of active announcement threads reached",
-		160007
+		160007,
+	),
+	INVALID_JSON_FOR_UPLOADED_LOTTIE_FILE: new ApiError(
+		"Invalid JSON for uploaded Lottie file",
+		170001,
 	),
-	INVALID_JSON_FOR_UPLOADED_LOTTIE_FILE: new ApiError("Invalid JSON for uploaded Lottie file", 170001),
 	LOTTIES_CANNOT_CONTAIN_RASTERIZED_IMAGES: new ApiError(
 		"Uploaded Lotties cannot contain rasterized images such as PNG or JPEG",
-		170002
+		170002,
+	),
+	STICKER_MAXIMUM_FRAMERATE: new ApiError(
+		"Sticker maximum framerate exceeded",
+		170003,
+	),
+	STICKER_MAXIMUM_FRAME_COUNT: new ApiError(
+		"Sticker frame count exceeds maximum of {} frames",
+		170004,
+		undefined,
+		["1000"],
+	),
+	LOTTIE_ANIMATION_MAXIMUM_DIMENSIONS: new ApiError(
+		"Lottie animation maximum dimensions exceeded",
+		170005,
 	),
-	STICKER_MAXIMUM_FRAMERATE: new ApiError("Sticker maximum framerate exceeded", 170003),
-	STICKER_MAXIMUM_FRAME_COUNT: new ApiError("Sticker frame count exceeds maximum of {} frames", 170004, undefined, [
-		"1000",
-	]),
-	LOTTIE_ANIMATION_MAXIMUM_DIMENSIONS: new ApiError("Lottie animation maximum dimensions exceeded", 170005),
 	STICKER_FRAME_RATE_TOO_SMALL_OR_TOO_LARGE: new ApiError(
 		"Sticker frame rate is either too small or too large",
-		170006
+		170006,
 	),
 	STICKER_ANIMATION_DURATION_MAXIMUM: new ApiError(
 		"Sticker animation duration exceeds maximum of {} seconds",
 		170007,
 		undefined,
-		["5"]
+		["5"],
 	),
 
 	//Other errors
@@ -731,26 +982,92 @@ export const DiscordApiErrors = {
  * An error encountered while performing an API request (Fosscord only). Here are the potential errors:
  */
 export const FosscordApiErrors = {
-	MANUALLY_TRIGGERED_ERROR: new ApiError("This is an artificial error", 1, 500),
-	PREMIUM_DISABLED_FOR_GUILD: new ApiError("This guild cannot be boosted", 25001),
-	NO_FURTHER_PREMIUM: new ApiError("This guild does not receive further boosts", 25002),
-	GUILD_PREMIUM_DISABLED_FOR_YOU: new ApiError("This guild cannot be boosted by you", 25003, 403),
+	MANUALLY_TRIGGERED_ERROR: new ApiError(
+		"This is an artificial error",
+		1,
+		500,
+	),
+	PREMIUM_DISABLED_FOR_GUILD: new ApiError(
+		"This guild cannot be boosted",
+		25001,
+	),
+	NO_FURTHER_PREMIUM: new ApiError(
+		"This guild does not receive further boosts",
+		25002,
+	),
+	GUILD_PREMIUM_DISABLED_FOR_YOU: new ApiError(
+		"This guild cannot be boosted by you",
+		25003,
+		403,
+	),
 	CANNOT_FRIEND_SELF: new ApiError("Cannot friend oneself", 25009),
-	USER_SPECIFIC_INVITE_WRONG_RECIPIENT: new ApiError("This invite is not meant for you", 25010),
+	USER_SPECIFIC_INVITE_WRONG_RECIPIENT: new ApiError(
+		"This invite is not meant for you",
+		25010,
+	),
 	USER_SPECIFIC_INVITE_FAILED: new ApiError("Failed to invite user", 25011),
-	CANNOT_MODIFY_USER_GROUP: new ApiError("This user cannot manipulate this group", 25050, 403),
-	CANNOT_REMOVE_SELF_FROM_GROUP: new ApiError("This user cannot remove oneself from user group", 25051),
-	CANNOT_BAN_OPERATOR: new ApiError("Non-OPERATOR cannot ban OPERATOR from instance", 25052),
-	CANNOT_LEAVE_GUILD: new ApiError("You are not allowed to leave guilds that you joined by yourself", 25059, 403),
-	EDITS_DISABLED: new ApiError("You are not allowed to edit your own messages", 25060, 403),
-	DELETE_MESSAGE_DISABLED: new ApiError("You are not allowed to delete your own messages", 25061, 403),
-	FEATURE_PERMANENTLY_DISABLED: new ApiError("This feature has been disabled server-side", 45006, 501),
-	MISSING_RIGHTS: new ApiError("You lack rights to perform that action ({})", 50013, undefined, [""]),
-	CANNOT_REPLACE_BY_BACKFILL: new ApiError("Cannot backfill to message ID that already exists", 55002, 409),
-	CANNOT_BACKFILL_TO_THE_FUTURE: new ApiError("You cannot backfill messages in the future", 55003),
-	CANNOT_GRANT_PERMISSIONS_EXCEEDING_RIGHTS: new ApiError("You cannot grant permissions exceeding your own rights", 50050),
-	ROUTES_LOOPING: new ApiError("Loops in the route definition ({})", 50060, undefined, [""]),
-	CANNOT_REMOVE_ROUTE: new ApiError("Cannot remove message route while it is in effect and being used", 50061),
+	CANNOT_MODIFY_USER_GROUP: new ApiError(
+		"This user cannot manipulate this group",
+		25050,
+		403,
+	),
+	CANNOT_REMOVE_SELF_FROM_GROUP: new ApiError(
+		"This user cannot remove oneself from user group",
+		25051,
+	),
+	CANNOT_BAN_OPERATOR: new ApiError(
+		"Non-OPERATOR cannot ban OPERATOR from instance",
+		25052,
+	),
+	CANNOT_LEAVE_GUILD: new ApiError(
+		"You are not allowed to leave guilds that you joined by yourself",
+		25059,
+		403,
+	),
+	EDITS_DISABLED: new ApiError(
+		"You are not allowed to edit your own messages",
+		25060,
+		403,
+	),
+	DELETE_MESSAGE_DISABLED: new ApiError(
+		"You are not allowed to delete your own messages",
+		25061,
+		403,
+	),
+	FEATURE_PERMANENTLY_DISABLED: new ApiError(
+		"This feature has been disabled server-side",
+		45006,
+		501,
+	),
+	MISSING_RIGHTS: new ApiError(
+		"You lack rights to perform that action ({})",
+		50013,
+		undefined,
+		[""],
+	),
+	CANNOT_REPLACE_BY_BACKFILL: new ApiError(
+		"Cannot backfill to message ID that already exists",
+		55002,
+		409,
+	),
+	CANNOT_BACKFILL_TO_THE_FUTURE: new ApiError(
+		"You cannot backfill messages in the future",
+		55003,
+	),
+	CANNOT_GRANT_PERMISSIONS_EXCEEDING_RIGHTS: new ApiError(
+		"You cannot grant permissions exceeding your own rights",
+		50050,
+	),
+	ROUTES_LOOPING: new ApiError(
+		"Loops in the route definition ({})",
+		50060,
+		undefined,
+		[""],
+	),
+	CANNOT_REMOVE_ROUTE: new ApiError(
+		"Cannot remove message route while it is in effect and being used",
+		50061,
+	),
 };
 
 /**
@@ -769,11 +1086,7 @@ export const DefaultMessageNotifications = ["ALL", "MENTIONS", "MUTED"];
  * * INSERTED (Fosscord extension)
  * @typedef {string} MembershipStates
  */
-export const MembershipStates = [
-	"INSERTED",
-	"INVITED",
-	"ACCEPTED",
-];
+export const MembershipStates = ["INSERTED", "INVITED", "ACCEPTED"];
 
 /**
  * The value set for a webhook's type:
@@ -782,15 +1095,10 @@ export const MembershipStates = [
  * * Custom (Fosscord extension)
  * @typedef {string} WebhookTypes
  */
-export const WebhookTypes = [
-	"Custom",
-	"Incoming",
-	"Channel Follower",
-];
+export const WebhookTypes = ["Custom", "Incoming", "Channel Follower"];
 
 function keyMirror(arr: string[]) {
 	let 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 ddbea57d..e96be6c4 100644
--- a/src/util/util/Database.ts
+++ b/src/util/util/Database.ts
@@ -9,7 +9,8 @@ import { yellow, green, red } from "picocolors";
 // We want to generate all id's with Snowflakes that's why we have our own BaseEntity class
 
 var dbConnection: DataSource | undefined;
-let dbConnectionString = process.env.DATABASE || path.join(process.cwd(), "database.db");
+let dbConnectionString =
+	process.env.DATABASE || path.join(process.cwd(), "database.db");
 
 export function getDatabase(): DataSource | null {
 	// if (!dbConnection) throw new Error("Tried to get database before it was initialised");
@@ -20,18 +21,24 @@ export function getDatabase(): DataSource | null {
 export async function initDatabase(): Promise<DataSource> {
 	if (dbConnection) return dbConnection;
 
-	const type = dbConnectionString.includes("://") ? dbConnectionString.split(":")[0]?.replace("+srv", "") : "sqlite";
+	const type = dbConnectionString.includes("://")
+		? dbConnectionString.split(":")[0]?.replace("+srv", "")
+		: "sqlite";
 	const isSqlite = type.includes("sqlite");
 
 	console.log(`[Database] ${yellow(`connecting to ${type} db`)}`);
 	if (isSqlite) {
-		console.log(`[Database] ${red(`You are running sqlite! Please keep in mind that we recommend setting up a dedicated database!`)}`);
+		console.log(
+			`[Database] ${red(
+				`You are running sqlite! Please keep in mind that we recommend setting up a dedicated database!`,
+			)}`,
+		);
 	}
 
 	const dataSource = new DataSource({
 		//@ts-ignore
 		type,
-		charset: 'utf8mb4',
+		charset: "utf8mb4",
 		url: isSqlite ? undefined : dbConnectionString,
 		database: isSqlite ? dbConnectionString : undefined,
 		entities: ["dist/util/entities/*.js"],
diff --git a/src/util/util/Email.ts b/src/util/util/Email.ts
index 6885da33..c98ccff0 100644
--- a/src/util/util/Email.ts
+++ b/src/util/util/Email.ts
@@ -15,7 +15,7 @@ export function adjustEmail(email?: string): string | undefined {
 		// 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";
 	}
-	
+
 	if (domain === "google.com") {
 		// replace .dots and +alternatives -> Google Staff GMail Dot Trick
 		let v = user.replace(/[.]|(\+.*)/g, "") + "@google.com";
diff --git a/src/util/util/Event.ts b/src/util/util/Event.ts
index 20a638a0..c81de951 100644
--- a/src/util/util/Event.ts
+++ b/src/util/util/Event.ts
@@ -5,15 +5,27 @@ import { EVENT, Event } from "../interfaces";
 export const events = new EventEmitter();
 
 export async function emitEvent(payload: Omit<Event, "created_at">) {
-	const id = (payload.channel_id || payload.user_id || payload.guild_id) as string;
+	const id = (payload.channel_id ||
+		payload.user_id ||
+		payload.guild_id) as string;
 	if (!id) return console.error("event doesn't contain any id", payload);
 
 	if (RabbitMQ.connection) {
-		const data = typeof payload.data === "object" ? JSON.stringify(payload.data) : payload.data; // use rabbitmq for event transmission
-		await RabbitMQ.channel?.assertExchange(id, "fanout", { durable: false });
+		const data =
+			typeof payload.data === "object"
+				? JSON.stringify(payload.data)
+				: payload.data; // use rabbitmq for event transmission
+		await RabbitMQ.channel?.assertExchange(id, "fanout", {
+			durable: false,
+		});
 
 		// assertQueue isn't needed, because a queue will automatically created if it doesn't exist
-		const successful = RabbitMQ.channel?.publish(id, "", Buffer.from(`${data}`), { type: payload.event });
+		const successful = RabbitMQ.channel?.publish(
+			id,
+			"",
+			Buffer.from(`${data}`),
+			{ type: payload.event },
+		);
 		if (!successful) throw new Error("failed to send event");
 	} else if (process.env.EVENT_TRANSMISSION === "process") {
 		process.send?.({ type: "event", event: payload, id } as ProcessEvent);
@@ -48,10 +60,19 @@ export interface ProcessEvent {
 	id: string;
 }
 
-export async function listenEvent(event: string, callback: (event: EventOpts) => any, opts?: ListenEventOpts) {
+export async function listenEvent(
+	event: string,
+	callback: (event: EventOpts) => any,
+	opts?: ListenEventOpts,
+) {
 	if (RabbitMQ.connection) {
-		// @ts-ignore
-		return rabbitListen(opts?.channel || RabbitMQ.channel, event, callback, { acknowledge: opts?.acknowledge });
+		return rabbitListen(
+			// @ts-ignore
+			opts?.channel || RabbitMQ.channel,
+			event,
+			callback,
+			{ acknowledge: opts?.acknowledge },
+		);
 	} else if (process.env.EVENT_TRANSMISSION === "process") {
 		const cancel = () => {
 			process.removeListener("message", listener);
@@ -59,7 +80,9 @@ export async function listenEvent(event: string, callback: (event: EventOpts) =>
 		};
 
 		const listener = (msg: ProcessEvent) => {
-			msg.type === "event" && msg.id === event && callback({ ...msg.event, cancel });
+			msg.type === "event" &&
+				msg.id === event &&
+				callback({ ...msg.event, cancel });
 		};
 
 		//@ts-ignore apparently theres no function addListener with this signature
@@ -84,10 +107,13 @@ async function rabbitListen(
 	channel: Channel,
 	id: string,
 	callback: (event: EventOpts) => any,
-	opts?: { acknowledge?: boolean }
+	opts?: { acknowledge?: boolean },
 ) {
 	await channel.assertExchange(id, "fanout", { durable: false });
-	const q = await channel.assertQueue("", { exclusive: true, autoDelete: true });
+	const q = await channel.assertQueue("", {
+		exclusive: true,
+		autoDelete: true,
+	});
 
 	const cancel = () => {
 		channel.cancel(q.queue);
@@ -116,7 +142,7 @@ async function rabbitListen(
 		},
 		{
 			noAck: !opts?.acknowledge,
-		}
+		},
 	);
 
 	return cancel;
diff --git a/src/util/util/FieldError.ts b/src/util/util/FieldError.ts
index 406b33e8..24818fed 100644
--- a/src/util/util/FieldError.ts
+++ b/src/util/util/FieldError.ts
@@ -1,6 +1,8 @@
 import "missing-native-js-functions";
 
-export function FieldErrors(fields: Record<string, { code?: string; message: string }>) {
+export function FieldErrors(
+	fields: Record<string, { code?: string; message: string }>,
+) {
 	return new FieldError(
 		50035,
 		"Invalid Form Body",
@@ -11,7 +13,7 @@ export function FieldErrors(fields: Record<string, { code?: string; message: str
 					code: code || "BASE_TYPE_INVALID",
 				},
 			],
-		}))
+		})),
 	);
 }
 
@@ -19,7 +21,11 @@ export function FieldErrors(fields: Record<string, { code?: string; message: str
 // Ensure you use the proper content type (image/jpeg, image/png, image/gif) that matches the image data being provided.
 
 export class FieldError extends Error {
-	constructor(public code: string | number, public message: string, public errors?: any) {
+	constructor(
+		public code: string | number,
+		public message: string,
+		public errors?: any,
+	) {
 		super(message);
 	}
 }
diff --git a/src/util/util/Intents.ts b/src/util/util/Intents.ts
index 1e840b76..b9f4d65a 100644
--- a/src/util/util/Intents.ts
+++ b/src/util/util/Intents.ts
@@ -22,13 +22,12 @@ export class Intents extends BitField {
 		GUILD_POLICY_EXECUTION: BigInt(1) << BigInt(21), // guild policy execution
 		LIVE_MESSAGE_COMPOSITION: BigInt(1) << BigInt(32), // allow composing messages using the gateway
 		GUILD_ROUTES: BigInt(1) << BigInt(41), // message routes affecting the guild
-		DIRECT_MESSAGES_THREADS: BigInt(1) << BigInt(42),  // direct message threads
+		DIRECT_MESSAGES_THREADS: BigInt(1) << BigInt(42), // direct message threads
 		JUMBO_EVENTS: BigInt(1) << BigInt(43), // jumbo events (size limits to be defined later)
 		LOBBIES: BigInt(1) << BigInt(44), // lobbies
-		INSTANCE_ROUTES: BigInt(1) << BigInt(60), // all message route changes 
+		INSTANCE_ROUTES: BigInt(1) << BigInt(60), // all message route changes
 		INSTANCE_GUILD_CHANGES: BigInt(1) << BigInt(61), // all guild create, guild object patch, split, merge and delete events
 		INSTANCE_POLICY_UPDATES: BigInt(1) << BigInt(62), // all instance policy updates
-		INSTANCE_USER_UPDATES: BigInt(1) << BigInt(63) // all instance user updates
+		INSTANCE_USER_UPDATES: BigInt(1) << BigInt(63), // all instance user updates
 	};
 }
-
diff --git a/src/util/util/InvisibleCharacters.ts b/src/util/util/InvisibleCharacters.ts
index a48cfab0..da295d68 100644
--- a/src/util/util/InvisibleCharacters.ts
+++ b/src/util/util/InvisibleCharacters.ts
@@ -1,56 +1,56 @@
-// List from https://invisible-characters.com/

-export const InvisibleCharacters = [

-	'\u{9}',			//Tab

-	//'\u{20}',			//Space	//categories can have spaces in them

-	'\u{ad}',			//Soft hyphen

-	'\u{34f}',			//Combining grapheme joiner

-	'\u{61c}',			//Arabic letter mark

-	'\u{115f}',			//Hangul choseong filler

-	'\u{1160}',			//Hangul jungseong filler

-	'\u{17b4}',			//Khmer vowel inherent AQ

-	'\u{17b5}',			//Khmer vowel inherent AA

-	'\u{180e}',			//Mongolian vowel separator

-	'\u{2000}',			//En quad

-	'\u{2001}',			//Em quad

-	'\u{2002}',			//En space

-	'\u{2003}',			//Em space

-	'\u{2004}',			//Three-per-em space

-	'\u{2005}',			//Four-per-em space

-	'\u{2006}',			//Six-per-em space

-	'\u{2007}',			//Figure space

-	'\u{2008}',			//Punctuation space

-	'\u{2009}',			//Thin space

-	'\u{200a}',			//Hair space

-	'\u{200b}',			//Zero width space

-	'\u{200c}',			//Zero width non-joiner

-	'\u{200d}',			//Zero width joiner

-	'\u{200e}',			//Left-to-right mark

-	'\u{200f}',			//Right-to-left mark

-	'\u{202f}',			//Narrow no-break space

-	'\u{205f}',			//Medium mathematical space

-	'\u{2060}',			//Word joiner

-	'\u{2061}',			//Function application

-	'\u{2062}',			//Invisible times

-	'\u{2063}',			//Invisible separator

-	'\u{2064}',			//Invisible plus

-	'\u{206a}',			//Inhibit symmetric swapping

-	'\u{206b}',			//Activate symmetric swapping

-	'\u{206c}',			//Inhibit arabic form shaping

-	'\u{206d}',			//Activate arabic form shaping

-	'\u{206e}',			//National digit shapes

-	'\u{206f}',			//Nominal digit shapes

-	'\u{3000}',			//Ideographic space

-	'\u{2800}',			//Braille pattern blank

-	'\u{3164}',			//Hangul filler

-	'\u{feff}',			//Zero width no-break space

-	'\u{ffa0}',			//Haldwidth hangul filler

-	'\u{1d159}',		//Musical symbol null notehead

-	'\u{1d173}',		//Musical symbol begin beam 

-	'\u{1d174}',		//Musical symbol end beam

-	'\u{1d175}',		//Musical symbol begin tie

-	'\u{1d176}',		//Musical symbol end tie

-	'\u{1d177}',		//Musical symbol begin slur

-	'\u{1d178}',		//Musical symbol end slur

-	'\u{1d179}',		//Musical symbol begin phrase

-	'\u{1d17a}'			//Musical symbol end phrase

-]; 
\ No newline at end of file
+// List from https://invisible-characters.com/
+export const InvisibleCharacters = [
+	"\u{9}", //Tab
+	//'\u{20}',			//Space	//categories can have spaces in them
+	"\u{ad}", //Soft hyphen
+	"\u{34f}", //Combining grapheme joiner
+	"\u{61c}", //Arabic letter mark
+	"\u{115f}", //Hangul choseong filler
+	"\u{1160}", //Hangul jungseong filler
+	"\u{17b4}", //Khmer vowel inherent AQ
+	"\u{17b5}", //Khmer vowel inherent AA
+	"\u{180e}", //Mongolian vowel separator
+	"\u{2000}", //En quad
+	"\u{2001}", //Em quad
+	"\u{2002}", //En space
+	"\u{2003}", //Em space
+	"\u{2004}", //Three-per-em space
+	"\u{2005}", //Four-per-em space
+	"\u{2006}", //Six-per-em space
+	"\u{2007}", //Figure space
+	"\u{2008}", //Punctuation space
+	"\u{2009}", //Thin space
+	"\u{200a}", //Hair space
+	"\u{200b}", //Zero width space
+	"\u{200c}", //Zero width non-joiner
+	"\u{200d}", //Zero width joiner
+	"\u{200e}", //Left-to-right mark
+	"\u{200f}", //Right-to-left mark
+	"\u{202f}", //Narrow no-break space
+	"\u{205f}", //Medium mathematical space
+	"\u{2060}", //Word joiner
+	"\u{2061}", //Function application
+	"\u{2062}", //Invisible times
+	"\u{2063}", //Invisible separator
+	"\u{2064}", //Invisible plus
+	"\u{206a}", //Inhibit symmetric swapping
+	"\u{206b}", //Activate symmetric swapping
+	"\u{206c}", //Inhibit arabic form shaping
+	"\u{206d}", //Activate arabic form shaping
+	"\u{206e}", //National digit shapes
+	"\u{206f}", //Nominal digit shapes
+	"\u{3000}", //Ideographic space
+	"\u{2800}", //Braille pattern blank
+	"\u{3164}", //Hangul filler
+	"\u{feff}", //Zero width no-break space
+	"\u{ffa0}", //Haldwidth hangul filler
+	"\u{1d159}", //Musical symbol null notehead
+	"\u{1d173}", //Musical symbol begin beam
+	"\u{1d174}", //Musical symbol end beam
+	"\u{1d175}", //Musical symbol begin tie
+	"\u{1d176}", //Musical symbol end tie
+	"\u{1d177}", //Musical symbol begin slur
+	"\u{1d178}", //Musical symbol end slur
+	"\u{1d179}", //Musical symbol begin phrase
+	"\u{1d17a}", //Musical symbol end phrase
+];
diff --git a/src/util/util/Permissions.ts b/src/util/util/Permissions.ts
index a432af76..0c12487e 100644
--- a/src/util/util/Permissions.ts
+++ b/src/util/util/Permissions.ts
@@ -1,6 +1,12 @@
 // https://github.com/discordjs/discord.js/blob/master/src/util/Permissions.js
 // Apache License Version 2.0 Copyright 2015 - 2021 Amish Shah
-import { Channel, ChannelPermissionOverwrite, Guild, Member, Role } from "../entities";
+import {
+	Channel,
+	ChannelPermissionOverwrite,
+	Guild,
+	Member,
+	Role,
+} from "../entities";
 import { BitField } from "./BitField";
 import "missing-native-js-functions";
 import { BitFieldResolvable, BitFlag } from "./BitField";
@@ -13,7 +19,12 @@ try {
 	HTTPError = Error;
 }
 
-export type PermissionResolvable = bigint | number | Permissions | PermissionResolvable[] | PermissionString;
+export type PermissionResolvable =
+	| bigint
+	| number
+	| Permissions
+	| PermissionResolvable[]
+	| PermissionString;
 
 type PermissionString = keyof typeof Permissions.FLAGS;
 
@@ -80,14 +91,20 @@ export class Permissions extends BitField {
 	};
 
 	any(permission: PermissionResolvable, checkAdmin = true) {
-		return (checkAdmin && super.any(Permissions.FLAGS.ADMINISTRATOR)) || super.any(permission);
+		return (
+			(checkAdmin && super.any(Permissions.FLAGS.ADMINISTRATOR)) ||
+			super.any(permission)
+		);
 	}
 
 	/**
 	 * Checks whether the bitfield has a permission, or multiple permissions.
 	 */
 	has(permission: PermissionResolvable, checkAdmin = true) {
-		return (checkAdmin && super.has(Permissions.FLAGS.ADMINISTRATOR)) || super.has(permission);
+		return (
+			(checkAdmin && super.has(Permissions.FLAGS.ADMINISTRATOR)) ||
+			super.has(permission)
+		);
 	}
 
 	/**
@@ -96,28 +113,39 @@ 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);
+		throw new HTTPError(
+			`You are missing the following permissions ${permission}`,
+			403,
+		);
 	}
 
 	overwriteChannel(overwrites: ChannelPermissionOverwrite[]) {
 		if (!overwrites) return this;
 		if (!this.cache) throw new Error("permission chache not available");
 		overwrites = overwrites.filter((x) => {
-			if (x.type === 0 && this.cache.roles?.some((r) => r.id === x.id)) return true;
+			if (x.type === 0 && this.cache.roles?.some((r) => r.id === x.id))
+				return true;
 			if (x.type === 1 && x.id == this.cache.user_id) return true;
 			return false;
 		});
-		return new Permissions(Permissions.channelPermission(overwrites, this.bitfield));
+		return new Permissions(
+			Permissions.channelPermission(overwrites, this.bitfield),
+		);
 	}
 
-	static channelPermission(overwrites: ChannelPermissionOverwrite[], init?: bigint) {
+	static channelPermission(
+		overwrites: ChannelPermissionOverwrite[],
+		init?: bigint,
+	) {
 		// TODO: do not deny any permissions if admin
 		return overwrites.reduce((permission, overwrite) => {
 			// apply disallowed permission
 			// * permission: current calculated permission (e.g. 010)
 			// * deny contains all denied permissions (e.g. 011)
 			// * allow contains all explicitly allowed permisions (e.g. 100)
-			return (permission & ~BigInt(overwrite.deny)) | BigInt(overwrite.allow);
+			return (
+				(permission & ~BigInt(overwrite.deny)) | BigInt(overwrite.allow)
+			);
 			// ~ operator inverts deny (e.g. 011 -> 100)
 			// & operator only allows 1 for both ~deny and permission (e.g. 010 & 100 -> 000)
 			// | operators adds both together (e.g. 000 + 100 -> 100)
@@ -126,7 +154,10 @@ export class Permissions extends BitField {
 
 	static rolePermission(roles: Role[]) {
 		// adds all permissions of all roles together (Bit OR)
-		return roles.reduce((permission, role) => permission | BigInt(role.permissions), BigInt(0));
+		return roles.reduce(
+			(permission, role) => permission | BigInt(role.permissions),
+			BigInt(0),
+		);
 	}
 
 	static finalPermission({
@@ -157,7 +188,8 @@ export class Permissions extends BitField {
 		}
 
 		if (channel?.recipient_ids) {
-			if (channel?.owner_id === user.id) return new Permissions("ADMINISTRATOR");
+			if (channel?.owner_id === user.id)
+				return new Permissions("ADMINISTRATOR");
 			if (channel.recipient_ids.includes(user.id)) {
 				// Default dm permissions
 				return new Permissions([
@@ -183,7 +215,10 @@ export class Permissions extends BitField {
 	}
 }
 
-const ALL_PERMISSIONS = Object.values(Permissions.FLAGS).reduce((total, val) => total | val, BigInt(0));
+const ALL_PERMISSIONS = Object.values(Permissions.FLAGS).reduce(
+	(total, val) => total | val,
+	BigInt(0),
+);
 
 export type PermissionCache = {
 	channel?: Channel | undefined;
@@ -204,7 +239,7 @@ export async function getPermission(
 		channel_relations?: string[];
 		member_select?: (keyof Member)[];
 		member_relations?: string[];
-	} = {}
+	} = {},
 ) {
 	if (!user_id) throw new HTTPError("User not found");
 	var channel: Channel | undefined;
@@ -239,16 +274,17 @@ export async function getPermission(
 			],
 			relations: opts.guild_relations,
 		});
-		if (guild.owner_id === user_id) return new Permissions(Permissions.FLAGS.ADMINISTRATOR);
+		if (guild.owner_id === user_id)
+			return new Permissions(Permissions.FLAGS.ADMINISTRATOR);
 
 		member = await Member.findOneOrFail({
 			where: { guild_id, id: user_id },
 			relations: ["roles", ...(opts.member_relations || [])],
 			// select: [
-				// "id",		// TODO: Bug in typeorm? adding these selects breaks the query.
-				// "roles",
-				// @ts-ignore
-				// ...(opts.member_select || []),
+			// "id",		// TODO: Bug in typeorm? adding these selects breaks the query.
+			// "roles",
+			// @ts-ignore
+			// ...(opts.member_select || []),
 			// ],
 		});
 	}
diff --git a/src/util/util/RabbitMQ.ts b/src/util/util/RabbitMQ.ts
index 0f5eb6aa..1bfb3f5c 100644
--- a/src/util/util/RabbitMQ.ts
+++ b/src/util/util/RabbitMQ.ts
@@ -1,7 +1,11 @@
 import amqp, { Connection, Channel } from "amqplib";
 // import Config from "./Config";
 
-export const RabbitMQ: { connection: Connection | null; channel: Channel | null; init: () => Promise<void> } = {
+export const RabbitMQ: {
+	connection: Connection | null;
+	channel: Channel | null;
+	init: () => Promise<void>;
+} = {
 	connection: null,
 	channel: null,
 	init: async function () {
diff --git a/src/util/util/Rights.ts b/src/util/util/Rights.ts
index b28c75b7..659353a6 100644
--- a/src/util/util/Rights.ts
+++ b/src/util/util/Rights.ts
@@ -11,7 +11,12 @@ try {
 	HTTPError = Error;
 }
 
-export type RightResolvable = bigint | number | Rights | RightResolvable[] | RightString;
+export type RightResolvable =
+	| bigint
+	| number
+	| Rights
+	| RightResolvable[]
+	| RightString;
 
 type RightString = keyof typeof Rights.FLAGS;
 // TODO: just like roles for members, users should have privilidges which combine multiple rights into one and make it easy to assign
@@ -60,7 +65,7 @@ export class Rights extends BitField {
 		CREDITABLE: BitFlag(32), // can receive money from monetisation related features
 		KICK_BAN_MEMBERS: BitFlag(33),
 		// can kick or ban guild or group DM members in the guilds/groups that they have KICK_MEMBERS, or BAN_MEMBERS
-		SELF_LEAVE_GROUPS: BitFlag(34), 
+		SELF_LEAVE_GROUPS: BitFlag(34),
 		// can leave the guilds or group DMs that they joined on their own (one can always leave a guild or group DMs they have been force-added)
 		PRESENCE: BitFlag(35),
 		// inverts the presence confidentiality default (OPERATOR's presence is not routed by default, others' are) for a given user
@@ -72,31 +77,44 @@ export class Rights extends BitField {
 		RESPOND_TO_INTERACTIONS: BitFlag(41), // can respond to interactions
 		SEND_BACKDATED_EVENTS: BitFlag(42), // can send backdated events
 		USE_MASS_INVITES: BitFlag(43), // added per @xnacly's request — can accept mass invites
-		ACCEPT_INVITES: BitFlag(44) // added per @xnacly's request — can accept user-specific invites and DM requests
+		ACCEPT_INVITES: BitFlag(44), // added per @xnacly's request — can accept user-specific invites and DM requests
 	};
 
 	any(permission: RightResolvable, checkOperator = true) {
-		return (checkOperator && super.any(Rights.FLAGS.OPERATOR)) || super.any(permission);
+		return (
+			(checkOperator && super.any(Rights.FLAGS.OPERATOR)) ||
+			super.any(permission)
+		);
 	}
 
 	has(permission: RightResolvable, checkOperator = true) {
-		return (checkOperator && super.has(Rights.FLAGS.OPERATOR)) || super.has(permission);
+		return (
+			(checkOperator && super.has(Rights.FLAGS.OPERATOR)) ||
+			super.has(permission)
+		);
 	}
 
 	hasThrow(permission: RightResolvable) {
 		if (this.has(permission)) return true;
 		// @ts-ignore
-		throw new HTTPError(`You are missing the following rights ${permission}`, 403);
+		throw new HTTPError(
+			`You are missing the following rights ${permission}`,
+			403,
+		);
 	}
-	
 }
 
-const ALL_RIGHTS = Object.values(Rights.FLAGS).reduce((total, val) => total | val, BigInt(0));
+const ALL_RIGHTS = Object.values(Rights.FLAGS).reduce(
+	(total, val) => total | val,
+	BigInt(0),
+);
 
-export async function getRights(	user_id: string
+export async function getRights(
+	user_id: string,
 	/**, opts: {
 		in_behalf?: (keyof User)[];
-	} = {} **/) {
+	} = {} **/
+) {
 	let user = await User.findOneOrFail({ where: { id: user_id } });
 	return new Rights(user.rights);
-} 
+}
diff --git a/src/util/util/Snowflake.ts b/src/util/util/Snowflake.ts
index 134d526e..69effb2e 100644
--- a/src/util/util/Snowflake.ts
+++ b/src/util/util/Snowflake.ts
@@ -17,7 +17,9 @@ export class Snowflake {
 	static workerId = BigInt((cluster.worker?.id || 0) % 31); // max 31
 
 	constructor() {
-		throw new Error(`The ${this.constructor.name} class may not be instantiated.`);
+		throw new Error(
+			`The ${this.constructor.name} class may not be instantiated.`,
+		);
 	}
 
 	/**
@@ -83,14 +85,15 @@ export class Snowflake {
 		return dec;
 	}
 
-	static generateWorkerProcess() { // worker process - returns a number
+	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++;
 		return BigInt(time | worker | process | increment);
 	}
-	
+
 	static generate() {
 		return Snowflake.generateWorkerProcess().toString();
 	}
@@ -111,7 +114,9 @@ export class Snowflake {
 	 * @returns {DeconstructedSnowflake} Deconstructed snowflake
 	 */
 	static deconstruct(snowflake) {
-		const BINARY = Snowflake.idToBinary(snowflake).toString(2).padStart(64, "0");
+		const BINARY = Snowflake.idToBinary(snowflake)
+			.toString(2)
+			.padStart(64, "0");
 		const res = {
 			timestamp: parseInt(BINARY.substring(0, 42), 2) + Snowflake.EPOCH,
 			workerID: parseInt(BINARY.substring(42, 47), 2),
diff --git a/src/util/util/Token.ts b/src/util/util/Token.ts
index 5ba3e1ec..19e64f47 100644
--- a/src/util/util/Token.ts
+++ b/src/util/util/Token.ts
@@ -17,11 +17,14 @@ export function checkToken(token: string, jwtSecret: string): Promise<any> {
 
 			const user = await User.findOne({
 				where: { id: decoded.id },
-				select: ["data", "bot", "disabled", "deleted", "rights"]
+				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))
+			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");
@@ -45,7 +48,7 @@ export async function generateToken(id: string) {
 			(err, token) => {
 				if (err) return rej(err);
 				return res(token);
-			}
+			},
 		);
 	});
 }
diff --git a/src/util/util/TraverseDirectory.ts b/src/util/util/TraverseDirectory.ts
index 3d0d6279..3f5b0385 100644
--- a/src/util/util/TraverseDirectory.ts
+++ b/src/util/util/TraverseDirectory.ts
@@ -1,13 +1,14 @@
 import { Server, traverseDirectory } from "lambert-server";
 
 //if we're using ts-node, use ts files instead of js
-const extension = Symbol.for("ts-node.register.instance") in process ? "ts" : "js"
+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(
 		{ dirname: root, recursive: true, filter: DEFAULT_FILTER },
-		server.registerRoute.bind(server, root)
+		server.registerRoute.bind(server, root),
 	);
 }
diff --git a/src/util/util/cdn.ts b/src/util/util/cdn.ts
index 812a4e1d..6b2c8424 100644
--- a/src/util/util/cdn.ts
+++ b/src/util/util/cdn.ts
@@ -4,7 +4,10 @@ import fetch from "node-fetch";
 import { Attachment } from "../entities";
 import { Config } from "./Config";
 
-export async function uploadFile(path: string, file?: Express.Multer.File): Promise<Attachment> {
+export async function uploadFile(
+	path: string,
+	file?: Express.Multer.File,
+): Promise<Attachment> {
 	if (!file?.buffer) throw new HTTPError("Missing file in body");
 
 	const form = new FormData();
@@ -13,28 +16,38 @@ export async function uploadFile(path: string, file?: Express.Multer.File): Prom
 		filename: file.originalname,
 	});
 
-	const response = await fetch(`${Config.get().cdn.endpointPrivate || "http://localhost:3003"}${path}`, {
-		headers: {
-			signature: Config.get().security.requestSignature,
-			...form.getHeaders(),
+	const response = await fetch(
+		`${Config.get().cdn.endpointPrivate || "http://localhost:3003"}${path}`,
+		{
+			headers: {
+				signature: Config.get().security.requestSignature,
+				...form.getHeaders(),
+			},
+			method: "POST",
+			body: form,
 		},
-		method: "POST",
-		body: form,
-	});
-	const result = await response.json() as Attachment;
+	);
+	const result = (await response.json()) as Attachment;
 
 	if (response.status !== 200) throw result;
 	return result;
 }
 
-export async function handleFile(path: string, body?: string): Promise<string | undefined> {
+export async function handleFile(
+	path: string,
+	body?: string,
+): Promise<string | undefined> {
 	if (!body || !body.startsWith("data:")) return undefined;
 	try {
 		const mimetype = body.split(":")[1].split(";")[0];
 		const buffer = Buffer.from(body.split(",")[1], "base64");
 
 		// @ts-ignore
-		const { id } = await uploadFile(path, { buffer, mimetype, originalname: "banner" });
+		const { id } = await uploadFile(path, {
+			buffer,
+			mimetype,
+			originalname: "banner",
+		});
 		return id;
 	} catch (error) {
 		console.error(error);
@@ -43,12 +56,15 @@ export async function handleFile(path: string, body?: string): Promise<string |
 }
 
 export async function deleteFile(path: string) {
-	const response = await fetch(`${Config.get().cdn.endpointPrivate || "http://localhost:3003"}${path}`, {
-		headers: {
-			signature: Config.get().security.requestSignature,
+	const response = await fetch(
+		`${Config.get().cdn.endpointPrivate || "http://localhost:3003"}${path}`,
+		{
+			headers: {
+				signature: Config.get().security.requestSignature,
+			},
+			method: "DELETE",
 		},
-		method: "DELETE",
-	});
+	);
 	const result = await response.json();
 
 	if (response.status !== 200) throw result;
diff --git a/src/util/util/index.ts b/src/util/util/index.ts
index b2bd6489..aa38e472 100644
--- a/src/util/util/index.ts
+++ b/src/util/util/index.ts
@@ -20,4 +20,4 @@ export * from "./String";
 export * from "./Array";
 export * from "./TraverseDirectory";
 export * from "./InvisibleCharacters";
-export * from "./BannedWords";
\ No newline at end of file
+export * from "./BannedWords";
diff --git a/src/webrtc/Server.ts b/src/webrtc/Server.ts
index 32b795ea..d9a892a3 100644
--- a/src/webrtc/Server.ts
+++ b/src/webrtc/Server.ts
@@ -11,7 +11,15 @@ export class Server {
 	public server: http.Server;
 	public production: boolean;
 
-	constructor({ port, server, production }: { port: number; server?: http.Server; production?: boolean }) {
+	constructor({
+		port,
+		server,
+		production,
+	}: {
+		port: number;
+		server?: http.Server;
+		production?: boolean;
+	}) {
 		this.port = port;
 		this.production = production || false;
 
@@ -53,4 +61,4 @@ export class Server {
 		closeDatabase();
 		this.server.close();
 	}
-}
\ No newline at end of file
+}
diff --git a/src/webrtc/events/Close.ts b/src/webrtc/events/Close.ts
index 1c203653..4cf80bb2 100644
--- a/src/webrtc/events/Close.ts
+++ b/src/webrtc/events/Close.ts
@@ -6,4 +6,4 @@ export async function onClose(this: WebSocket, code: number, reason: string) {
 
 	if (this.session_id) await Session.delete({ session_id: this.session_id });
 	this.removeAllListeners();
-}
\ No newline at end of file
+}
diff --git a/src/webrtc/events/Connection.ts b/src/webrtc/events/Connection.ts
index bf228d64..9300b6b2 100644
--- a/src/webrtc/events/Connection.ts
+++ b/src/webrtc/events/Connection.ts
@@ -14,7 +14,11 @@ try {
 // TODO: specify rate limit in config
 // TODO: check msg max size
 
-export async function Connection(this: WS.Server, socket: WebSocket, request: IncomingMessage) {
+export async function Connection(
+	this: WS.Server,
+	socket: WebSocket,
+	request: IncomingMessage,
+) {
 	try {
 		socket.on("close", onClose.bind(socket));
 		socket.on("message", onMessage.bind(socket));
@@ -29,7 +33,7 @@ export async function Connection(this: WS.Server, socket: WebSocket, request: In
 				"open",
 				"ping",
 				"pong",
-				"unexpected-response"
+				"unexpected-response",
 			].forEach((x) => {
 				socket.on(x, (y) => console.log("[WebRTC]", x, y));
 			});
@@ -39,7 +43,8 @@ export async function Connection(this: WS.Server, socket: WebSocket, request: In
 
 		socket.encoding = "json";
 		socket.version = Number(searchParams.get("v")) || 5;
-		if (socket.version < 3) return socket.close(CLOSECODES.Unknown_error, "invalid version");
+		if (socket.version < 3)
+			return socket.close(CLOSECODES.Unknown_error, "invalid version");
 
 		setHeartbeat(socket);
 
@@ -50,11 +55,11 @@ export async function Connection(this: WS.Server, socket: WebSocket, request: In
 		await Send(socket, {
 			op: VoiceOPCodes.HELLO,
 			d: {
-				heartbeat_interval: 1000 * 30
-			}
+				heartbeat_interval: 1000 * 30,
+			},
 		});
 	} catch (error) {
 		console.error("[WebRTC]", error);
 		return socket.close(CLOSECODES.Unknown_error);
 	}
-}
\ No newline at end of file
+}
diff --git a/src/webrtc/events/Message.ts b/src/webrtc/events/Message.ts
index 8f75a815..38676f6c 100644
--- a/src/webrtc/events/Message.ts
+++ b/src/webrtc/events/Message.ts
@@ -7,13 +7,14 @@ const PayloadSchema = {
 	op: Number,
 	$d: new Tuple(Object, Number), // or number for heartbeat sequence
 	$s: Number,
-	$t: String
+	$t: String,
 };
 
 export async function onMessage(this: WebSocket, buffer: Buffer) {
 	try {
 		var data: Payload = JSON.parse(buffer.toString());
-		if (data.op !== VoiceOPCodes.IDENTIFY && !this.user_id) return this.close(CLOSECODES.Not_authenticated);
+		if (data.op !== VoiceOPCodes.IDENTIFY && !this.user_id)
+			return this.close(CLOSECODES.Not_authenticated);
 
 		// @ts-ignore
 		const OPCodeHandler = OPCodeHandlers[data.op];
@@ -25,7 +26,11 @@ export async function onMessage(this: WebSocket, buffer: Buffer) {
 			return;
 		}
 
-		if (![VoiceOPCodes.HEARTBEAT, VoiceOPCodes.SPEAKING].includes(data.op as VoiceOPCodes)) {
+		if (
+			![VoiceOPCodes.HEARTBEAT, VoiceOPCodes.SPEAKING].includes(
+				data.op as VoiceOPCodes,
+			)
+		) {
 			// @ts-ignore
 			console.log("[WebRTC] Opcode " + VoiceOPCodes[data.op]);
 		}
@@ -35,4 +40,4 @@ export async function onMessage(this: WebSocket, buffer: Buffer) {
 		console.error("[WebRTC] error", error);
 		// if (!this.CLOSED && this.CLOSING) return this.close(CloseCodes.Unknown_error);
 	}
-}
\ No newline at end of file
+}
diff --git a/src/webrtc/index.ts b/src/webrtc/index.ts
index 7cecc9b6..ccb088ac 100644
--- a/src/webrtc/index.ts
+++ b/src/webrtc/index.ts
@@ -1,2 +1,2 @@
 export * from "./Server";
-export * from "./util/index";
\ No newline at end of file
+export * from "./util/index";
diff --git a/src/webrtc/opcodes/BackendVersion.ts b/src/webrtc/opcodes/BackendVersion.ts
index b4b61c7d..375dd0cc 100644
--- a/src/webrtc/opcodes/BackendVersion.ts
+++ b/src/webrtc/opcodes/BackendVersion.ts
@@ -2,5 +2,8 @@ import { Payload, Send, WebSocket } from "@fosscord/gateway";
 import { VoiceOPCodes } from "../util";
 
 export async function onBackendVersion(this: WebSocket, data: Payload) {
-	await Send(this, { op: VoiceOPCodes.VOICE_BACKEND_VERSION, d: { voice: "0.8.43", rtc_worker: "0.3.26" } });
-}
\ No newline at end of file
+	await Send(this, {
+		op: VoiceOPCodes.VOICE_BACKEND_VERSION,
+		d: { voice: "0.8.43", rtc_worker: "0.3.26" },
+	});
+}
diff --git a/src/webrtc/opcodes/Heartbeat.ts b/src/webrtc/opcodes/Heartbeat.ts
index 1b6c5bcd..932cd458 100644
--- a/src/webrtc/opcodes/Heartbeat.ts
+++ b/src/webrtc/opcodes/Heartbeat.ts
@@ -1,4 +1,10 @@
-import { CLOSECODES, Payload, Send, setHeartbeat, WebSocket } from "@fosscord/gateway";
+import {
+	CLOSECODES,
+	Payload,
+	Send,
+	setHeartbeat,
+	WebSocket,
+} from "@fosscord/gateway";
 import { VoiceOPCodes } from "../util";
 
 export async function onHeartbeat(this: WebSocket, data: Payload) {
@@ -6,4 +12,4 @@ export async function onHeartbeat(this: WebSocket, data: Payload) {
 	if (isNaN(data.d)) return this.close(CLOSECODES.Decode_error);
 
 	await Send(this, { op: VoiceOPCodes.HEARTBEAT_ACK, d: data.d });
-}
\ No newline at end of file
+}
diff --git a/src/webrtc/opcodes/Identify.ts b/src/webrtc/opcodes/Identify.ts
index 19a575ab..45ad6c0a 100644
--- a/src/webrtc/opcodes/Identify.ts
+++ b/src/webrtc/opcodes/Identify.ts
@@ -1,33 +1,46 @@
 import { CLOSECODES, Payload, Send, WebSocket } from "@fosscord/gateway";
-import { validateSchema, VoiceIdentifySchema, VoiceState } from "@fosscord/util";
+import {
+	validateSchema,
+	VoiceIdentifySchema,
+	VoiceState,
+} from "@fosscord/util";
 import { endpoint, getClients, VoiceOPCodes, PublicIP } from "@fosscord/webrtc";
 import SemanticSDP from "semantic-sdp";
 const defaultSDP = require("./sdp.json");
 
 export async function onIdentify(this: WebSocket, data: Payload) {
 	clearTimeout(this.readyTimeout);
-	const { server_id, user_id, session_id, token, streams, video } = validateSchema("VoiceIdentifySchema", data.d) as VoiceIdentifySchema;
+	const { server_id, user_id, session_id, token, streams, video } =
+		validateSchema("VoiceIdentifySchema", data.d) as VoiceIdentifySchema;
 
-	const voiceState = await VoiceState.findOne({ where: { guild_id: server_id, user_id, token, session_id } });
+	const voiceState = await VoiceState.findOne({
+		where: { guild_id: server_id, user_id, token, session_id },
+	});
 	if (!voiceState) return this.close(CLOSECODES.Authentication_failed);
 
 	this.user_id = user_id;
 	this.session_id = session_id;
 	const sdp = SemanticSDP.SDPInfo.expand(defaultSDP);
-	sdp.setDTLS(SemanticSDP.DTLSInfo.expand({ setup: "actpass", hash: "sha-256", fingerprint: endpoint.getDTLSFingerprint() }));
+	sdp.setDTLS(
+		SemanticSDP.DTLSInfo.expand({
+			setup: "actpass",
+			hash: "sha-256",
+			fingerprint: endpoint.getDTLSFingerprint(),
+		}),
+	);
 
 	this.client = {
 		websocket: this,
 		out: {
-			tracks: new Map()
+			tracks: new Map(),
 		},
 		in: {
 			audio_ssrc: 0,
 			video_ssrc: 0,
-			rtx_ssrc: 0
+			rtx_ssrc: 0,
 		},
 		sdp,
-		channel_id: voiceState.channel_id
+		channel_id: voiceState.channel_id,
 	};
 
 	const clients = getClients(voiceState.channel_id)!;
@@ -51,10 +64,10 @@ export async function onIdentify(this: WebSocket, data: Payload) {
 				"xsalsa20_poly1305_lite_rtpsize",
 				"xsalsa20_poly1305_lite",
 				"xsalsa20_poly1305_suffix",
-				"xsalsa20_poly1305"
+				"xsalsa20_poly1305",
 			],
 			ip: PublicIP,
-			experiments: []
-		}
+			experiments: [],
+		},
 	});
-}
\ No newline at end of file
+}
diff --git a/src/webrtc/opcodes/SelectProtocol.ts b/src/webrtc/opcodes/SelectProtocol.ts
index a3579b34..eadba283 100644
--- a/src/webrtc/opcodes/SelectProtocol.ts
+++ b/src/webrtc/opcodes/SelectProtocol.ts
@@ -6,7 +6,10 @@ import SemanticSDP, { MediaInfo, SDPInfo } from "semantic-sdp";
 export async function onSelectProtocol(this: WebSocket, payload: Payload) {
 	if (!this.client) return;
 
-	const data = validateSchema("SelectProtocolSchema", payload.d) as SelectProtocolSchema;
+	const data = validateSchema(
+		"SelectProtocolSchema",
+		payload.d,
+	) as SelectProtocolSchema;
 
 	const offer = SemanticSDP.SDPInfo.parse("m=audio\n" + data.sdp!);
 	this.client.sdp!.setICE(offer.getICE());
@@ -25,14 +28,14 @@ export async function onSelectProtocol(this: WebSocket, payload: Payload) {
 	const candidate = candidates[0];
 
 	const answer =
-		`m=audio ${port} ICE/SDP`
-		+ `a=fingerprint:${fingerprint}`
-		+ `c=IN IP4 ${PublicIP}`
-		+ `a=rtcp:${port}`
-		+ `a=ice-ufrag:${ice.getUfrag()}`
-		+ `a=ice-pwd:${ice.getPwd()}`
-		+ `a=fingerprint:${fingerprint}`
-		+ `a=candidate:1 1 ${candidate.getTransport()} ${candidate.getFoundation()} ${candidate.getAddress()} ${candidate.getPort()} typ host`;
+		`m=audio ${port} ICE/SDP` +
+		`a=fingerprint:${fingerprint}` +
+		`c=IN IP4 ${PublicIP}` +
+		`a=rtcp:${port}` +
+		`a=ice-ufrag:${ice.getUfrag()}` +
+		`a=ice-pwd:${ice.getPwd()}` +
+		`a=fingerprint:${fingerprint}` +
+		`a=candidate:1 1 ${candidate.getTransport()} ${candidate.getFoundation()} ${candidate.getAddress()} ${candidate.getPort()} typ host`;
 
 	await Send(this, {
 		op: VoiceOPCodes.SELECT_PROTOCOL_ACK,
@@ -40,7 +43,7 @@ export async function onSelectProtocol(this: WebSocket, payload: Payload) {
 			video_codec: "H264",
 			sdp: answer,
 			media_session_id: this.session_id,
-			audio_codec: "opus"
-		}
+			audio_codec: "opus",
+		},
 	});
-}
\ No newline at end of file
+}
diff --git a/src/webrtc/opcodes/Speaking.ts b/src/webrtc/opcodes/Speaking.ts
index e2227040..8488acf8 100644
--- a/src/webrtc/opcodes/Speaking.ts
+++ b/src/webrtc/opcodes/Speaking.ts
@@ -15,8 +15,8 @@ export async function onSpeaking(this: WebSocket, data: Payload) {
 			d: {
 				user_id: client.websocket.user_id,
 				speaking: data.d.speaking,
-				ssrc: ssrc?.audio_ssrc || 0
-			}
+				ssrc: ssrc?.audio_ssrc || 0,
+			},
 		});
 	});
-}
\ No newline at end of file
+}
diff --git a/src/webrtc/opcodes/Video.ts b/src/webrtc/opcodes/Video.ts
index ff20d5a9..dcbc9aa0 100644
--- a/src/webrtc/opcodes/Video.ts
+++ b/src/webrtc/opcodes/Video.ts
@@ -21,8 +21,8 @@ export async function onVideo(this: WebSocket, payload: Payload) {
 			SemanticSDP.StreamInfo.expand({
 				id,
 				// @ts-ignore
-				tracks: []
-			})
+				tracks: [],
+			}),
 		);
 		this.client.in.stream = stream;
 
@@ -46,8 +46,8 @@ export async function onVideo(this: WebSocket, payload: Payload) {
 			SemanticSDP.StreamInfo.expand({
 				id: "out" + this.user_id,
 				// @ts-ignore
-				tracks: []
-			})
+				tracks: [],
+			}),
 		);
 		this.client.out.stream = out;
 
@@ -64,20 +64,35 @@ export async function onVideo(this: WebSocket, payload: Payload) {
 	}
 
 	if (d.audio_ssrc) {
-		handleSSRC.call(this, "audio", { media: d.audio_ssrc, rtx: d.audio_ssrc + 1 });
+		handleSSRC.call(this, "audio", {
+			media: d.audio_ssrc,
+			rtx: d.audio_ssrc + 1,
+		});
 	}
 	if (d.video_ssrc && d.rtx_ssrc) {
-		handleSSRC.call(this, "video", { media: d.video_ssrc, rtx: d.rtx_ssrc });
+		handleSSRC.call(this, "video", {
+			media: d.video_ssrc,
+			rtx: d.rtx_ssrc,
+		});
 	}
 }
 
-function attachTrack(this: WebSocket, track: IncomingStreamTrack, user_id: string) {
+function attachTrack(
+	this: WebSocket,
+	track: IncomingStreamTrack,
+	user_id: string,
+) {
 	if (!this.client) return;
-	const outTrack = this.client.transport!.createOutgoingStreamTrack(track.getMedia());
+	const outTrack = this.client.transport!.createOutgoingStreamTrack(
+		track.getMedia(),
+	);
 	outTrack.attachTo(track);
 	this.client.out.stream!.addTrack(outTrack);
 	var ssrcs = this.client.out.tracks.get(user_id)!;
-	if (!ssrcs) ssrcs = this.client.out.tracks.set(user_id, { audio_ssrc: 0, rtx_ssrc: 0, video_ssrc: 0 }).get(user_id)!;
+	if (!ssrcs)
+		ssrcs = this.client.out.tracks
+			.set(user_id, { audio_ssrc: 0, rtx_ssrc: 0, video_ssrc: 0 })
+			.get(user_id)!;
 
 	if (track.getMedia() === "audio") {
 		ssrcs.audio_ssrc = outTrack.getSSRCs().media!;
@@ -90,8 +105,8 @@ function attachTrack(this: WebSocket, track: IncomingStreamTrack, user_id: strin
 		op: VoiceOPCodes.VIDEO,
 		d: {
 			user_id: user_id,
-			...ssrcs
-		} as VoiceVideoSchema
+			...ssrcs,
+		} as VoiceVideoSchema,
 	});
 }
 
@@ -115,4 +130,4 @@ function handleSSRC(this: WebSocket, type: "audio" | "video", ssrcs: SSRCs) {
 			attachTrack.call(this, track, client.websocket.user_id);
 		});
 	}
-}
\ No newline at end of file
+}
diff --git a/src/webrtc/opcodes/index.ts b/src/webrtc/opcodes/index.ts
index 8c664cce..86e39687 100644
--- a/src/webrtc/opcodes/index.ts
+++ b/src/webrtc/opcodes/index.ts
@@ -15,5 +15,5 @@ export default {
 	[VoiceOPCodes.VOICE_BACKEND_VERSION]: onBackendVersion,
 	[VoiceOPCodes.VIDEO]: onVideo,
 	[VoiceOPCodes.SPEAKING]: onSpeaking,
-	[VoiceOPCodes.SELECT_PROTOCOL]: onSelectProtocol
-};
\ No newline at end of file
+	[VoiceOPCodes.SELECT_PROTOCOL]: onSelectProtocol,
+};
diff --git a/src/webrtc/opcodes/sdp.json b/src/webrtc/opcodes/sdp.json
index 4867b9c7..5f7eba38 100644
--- a/src/webrtc/opcodes/sdp.json
+++ b/src/webrtc/opcodes/sdp.json
@@ -417,4 +417,4 @@
 		}
 	],
 	"candidates": []
-}
\ No newline at end of file
+}
diff --git a/src/webrtc/start.ts b/src/webrtc/start.ts
index 9a5f38ee..57361909 100644
--- a/src/webrtc/start.ts
+++ b/src/webrtc/start.ts
@@ -8,6 +8,6 @@ config();
 const port = Number(process.env.PORT) || 3004;
 
 const server = new Server({
-	port
+	port,
 });
-server.start();
\ No newline at end of file
+server.start();
diff --git a/src/webrtc/util/Constants.ts b/src/webrtc/util/Constants.ts
index 64d78e22..d9f1ff60 100644
--- a/src/webrtc/util/Constants.ts
+++ b/src/webrtc/util/Constants.ts
@@ -3,7 +3,7 @@ export enum VoiceStatus {
 	CONNECTING = 1,
 	AUTHENTICATING = 2,
 	RECONNECTING = 3,
-	DISCONNECTED = 4
+	DISCONNECTED = 4,
 }
 
 export enum VoiceOPCodes {
@@ -22,5 +22,5 @@ export enum VoiceOPCodes {
 	SESSION_UPDATE = 14,
 	MEDIA_SINK_WANTS = 15,
 	VOICE_BACKEND_VERSION = 16,
-	CHANNEL_OPTIONS_UPDATE = 17
-}
\ No newline at end of file
+	CHANNEL_OPTIONS_UPDATE = 17,
+}
diff --git a/src/webrtc/util/MediaServer.ts b/src/webrtc/util/MediaServer.ts
index 93230c91..520b8682 100644
--- a/src/webrtc/util/MediaServer.ts
+++ b/src/webrtc/util/MediaServer.ts
@@ -1,5 +1,9 @@
 import { WebSocket } from "@fosscord/gateway";
-import MediaServer, { IncomingStream, OutgoingStream, Transport } from "medooze-media-server";
+import MediaServer, {
+	IncomingStream,
+	OutgoingStream,
+	Transport,
+} from "medooze-media-server";
 import SemanticSDP from "semantic-sdp";
 MediaServer.enableLog(true);
 
@@ -13,7 +17,11 @@ try {
 
 	MediaServer.setPortRange(min, max);
 } catch (error) {
-	console.error("Invalid env var: WEBRTC_PORT_RANGE", process.env.WEBRTC_PORT_RANGE, error);
+	console.error(
+		"Invalid env var: WEBRTC_PORT_RANGE",
+		process.env.WEBRTC_PORT_RANGE,
+		error,
+	);
 	process.exit(1);
 }
 
@@ -48,4 +56,4 @@ export interface Client {
 export function getClients(channel_id: string) {
 	if (!channels.has(channel_id)) channels.set(channel_id, new Set());
 	return channels.get(channel_id)!;
-}
\ No newline at end of file
+}
diff --git a/src/webrtc/util/index.ts b/src/webrtc/util/index.ts
index 2e09bc48..f0d49049 100644
--- a/src/webrtc/util/index.ts
+++ b/src/webrtc/util/index.ts
@@ -1,2 +1,2 @@
 export * from "./Constants";
-export * from "./MediaServer";
\ No newline at end of file
+export * from "./MediaServer";
diff --git a/tsconfig.json b/tsconfig.json
index 9797ae10..48187ced 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,113 +1,114 @@
 {
-  "exclude": [
-    "./src/webrtc",
-	"./src-slowcord"
-  ],
-  "include": ["./src"],
-  "compilerOptions": {
-    /* Visit https://aka.ms/tsconfig to read more about this file */
+	"exclude": ["./src/webrtc", "./src-slowcord"],
+	"include": ["./src"],
+	"compilerOptions": {
+		/* Visit https://aka.ms/tsconfig to read more about this file */
 
-    /* Projects */
-    "incremental": true,                              /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
-    // "composite": true,                                /* Enable constraints that allow a TypeScript project to be used with project references. */
-    // "tsBuildInfoFile": "./.tsbuildinfo",              /* Specify the path to .tsbuildinfo incremental compilation file. */
-    // "disableSourceOfProjectReferenceRedirect": true,  /* Disable preferring source files instead of declaration files when referencing composite projects. */
-    // "disableSolutionSearching": true,                 /* Opt a project out of multi-project reference checking when editing. */
-    // "disableReferencedProjectLoad": true,             /* Reduce the number of projects loaded automatically by TypeScript. */
+		/* Projects */
+		"incremental": true /* Save .tsbuildinfo files to allow for incremental compilation of projects. */,
+		// "composite": true,                                /* Enable constraints that allow a TypeScript project to be used with project references. */
+		// "tsBuildInfoFile": "./.tsbuildinfo",              /* Specify the path to .tsbuildinfo incremental compilation file. */
+		// "disableSourceOfProjectReferenceRedirect": true,  /* Disable preferring source files instead of declaration files when referencing composite projects. */
+		// "disableSolutionSearching": true,                 /* Opt a project out of multi-project reference checking when editing. */
+		// "disableReferencedProjectLoad": true,             /* Reduce the number of projects loaded automatically by TypeScript. */
 
-    /* Language and Environment */
-    "target": "ESNext",                                  /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
-    "lib": ["ESNext"],                                        /* Specify a set of bundled library declaration files that describe the target runtime environment. */
-    // "jsx": "preserve",                                /* Specify what JSX code is generated. */
-    "experimentalDecorators": true,                   /* Enable experimental support for TC39 stage 2 draft decorators. */
-    "emitDecoratorMetadata": true,                    /* Emit design-type metadata for decorated declarations in source files. */
-    // "jsxFactory": "",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
-    // "jsxFragmentFactory": "",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
-    // "jsxImportSource": "",                            /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
-    // "reactNamespace": "",                             /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
-    // "noLib": true,                                    /* Disable including any library files, including the default lib.d.ts. */
-    // "useDefineForClassFields": true,                  /* Emit ECMAScript-standard-compliant class fields. */
-    // "moduleDetection": "auto",                        /* Control what method is used to detect module-format JS files. */
+		/* Language and Environment */
+		"target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
+		"lib": [
+			"ESNext"
+		] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,
+		// "jsx": "preserve",                                /* Specify what JSX code is generated. */
+		"experimentalDecorators": true /* Enable experimental support for TC39 stage 2 draft decorators. */,
+		"emitDecoratorMetadata": true /* Emit design-type metadata for decorated declarations in source files. */,
+		// "jsxFactory": "",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
+		// "jsxFragmentFactory": "",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
+		// "jsxImportSource": "",                            /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
+		// "reactNamespace": "",                             /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
+		// "noLib": true,                                    /* Disable including any library files, including the default lib.d.ts. */
+		// "useDefineForClassFields": true,                  /* Emit ECMAScript-standard-compliant class fields. */
+		// "moduleDetection": "auto",                        /* Control what method is used to detect module-format JS files. */
 
-    /* Modules */
-    "module": "commonjs",                                /* Specify what module code is generated. */
-    // "rootDir": "./src",                                  /* Specify the root folder within your source files. */
-    "moduleResolution": "node",                       /* Specify how TypeScript looks up a file from a given module specifier. */
-	"baseUrl": "./src/",
-	"paths": {
-		"@fosscord/api*": ["./api"],
-		"@fosscord/gateway*": ["./gateway"],
-		"@fosscord/cdn*": ["./cdn"],
-		"@fosscord/util*": ["./util"]
-	},                               /* Specify a set of entries that re-map imports to additional lookup locations. */
-    // "rootDirs": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */
-    // "typeRoots": [],                                  /* Specify multiple folders that act like './node_modules/@types'. */
-    "types": ["node"],                                      /* Specify type package names to be included without being referenced in a source file. */
-    // "allowUmdGlobalAccess": true,                     /* Allow accessing UMD globals from modules. */
-    // "moduleSuffixes": [],                             /* List of file name suffixes to search when resolving a module. */
-    "resolveJsonModule": true,                        /* Enable importing .json files. */
-    // "noResolve": true,                                /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
+		/* Modules */
+		"module": "commonjs" /* Specify what module code is generated. */,
+		// "rootDir": "./src",                                  /* Specify the root folder within your source files. */
+		"moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */,
+		"baseUrl": "./src/",
+		"paths": {
+			"@fosscord/api*": ["./api"],
+			"@fosscord/gateway*": ["./gateway"],
+			"@fosscord/cdn*": ["./cdn"],
+			"@fosscord/util*": ["./util"]
+		} /* Specify a set of entries that re-map imports to additional lookup locations. */,
+		// "rootDirs": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */
+		// "typeRoots": [],                                  /* Specify multiple folders that act like './node_modules/@types'. */
+		"types": [
+			"node"
+		] /* Specify type package names to be included without being referenced in a source file. */,
+		// "allowUmdGlobalAccess": true,                     /* Allow accessing UMD globals from modules. */
+		// "moduleSuffixes": [],                             /* List of file name suffixes to search when resolving a module. */
+		"resolveJsonModule": true /* Enable importing .json files. */,
+		// "noResolve": true,                                /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
 
-    /* JavaScript Support */
-    "allowJs": true,                                  /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
-    "checkJs": true,                                  /* Enable error reporting in type-checked JavaScript files. */
-    // "maxNodeModuleJsDepth": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
+		/* JavaScript Support */
+		"allowJs": true /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */,
+		"checkJs": true /* Enable error reporting in type-checked JavaScript files. */,
+		// "maxNodeModuleJsDepth": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
 
-    /* Emit */
-    "declaration": false,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
-    "declarationMap": false,                           /* Create sourcemaps for d.ts files. */
-    // "emitDeclarationOnly": true,                      /* Only output d.ts files and not JavaScript files. */
-    "sourceMap": true,                                /* Create source map files for emitted JavaScript files. */
-    // "outFile": "./",                                  /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
-    "outDir": "./dist/",                                   /* Specify an output folder for all emitted files. */
-    // "removeComments": true,                           /* Disable emitting comments. */
-    // "noEmit": true,                                   /* Disable emitting files from a compilation. */
-    "importHelpers": true,                            /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
-    // "importsNotUsedAsValues": "remove",               /* Specify emit/checking behavior for imports that are only used for types. */
-    // "downlevelIteration": true,                       /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
-    // "sourceRoot": "",                                 /* Specify the root path for debuggers to find the reference source code. */
-    // "mapRoot": "",                                    /* Specify the location where debugger should locate map files instead of generated locations. */
-    // "inlineSourceMap": true,                          /* Include sourcemap files inside the emitted JavaScript. */
-    // "inlineSources": true,                            /* Include source code in the sourcemaps inside the emitted JavaScript. */
-    // "emitBOM": true,                                  /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
-    // "newLine": "crlf",                                /* Set the newline character for emitting files. */
-    // "stripInternal": true,                            /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
-    "noEmitHelpers": true,                            /* Disable generating custom helper functions like '__extends' in compiled output. */
-    // "noEmitOnError": true,                            /* Disable emitting files if any type checking errors are reported. */
-    // "preserveConstEnums": true,                       /* Disable erasing 'const enum' declarations in generated code. */
-    // "declarationDir": "./",                           /* Specify the output directory for generated declaration files. */
-    // "preserveValueImports": true,                     /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
+		/* Emit */
+		"declaration": false /* Generate .d.ts files from TypeScript and JavaScript files in your project. */,
+		"declarationMap": false /* Create sourcemaps for d.ts files. */,
+		// "emitDeclarationOnly": true,                      /* Only output d.ts files and not JavaScript files. */
+		"sourceMap": true /* Create source map files for emitted JavaScript files. */,
+		// "outFile": "./",                                  /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
+		"outDir": "./dist/" /* Specify an output folder for all emitted files. */,
+		// "removeComments": true,                           /* Disable emitting comments. */
+		// "noEmit": true,                                   /* Disable emitting files from a compilation. */
+		"importHelpers": true /* Allow importing helper functions from tslib once per project, instead of including them per-file. */,
+		// "importsNotUsedAsValues": "remove",               /* Specify emit/checking behavior for imports that are only used for types. */
+		// "downlevelIteration": true,                       /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
+		// "sourceRoot": "",                                 /* Specify the root path for debuggers to find the reference source code. */
+		// "mapRoot": "",                                    /* Specify the location where debugger should locate map files instead of generated locations. */
+		// "inlineSourceMap": true,                          /* Include sourcemap files inside the emitted JavaScript. */
+		// "inlineSources": true,                            /* Include source code in the sourcemaps inside the emitted JavaScript. */
+		// "emitBOM": true,                                  /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
+		// "newLine": "crlf",                                /* Set the newline character for emitting files. */
+		// "stripInternal": true,                            /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
+		"noEmitHelpers": true /* Disable generating custom helper functions like '__extends' in compiled output. */,
+		// "noEmitOnError": true,                            /* Disable emitting files if any type checking errors are reported. */
+		// "preserveConstEnums": true,                       /* Disable erasing 'const enum' declarations in generated code. */
+		// "declarationDir": "./",                           /* Specify the output directory for generated declaration files. */
+		// "preserveValueImports": true,                     /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
 
-    /* Interop Constraints */
-    // "isolatedModules": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */
-    // "allowSyntheticDefaultImports": true,             /* Allow 'import x from y' when a module doesn't have a default export. */
-    "esModuleInterop": true,                             /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
-    // "preserveSymlinks": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
-    "forceConsistentCasingInFileNames": true,            /* Ensure that casing is correct in imports. */
+		/* Interop Constraints */
+		// "isolatedModules": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */
+		// "allowSyntheticDefaultImports": true,             /* Allow 'import x from y' when a module doesn't have a default export. */
+		"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
+		// "preserveSymlinks": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
+		"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
 
-    /* Type Checking */
-    "strict": true,                                      /* Enable all strict type-checking options. */
-    "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied 'any' type. */
-    "strictNullChecks": true,                         /* When type checking, take into account 'null' and 'undefined'. */
-    // "strictFunctionTypes": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
-    // "strictBindCallApply": true,                      /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
-    "strictPropertyInitialization": false,             /* Check for class properties that are declared but not set in the constructor. */
-    // "noImplicitThis": true,                           /* Enable error reporting when 'this' is given the type 'any'. */
-    // "useUnknownInCatchVariables": true,               /* Default catch clause variables as 'unknown' instead of 'any'. */
-    "alwaysStrict": true,                             /* Ensure 'use strict' is always emitted. */
-    // "noUnusedLocals": true,                           /* Enable error reporting when local variables aren't read. */
-    // "noUnusedParameters": true,                       /* Raise an error when a function parameter isn't read. */
-    // "exactOptionalPropertyTypes": true,               /* Interpret optional property types as written, rather than adding 'undefined'. */
-    // "noImplicitReturns": true,                        /* Enable error reporting for codepaths that do not explicitly return in a function. */
-    // "noFallthroughCasesInSwitch": true,               /* Enable error reporting for fallthrough cases in switch statements. */
-    // "noUncheckedIndexedAccess": true,                 /* Add 'undefined' to a type when accessed using an index. */
-    // "noImplicitOverride": true,                       /* Ensure overriding members in derived classes are marked with an override modifier. */
-    // "noPropertyAccessFromIndexSignature": true,       /* Enforces using indexed accessors for keys declared using an indexed type. */
-    // "allowUnusedLabels": true,                        /* Disable error reporting for unused labels. */
-    // "allowUnreachableCode": true,                     /* Disable error reporting for unreachable code. */
+		/* Type Checking */
+		"strict": true /* Enable all strict type-checking options. */,
+		"noImplicitAny": true /* Enable error reporting for expressions and declarations with an implied 'any' type. */,
+		"strictNullChecks": true /* When type checking, take into account 'null' and 'undefined'. */,
+		// "strictFunctionTypes": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
+		// "strictBindCallApply": true,                      /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
+		"strictPropertyInitialization": false /* Check for class properties that are declared but not set in the constructor. */,
+		// "noImplicitThis": true,                           /* Enable error reporting when 'this' is given the type 'any'. */
+		// "useUnknownInCatchVariables": true,               /* Default catch clause variables as 'unknown' instead of 'any'. */
+		"alwaysStrict": true /* Ensure 'use strict' is always emitted. */,
+		// "noUnusedLocals": true,                           /* Enable error reporting when local variables aren't read. */
+		// "noUnusedParameters": true,                       /* Raise an error when a function parameter isn't read. */
+		// "exactOptionalPropertyTypes": true,               /* Interpret optional property types as written, rather than adding 'undefined'. */
+		// "noImplicitReturns": true,                        /* Enable error reporting for codepaths that do not explicitly return in a function. */
+		// "noFallthroughCasesInSwitch": true,               /* Enable error reporting for fallthrough cases in switch statements. */
+		// "noUncheckedIndexedAccess": true,                 /* Add 'undefined' to a type when accessed using an index. */
+		// "noImplicitOverride": true,                       /* Ensure overriding members in derived classes are marked with an override modifier. */
+		// "noPropertyAccessFromIndexSignature": true,       /* Enforces using indexed accessors for keys declared using an indexed type. */
+		// "allowUnusedLabels": true,                        /* Disable error reporting for unused labels. */
+		// "allowUnreachableCode": true,                     /* Disable error reporting for unreachable code. */
 
-    /* Completeness */
-    // "skipDefaultLibCheck": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */
-    "skipLibCheck": true                                 /* Skip type checking all .d.ts files. */
-  }
+		/* Completeness */
+		// "skipDefaultLibCheck": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */
+		"skipLibCheck": true /* Skip type checking all .d.ts files. */
+	}
 }