summary refs log tree commit diff
path: root/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/util')
-rw-r--r--src/util/config/Config.ts46
-rw-r--r--src/util/config/index.ts2
-rw-r--r--src/util/config/types/ApiConfiguration.ts5
-rw-r--r--src/util/config/types/ClientConfiguration.ts8
-rw-r--r--src/util/config/types/DefaultsConfiguration.ts6
-rw-r--r--src/util/config/types/EndpointConfiguration.ts4
-rw-r--r--src/util/config/types/GeneralConfiguration.ts12
-rw-r--r--src/util/config/types/GifConfiguration.ts5
-rw-r--r--src/util/config/types/GuildConfiguration.ts6
-rw-r--r--src/util/config/types/KafkaConfiguration.ts5
-rw-r--r--src/util/config/types/LimitConfigurations.ts9
-rw-r--r--src/util/config/types/LoginConfiguration.ts3
-rw-r--r--src/util/config/types/MetricsConfiguration.ts3
-rw-r--r--src/util/config/types/RabbitMQConfiguration.ts3
-rw-r--r--src/util/config/types/RegionConfiguration.ts16
-rw-r--r--src/util/config/types/RegisterConfiguration.ts19
-rw-r--r--src/util/config/types/SecurityConfiguration.ts19
-rw-r--r--src/util/config/types/SentryConfiguration.ts8
-rw-r--r--src/util/config/types/TemplateConfiguration.ts6
-rw-r--r--src/util/config/types/index.ts18
-rw-r--r--src/util/config/types/subconfigurations/client/ClientReleaseConfiguration.ts4
-rw-r--r--src/util/config/types/subconfigurations/client/index.ts1
-rw-r--r--src/util/config/types/subconfigurations/defaults/GuildDefaults.ts8
-rw-r--r--src/util/config/types/subconfigurations/defaults/UserDefaults.ts5
-rw-r--r--src/util/config/types/subconfigurations/defaults/index.ts2
-rw-r--r--src/util/config/types/subconfigurations/guild/AutoJoin.ts5
-rw-r--r--src/util/config/types/subconfigurations/guild/Discovery.ts6
-rw-r--r--src/util/config/types/subconfigurations/guild/index.ts2
-rw-r--r--src/util/config/types/subconfigurations/index.ts8
-rw-r--r--src/util/config/types/subconfigurations/kafka/KafkaBroker.ts4
-rw-r--r--src/util/config/types/subconfigurations/kafka/index.ts1
-rw-r--r--src/util/config/types/subconfigurations/limits/ChannelLimits.ts5
-rw-r--r--src/util/config/types/subconfigurations/limits/GuildLimits.ts8
-rw-r--r--src/util/config/types/subconfigurations/limits/MessageLimits.ts8
-rw-r--r--src/util/config/types/subconfigurations/limits/RateLimits.ts18
-rw-r--r--src/util/config/types/subconfigurations/limits/UserLimits.ts5
-rw-r--r--src/util/config/types/subconfigurations/limits/index.ts6
-rw-r--r--src/util/config/types/subconfigurations/limits/ratelimits/Auth.ts12
-rw-r--r--src/util/config/types/subconfigurations/limits/ratelimits/RateLimitOptions.ts6
-rw-r--r--src/util/config/types/subconfigurations/limits/ratelimits/Route.ts19
-rw-r--r--src/util/config/types/subconfigurations/limits/ratelimits/index.ts3
-rw-r--r--src/util/config/types/subconfigurations/region/Region.ts12
-rw-r--r--src/util/config/types/subconfigurations/region/index.ts1
-rw-r--r--src/util/config/types/subconfigurations/register/DateOfBirth.ts4
-rw-r--r--src/util/config/types/subconfigurations/register/Email.ts7
-rw-r--r--src/util/config/types/subconfigurations/register/Password.ts7
-rw-r--r--src/util/config/types/subconfigurations/register/index.ts3
-rw-r--r--src/util/config/types/subconfigurations/security/Captcha.ts6
-rw-r--r--src/util/config/types/subconfigurations/security/TwoFactor.ts3
-rw-r--r--src/util/config/types/subconfigurations/security/index.ts2
-rw-r--r--src/util/dtos/DmChannelDTO.ts41
-rw-r--r--src/util/dtos/UserDTO.ts17
-rw-r--r--src/util/dtos/index.ts2
-rw-r--r--src/util/entities/Application.ts154
-rw-r--r--src/util/entities/Attachment.ts43
-rw-r--r--src/util/entities/AuditLog.ts194
-rw-r--r--src/util/entities/BackupCodes.ts19
-rw-r--r--src/util/entities/Ban.ts41
-rw-r--r--src/util/entities/BaseClass.ts26
-rw-r--r--src/util/entities/Categories.ts33
-rw-r--r--src/util/entities/Channel.ts389
-rw-r--r--src/util/entities/ClientRelease.ts26
-rw-r--r--src/util/entities/Config.ts11
-rw-r--r--src/util/entities/ConnectedAccount.ts42
-rw-r--r--src/util/entities/Emoji.ts45
-rw-r--r--src/util/entities/Encryption.ts25
-rw-r--r--src/util/entities/Group.ts33
-rw-r--r--src/util/entities/Guild.ts357
-rw-r--r--src/util/entities/Invite.ts88
-rw-r--r--src/util/entities/Member.ts334
-rw-r--r--src/util/entities/Message.ts271
-rw-r--r--src/util/entities/Migration.ts16
-rw-r--r--src/util/entities/Note.ts18
-rw-r--r--src/util/entities/RateLimit.ts17
-rw-r--r--src/util/entities/ReadState.ts54
-rw-r--r--src/util/entities/Recipient.ts30
-rw-r--r--src/util/entities/Relationship.ts49
-rw-r--r--src/util/entities/Role.ts51
-rw-r--r--src/util/entities/Session.ts40
-rw-r--r--src/util/entities/Sticker.ts66
-rw-r--r--src/util/entities/StickerPack.ts31
-rw-r--r--src/util/entities/Team.ts27
-rw-r--r--src/util/entities/TeamMember.ts37
-rw-r--r--src/util/entities/Template.ts44
-rw-r--r--src/util/entities/User.ts321
-rw-r--r--src/util/entities/UserGroup.ts35
-rw-r--r--src/util/entities/UserSettings.ts119
-rw-r--r--src/util/entities/VoiceState.ts77
-rw-r--r--src/util/entities/Webhook.ts76
-rw-r--r--src/util/entities/index.ts33
-rw-r--r--src/util/index.ts9
-rw-r--r--src/util/interfaces/Activity.ts44
-rw-r--r--src/util/interfaces/Event.ts640
-rw-r--r--src/util/interfaces/Interaction.ts34
-rw-r--r--src/util/interfaces/Presence.ts12
-rw-r--r--src/util/interfaces/Status.ts7
-rw-r--r--src/util/interfaces/index.ts5
-rw-r--r--src/util/migrations/mariadb/1659901151025-initial.ts1218
-rw-r--r--src/util/migrations/mariadb/1659921859145-premium_since_as_date.ts25
-rw-r--r--src/util/migrations/mariadb/1660130586602-updated-applications.ts184
-rw-r--r--src/util/migrations/mariadb/1661273147273-test.ts149
-rw-r--r--src/util/migrations/mariadb/1661273179287-test2.ts18
-rw-r--r--src/util/migrations/postgres/1659899687168-initial.ts1244
-rw-r--r--src/util/migrations/postgres/1659921826567-premium_since_as_date.ts25
-rw-r--r--src/util/migrations/postgres/1660130561959-updated-applications.ts181
-rw-r--r--src/util/migrations/postgres/1660257815436-CodeCleanup2.ts58
-rw-r--r--src/util/migrations/postgres/1660258372154-CodeCleanup3.ts18
-rw-r--r--src/util/migrations/postgres/1660260565996-CodeCleanup4.ts32
-rw-r--r--src/util/migrations/postgres/1660265907544-CodeCleanup5.ts25
-rw-r--r--src/util/migrations/postgres/1660416055566-InvitersAreDeletable.ts25
-rw-r--r--src/util/migrations/postgres/1660549242936-fix_nullables.ts29
-rw-r--r--src/util/migrations/sqlite/1659899662635-initial.ts3528
-rw-r--r--src/util/migrations/sqlite/1659921722863-premium_since_as_date.ts251
-rw-r--r--src/util/migrations/sqlite/1660130536131-updated-applications.ts828
-rw-r--r--src/util/migrations/sqlite/1660257576211-CodeCleanup1.ts325
-rw-r--r--src/util/migrations/sqlite/1660257795259-CodeCleanup2.ts571
-rw-r--r--src/util/migrations/sqlite/1660258351379-CodeCleanup3.ts230
-rw-r--r--src/util/migrations/sqlite/1660260672914-CodeCleanup4.ts458
-rw-r--r--src/util/migrations/sqlite/1660416010862-InvitersAreDeletable.ts245
-rw-r--r--src/util/migrations/sqlite/1660538628956-sync_migrations.ts171
-rw-r--r--src/util/migrations/sqlite/1660549233583-fix_nullables.ts239
-rw-r--r--src/util/schemas/ActivitySchema.ts51
-rw-r--r--src/util/schemas/BanCreateSchema.ts4
-rw-r--r--src/util/schemas/BanModeratorSchema.ts7
-rw-r--r--src/util/schemas/BanRegistrySchema.ts8
-rw-r--r--src/util/schemas/BulkDeleteSchema.ts3
-rw-r--r--src/util/schemas/ChannelModifySchema.ts28
-rw-r--r--src/util/schemas/ChannelPermissionOverwriteSchema.ts5
-rw-r--r--src/util/schemas/ChannelReorderSchema.ts1
-rw-r--r--src/util/schemas/DmChannelCreateSchema.ts4
-rw-r--r--src/util/schemas/EmojiCreateSchema.ts6
-rw-r--r--src/util/schemas/EmojiModifySchema.ts4
-rw-r--r--src/util/schemas/GuildCreateSchema.ts14
-rw-r--r--src/util/schemas/GuildTemplateCreateSchema.ts4
-rw-r--r--src/util/schemas/GuildUpdateSchema.ts18
-rw-r--r--src/util/schemas/GuildUpdateWelcomeScreenSchema.ts10
-rw-r--r--src/util/schemas/IdentifySchema.ts89
-rw-r--r--src/util/schemas/InviteCreateSchema.ts11
-rw-r--r--src/util/schemas/LazyRequestSchema.ts19
-rw-r--r--src/util/schemas/LoginSchema.ts8
-rw-r--r--src/util/schemas/MemberChangeSchema.ts3
-rw-r--r--src/util/schemas/MemberNickChangeSchema.ts3
-rw-r--r--src/util/schemas/MessageAcknowledgeSchema.ts8
-rw-r--r--src/util/schemas/MessageCreateSchema.ts33
-rw-r--r--src/util/schemas/MfaCodesSchema.ts4
-rw-r--r--src/util/schemas/ModifyGuildStickerSchema.ts15
-rw-r--r--src/util/schemas/PruneSchema.ts6
-rw-r--r--src/util/schemas/PurgeSchema.ts4
-rw-r--r--src/util/schemas/RegisterSchema.ts26
-rw-r--r--src/util/schemas/RelationshipPostSchema.ts4
-rw-r--r--src/util/schemas/RelationshipPutSchema.ts5
-rw-r--r--src/util/schemas/RoleModifySchema.ts10
-rw-r--r--src/util/schemas/RolePositionUpdateSchema.ts4
-rw-r--r--src/util/schemas/TemplateCreateSchema.ts4
-rw-r--r--src/util/schemas/TemplateModifySchema.ts4
-rw-r--r--src/util/schemas/TotpDisableSchema.ts3
-rw-r--r--src/util/schemas/TotpEnableSchema.ts5
-rw-r--r--src/util/schemas/TotpSchema.ts6
-rw-r--r--src/util/schemas/UserModifySchema.ts19
-rw-r--r--src/util/schemas/UserSettingsSchema.ts3
-rw-r--r--src/util/schemas/VanityUrlSchema.ts7
-rw-r--r--src/util/schemas/VoiceStateUpdateSchema.ts18
-rw-r--r--src/util/schemas/WebhookCreateSchema.ts8
-rw-r--r--src/util/schemas/WidgetModifySchema.ts4
-rw-r--r--src/util/schemas/index.ts43
-rw-r--r--src/util/util/ApiError.ts27
-rw-r--r--src/util/util/Array.ts3
-rw-r--r--src/util/util/AutoUpdate.ts83
-rw-r--r--src/util/util/BitField.ts150
-rw-r--r--src/util/util/Categories.ts1
-rw-r--r--src/util/util/Config.ts105
-rw-r--r--src/util/util/Constants.ts726
-rw-r--r--src/util/util/Database.ts107
-rw-r--r--src/util/util/Email.ts25
-rw-r--r--src/util/util/Event.ts117
-rw-r--r--src/util/util/FieldError.ts23
-rw-r--r--src/util/util/Intents.ts33
-rw-r--r--src/util/util/InvisibleCharacters.ts57
-rw-r--r--src/util/util/MFA.ts18
-rw-r--r--src/util/util/MessageFlags.ts20
-rw-r--r--src/util/util/Permissions.ts273
-rw-r--r--src/util/util/RabbitMQ.ts19
-rw-r--r--src/util/util/Regex.ts7
-rw-r--r--src/util/util/Rights.ts94
-rw-r--r--src/util/util/Snowflake.ts131
-rw-r--r--src/util/util/String.ts7
-rw-r--r--src/util/util/Token.ts50
-rw-r--r--src/util/util/TraverseDirectory.ts10
-rw-r--r--src/util/util/cdn.ts55
-rw-r--r--src/util/util/imports/Checks.ts121
-rw-r--r--src/util/util/imports/HTTPError.ts5
-rw-r--r--src/util/util/imports/OrmUtils.ts96
-rw-r--r--src/util/util/imports/index.ts3
-rw-r--r--src/util/util/index.ts25
194 files changed, 17478 insertions, 0 deletions
diff --git a/src/util/config/Config.ts b/src/util/config/Config.ts
new file mode 100644
index 00000000..36c4509d
--- /dev/null
+++ b/src/util/config/Config.ts
@@ -0,0 +1,46 @@
+import {
+	ApiConfiguration,
+	ClientConfiguration,
+	DefaultsConfiguration,
+	EndpointConfiguration,
+	GeneralConfiguration,
+	GifConfiguration,
+	GuildConfiguration,
+	KafkaConfiguration,
+	LimitsConfiguration,
+	LoginConfiguration,
+	MetricsConfiguration,
+	RabbitMQConfiguration,
+	RegionConfiguration,
+	RegisterConfiguration,
+	SecurityConfiguration,
+	SentryConfiguration,
+	TemplateConfiguration
+} from ".";
+
+export class ConfigValue {
+	gateway: EndpointConfiguration = {
+		endpointPublic: '${location.protocol === "https:" ? "wss://" : "ws://"}${location.host}',
+		endpointPrivate: `ws://localhost:3001`
+	};
+	cdn: EndpointConfiguration = {
+		endpointPublic: "${location.host}",
+		endpointPrivate: `http://localhost:3001`
+	};
+	api: ApiConfiguration = new ApiConfiguration();
+	general: GeneralConfiguration = new GeneralConfiguration();
+	limits: LimitsConfiguration = new LimitsConfiguration();
+	security: SecurityConfiguration = new SecurityConfiguration();
+	login: LoginConfiguration = new LoginConfiguration();
+	register: RegisterConfiguration = new RegisterConfiguration();
+	regions: RegionConfiguration = new RegionConfiguration();
+	guild: GuildConfiguration = new GuildConfiguration();
+	gif: GifConfiguration = new GifConfiguration();
+	rabbitmq: RabbitMQConfiguration = new RabbitMQConfiguration();
+	kafka: KafkaConfiguration = new KafkaConfiguration();
+	templates: TemplateConfiguration = new TemplateConfiguration();
+	client: ClientConfiguration = new ClientConfiguration();
+	metrics: MetricsConfiguration = new MetricsConfiguration();
+	sentry: SentryConfiguration = new SentryConfiguration();
+	defaults: DefaultsConfiguration = new DefaultsConfiguration();
+}
diff --git a/src/util/config/index.ts b/src/util/config/index.ts
new file mode 100644
index 00000000..0a9b58ae
--- /dev/null
+++ b/src/util/config/index.ts
@@ -0,0 +1,2 @@
+export * from "./Config";
+export * from "./types/index";
diff --git a/src/util/config/types/ApiConfiguration.ts b/src/util/config/types/ApiConfiguration.ts
new file mode 100644
index 00000000..442a5986
--- /dev/null
+++ b/src/util/config/types/ApiConfiguration.ts
@@ -0,0 +1,5 @@
+export class ApiConfiguration {
+	defaultVersion: string = "9";
+	activeVersions: string[] = ["6", "7", "8", "9"];
+	useFosscordEnhancements: boolean = true;
+}
diff --git a/src/util/config/types/ClientConfiguration.ts b/src/util/config/types/ClientConfiguration.ts
new file mode 100644
index 00000000..44704404
--- /dev/null
+++ b/src/util/config/types/ClientConfiguration.ts
@@ -0,0 +1,8 @@
+import { ClientReleaseConfiguration } from ".";
+
+export class ClientConfiguration {
+	//classes
+	releases: ClientReleaseConfiguration = new ClientReleaseConfiguration();
+	//base types
+	useTestClient: boolean = true;
+}
diff --git a/src/util/config/types/DefaultsConfiguration.ts b/src/util/config/types/DefaultsConfiguration.ts
new file mode 100644
index 00000000..d5ee39e7
--- /dev/null
+++ b/src/util/config/types/DefaultsConfiguration.ts
@@ -0,0 +1,6 @@
+import { GuildDefaults, UserDefaults } from ".";
+
+export class DefaultsConfiguration {
+	guild: GuildDefaults = new GuildDefaults();
+	user: UserDefaults = new UserDefaults();
+}
diff --git a/src/util/config/types/EndpointConfiguration.ts b/src/util/config/types/EndpointConfiguration.ts
new file mode 100644
index 00000000..26f3106f
--- /dev/null
+++ b/src/util/config/types/EndpointConfiguration.ts
@@ -0,0 +1,4 @@
+export class EndpointConfiguration {
+	endpointPrivate: string | null = null;
+	endpointPublic: string | null = null;
+}
diff --git a/src/util/config/types/GeneralConfiguration.ts b/src/util/config/types/GeneralConfiguration.ts
new file mode 100644
index 00000000..5cb8df89
--- /dev/null
+++ b/src/util/config/types/GeneralConfiguration.ts
@@ -0,0 +1,12 @@
+import { Snowflake } from "../../util";
+
+export class GeneralConfiguration {
+	instanceName: string = "Fosscord Instance";
+	instanceDescription: string | null = "This is a Fosscord instance made in the pre-release days";
+	frontPage: string | null = null;
+	tosPage: string | null = null;
+	correspondenceEmail: string | null = "noreply@localhost.local";
+	correspondenceUserID: string | null = null;
+	image: string | null = null;
+	instanceId: string = Snowflake.generate();
+}
diff --git a/src/util/config/types/GifConfiguration.ts b/src/util/config/types/GifConfiguration.ts
new file mode 100644
index 00000000..565c2ac0
--- /dev/null
+++ b/src/util/config/types/GifConfiguration.ts
@@ -0,0 +1,5 @@
+export class GifConfiguration {
+	enabled: boolean = true;
+	provider: "tenor" = "tenor"; // more coming soon
+	apiKey?: string = "LIVDSRZULELA";
+}
diff --git a/src/util/config/types/GuildConfiguration.ts b/src/util/config/types/GuildConfiguration.ts
new file mode 100644
index 00000000..ebc1b442
--- /dev/null
+++ b/src/util/config/types/GuildConfiguration.ts
@@ -0,0 +1,6 @@
+import { AutoJoinConfiguration, DiscoveryConfiguration } from ".";
+
+export class GuildConfiguration {
+	discovery: DiscoveryConfiguration = new DiscoveryConfiguration();
+	autoJoin: AutoJoinConfiguration = new AutoJoinConfiguration();
+}
diff --git a/src/util/config/types/KafkaConfiguration.ts b/src/util/config/types/KafkaConfiguration.ts
new file mode 100644
index 00000000..a3aa8058
--- /dev/null
+++ b/src/util/config/types/KafkaConfiguration.ts
@@ -0,0 +1,5 @@
+import { KafkaBroker } from ".";
+
+export class KafkaConfiguration {
+	brokers: KafkaBroker[] | null = null;
+}
diff --git a/src/util/config/types/LimitConfigurations.ts b/src/util/config/types/LimitConfigurations.ts
new file mode 100644
index 00000000..a3a52cf5
--- /dev/null
+++ b/src/util/config/types/LimitConfigurations.ts
@@ -0,0 +1,9 @@
+import { ChannelLimits, GuildLimits, MessageLimits, RateLimits, UserLimits } from ".";
+
+export class LimitsConfiguration {
+	user: UserLimits = new UserLimits();
+	guild: GuildLimits = new GuildLimits();
+	message: MessageLimits = new MessageLimits();
+	channel: ChannelLimits = new ChannelLimits();
+	rate: RateLimits = new RateLimits();
+}
diff --git a/src/util/config/types/LoginConfiguration.ts b/src/util/config/types/LoginConfiguration.ts
new file mode 100644
index 00000000..d8b737b9
--- /dev/null
+++ b/src/util/config/types/LoginConfiguration.ts
@@ -0,0 +1,3 @@
+export class LoginConfiguration {
+	requireCaptcha: boolean = false;
+}
diff --git a/src/util/config/types/MetricsConfiguration.ts b/src/util/config/types/MetricsConfiguration.ts
new file mode 100644
index 00000000..f6b1d8e6
--- /dev/null
+++ b/src/util/config/types/MetricsConfiguration.ts
@@ -0,0 +1,3 @@
+export class MetricsConfiguration {
+	timeout: number = 30000;
+}
diff --git a/src/util/config/types/RabbitMQConfiguration.ts b/src/util/config/types/RabbitMQConfiguration.ts
new file mode 100644
index 00000000..bd4b6ca3
--- /dev/null
+++ b/src/util/config/types/RabbitMQConfiguration.ts
@@ -0,0 +1,3 @@
+export class RabbitMQConfiguration {
+	host: string | null = null;
+}
diff --git a/src/util/config/types/RegionConfiguration.ts b/src/util/config/types/RegionConfiguration.ts
new file mode 100644
index 00000000..b4b8c4a3
--- /dev/null
+++ b/src/util/config/types/RegionConfiguration.ts
@@ -0,0 +1,16 @@
+import { Region } from ".";
+
+export class RegionConfiguration {
+	default: string = "fosscord";
+	useDefaultAsOptimal: boolean = true;
+	available: Region[] = [
+		{
+			id: "fosscord",
+			name: "Fosscord",
+			endpoint: "127.0.0.1:3004",
+			vip: false,
+			custom: false,
+			deprecated: false
+		}
+	];
+}
diff --git a/src/util/config/types/RegisterConfiguration.ts b/src/util/config/types/RegisterConfiguration.ts
new file mode 100644
index 00000000..68946272
--- /dev/null
+++ b/src/util/config/types/RegisterConfiguration.ts
@@ -0,0 +1,19 @@
+import { DateOfBirthConfiguration, EmailConfiguration, PasswordConfiguration } from ".";
+
+export class RegisterConfiguration {
+	//classes
+	email: EmailConfiguration = new EmailConfiguration();
+	dateOfBirth: DateOfBirthConfiguration = new DateOfBirthConfiguration();
+	password: PasswordConfiguration = new PasswordConfiguration();
+	//base types
+	disabled: boolean = false;
+	requireCaptcha: boolean = true;
+	requireInvite: boolean = false;
+	allowGuests: boolean = true;
+	guestsRequireInvite: boolean = true;
+	allowNewRegistration: boolean = true;
+	allowMultipleAccounts: boolean = true;
+	blockProxies: boolean = true;
+	incrementingDiscriminators: boolean = false; // random otherwise
+	defaultRights: string = "0";
+}
diff --git a/src/util/config/types/SecurityConfiguration.ts b/src/util/config/types/SecurityConfiguration.ts
new file mode 100644
index 00000000..a2cebbd3
--- /dev/null
+++ b/src/util/config/types/SecurityConfiguration.ts
@@ -0,0 +1,19 @@
+import crypto from "crypto";
+import { CaptchaConfiguration, TwoFactorConfiguration } from ".";
+
+export class SecurityConfiguration {
+	//classes
+	captcha: CaptchaConfiguration = new CaptchaConfiguration();
+	twoFactor: TwoFactorConfiguration = new TwoFactorConfiguration();
+	//base types
+	autoUpdate: boolean | number = true;
+	requestSignature: string = crypto.randomBytes(32).toString("base64");
+	jwtSecret: string = crypto.randomBytes(256).toString("base64");
+	// header to get the real user ip address
+	// X-Forwarded-For for nginx/reverse proxies
+	// CF-Connecting-IP for cloudflare
+	forwadedFor: string | null = null;
+	ipdataApiKey: string | null = "eca677b284b3bac29eb72f5e496aa9047f26543605efe99ff2ce35c9";
+	mfaBackupCodeCount: number = 10;
+	mfaBackupCodeBytes: number = 4;
+}
diff --git a/src/util/config/types/SentryConfiguration.ts b/src/util/config/types/SentryConfiguration.ts
new file mode 100644
index 00000000..d50f5f4c
--- /dev/null
+++ b/src/util/config/types/SentryConfiguration.ts
@@ -0,0 +1,8 @@
+import { hostname } from "os";
+
+export class SentryConfiguration {
+	enabled: boolean = false;
+	endpoint: string = "https://05e8e3d005f34b7d97e920ae5870a5e5@sentry.thearcanebrony.net/6";
+	traceSampleRate: number = 1.0;
+	environment: string = hostname();
+}
diff --git a/src/util/config/types/TemplateConfiguration.ts b/src/util/config/types/TemplateConfiguration.ts
new file mode 100644
index 00000000..aade2934
--- /dev/null
+++ b/src/util/config/types/TemplateConfiguration.ts
@@ -0,0 +1,6 @@
+export class TemplateConfiguration {
+	enabled: boolean = true;
+	allowTemplateCreation: boolean = true;
+	allowDiscordTemplates: boolean = true;
+	allowRaws: boolean = true;
+}
diff --git a/src/util/config/types/index.ts b/src/util/config/types/index.ts
new file mode 100644
index 00000000..a8cdff4c
--- /dev/null
+++ b/src/util/config/types/index.ts
@@ -0,0 +1,18 @@
+export * from "./ApiConfiguration";
+export * from "./ClientConfiguration";
+export * from "./DefaultsConfiguration";
+export * from "./EndpointConfiguration";
+export * from "./GeneralConfiguration";
+export * from "./GifConfiguration";
+export * from "./GuildConfiguration";
+export * from "./KafkaConfiguration";
+export * from "./LimitConfigurations";
+export * from "./LoginConfiguration";
+export * from "./MetricsConfiguration";
+export * from "./RabbitMQConfiguration";
+export * from "./RegionConfiguration";
+export * from "./RegisterConfiguration";
+export * from "./SecurityConfiguration";
+export * from "./SentryConfiguration";
+export * from "./subconfigurations/index";
+export * from "./TemplateConfiguration";
diff --git a/src/util/config/types/subconfigurations/client/ClientReleaseConfiguration.ts b/src/util/config/types/subconfigurations/client/ClientReleaseConfiguration.ts
new file mode 100644
index 00000000..b082b711
--- /dev/null
+++ b/src/util/config/types/subconfigurations/client/ClientReleaseConfiguration.ts
@@ -0,0 +1,4 @@
+export class ClientReleaseConfiguration {
+	useLocalRelease: boolean = true; //TODO
+	upstreamVersion: string = "0.0.264";
+}
diff --git a/src/util/config/types/subconfigurations/client/index.ts b/src/util/config/types/subconfigurations/client/index.ts
new file mode 100644
index 00000000..96bbb0ca
--- /dev/null
+++ b/src/util/config/types/subconfigurations/client/index.ts
@@ -0,0 +1 @@
+export * from "./ClientReleaseConfiguration";
diff --git a/src/util/config/types/subconfigurations/defaults/GuildDefaults.ts b/src/util/config/types/subconfigurations/defaults/GuildDefaults.ts
new file mode 100644
index 00000000..435ae06c
--- /dev/null
+++ b/src/util/config/types/subconfigurations/defaults/GuildDefaults.ts
@@ -0,0 +1,8 @@
+export class GuildDefaults {
+	maxPresences: number = 250000;
+	maxVideoChannelUsers: number = 200;
+	afkTimeout: number = 300;
+	defaultMessageNotifications: number = 1;
+	explicitContentFilter: number = 0;
+	test: number = 123;
+}
diff --git a/src/util/config/types/subconfigurations/defaults/UserDefaults.ts b/src/util/config/types/subconfigurations/defaults/UserDefaults.ts
new file mode 100644
index 00000000..cc56be36
--- /dev/null
+++ b/src/util/config/types/subconfigurations/defaults/UserDefaults.ts
@@ -0,0 +1,5 @@
+export class UserDefaults {
+	premium: boolean = false;
+	premium_type: number = 2;
+	verified: boolean = true;
+}
diff --git a/src/util/config/types/subconfigurations/defaults/index.ts b/src/util/config/types/subconfigurations/defaults/index.ts
new file mode 100644
index 00000000..50258d1c
--- /dev/null
+++ b/src/util/config/types/subconfigurations/defaults/index.ts
@@ -0,0 +1,2 @@
+export * from "./GuildDefaults";
+export * from "./UserDefaults";
diff --git a/src/util/config/types/subconfigurations/guild/AutoJoin.ts b/src/util/config/types/subconfigurations/guild/AutoJoin.ts
new file mode 100644
index 00000000..4d7af352
--- /dev/null
+++ b/src/util/config/types/subconfigurations/guild/AutoJoin.ts
@@ -0,0 +1,5 @@
+export class AutoJoinConfiguration {
+	enabled: boolean = true;
+	guilds: string[] = [];
+	canLeave: boolean = true;
+}
diff --git a/src/util/config/types/subconfigurations/guild/Discovery.ts b/src/util/config/types/subconfigurations/guild/Discovery.ts
new file mode 100644
index 00000000..a7cb81db
--- /dev/null
+++ b/src/util/config/types/subconfigurations/guild/Discovery.ts
@@ -0,0 +1,6 @@
+export class DiscoveryConfiguration {
+	showAllGuilds: boolean = false;
+	useRecommendation: boolean = false; // TODO: Recommendation, privacy concern?
+	offset: number = 0;
+	limit: number = 24;
+}
diff --git a/src/util/config/types/subconfigurations/guild/index.ts b/src/util/config/types/subconfigurations/guild/index.ts
new file mode 100644
index 00000000..e9614856
--- /dev/null
+++ b/src/util/config/types/subconfigurations/guild/index.ts
@@ -0,0 +1,2 @@
+export * from "./AutoJoin";
+export * from "./Discovery";
diff --git a/src/util/config/types/subconfigurations/index.ts b/src/util/config/types/subconfigurations/index.ts
new file mode 100644
index 00000000..bfbadc92
--- /dev/null
+++ b/src/util/config/types/subconfigurations/index.ts
@@ -0,0 +1,8 @@
+export * from "./client/index";
+export * from "./defaults/index";
+export * from "./guild/index";
+export * from "./kafka/index";
+export * from "./limits/index";
+export * from "./region/index";
+export * from "./register/index";
+export * from "./security/index";
diff --git a/src/util/config/types/subconfigurations/kafka/KafkaBroker.ts b/src/util/config/types/subconfigurations/kafka/KafkaBroker.ts
new file mode 100644
index 00000000..f7dc1cf7
--- /dev/null
+++ b/src/util/config/types/subconfigurations/kafka/KafkaBroker.ts
@@ -0,0 +1,4 @@
+export interface KafkaBroker {
+	ip: string;
+	port: number;
+}
diff --git a/src/util/config/types/subconfigurations/kafka/index.ts b/src/util/config/types/subconfigurations/kafka/index.ts
new file mode 100644
index 00000000..2c633950
--- /dev/null
+++ b/src/util/config/types/subconfigurations/kafka/index.ts
@@ -0,0 +1 @@
+export * from "./KafkaBroker";
diff --git a/src/util/config/types/subconfigurations/limits/ChannelLimits.ts b/src/util/config/types/subconfigurations/limits/ChannelLimits.ts
new file mode 100644
index 00000000..76eeeb41
--- /dev/null
+++ b/src/util/config/types/subconfigurations/limits/ChannelLimits.ts
@@ -0,0 +1,5 @@
+export class ChannelLimits {
+	maxPins: number = 500;
+	maxTopic: number = 1024;
+	maxWebhooks: number = 100;
+}
diff --git a/src/util/config/types/subconfigurations/limits/GuildLimits.ts b/src/util/config/types/subconfigurations/limits/GuildLimits.ts
new file mode 100644
index 00000000..015654cb
--- /dev/null
+++ b/src/util/config/types/subconfigurations/limits/GuildLimits.ts
@@ -0,0 +1,8 @@
+export class GuildLimits {
+	maxRoles: number = 1000;
+	maxEmojis: number = 2000;
+	maxMembers: number = 25000000;
+	maxChannels: number = 65535;
+	maxChannelsInCategory: number = 65535;
+	hideOfflineMember: number = 3;
+}
diff --git a/src/util/config/types/subconfigurations/limits/MessageLimits.ts b/src/util/config/types/subconfigurations/limits/MessageLimits.ts
new file mode 100644
index 00000000..684a5057
--- /dev/null
+++ b/src/util/config/types/subconfigurations/limits/MessageLimits.ts
@@ -0,0 +1,8 @@
+export class MessageLimits {
+	maxCharacters: number = 1048576;
+	maxTTSCharacters: number = 160;
+	maxReactions: number = 2048;
+	maxAttachmentSize: number = 1024 * 1024 * 1024;
+	maxBulkDelete: number = 1000;
+	maxEmbedDownloadSize: number = 1024 * 1024 * 5;
+}
diff --git a/src/util/config/types/subconfigurations/limits/RateLimits.ts b/src/util/config/types/subconfigurations/limits/RateLimits.ts
new file mode 100644
index 00000000..764acdd6
--- /dev/null
+++ b/src/util/config/types/subconfigurations/limits/RateLimits.ts
@@ -0,0 +1,18 @@
+import { RateLimitOptions, RouteRateLimit } from ".";
+
+export class RateLimits {
+	disabled: boolean = true;
+	ip: Omit<RateLimitOptions, "bot_count"> = {
+		count: 500,
+		window: 5
+	};
+	global: RateLimitOptions = {
+		count: 250,
+		window: 5
+	};
+	error: RateLimitOptions = {
+		count: 10,
+		window: 5
+	};
+	routes: RouteRateLimit = new RouteRateLimit();
+}
diff --git a/src/util/config/types/subconfigurations/limits/UserLimits.ts b/src/util/config/types/subconfigurations/limits/UserLimits.ts
new file mode 100644
index 00000000..b8bdcb2d
--- /dev/null
+++ b/src/util/config/types/subconfigurations/limits/UserLimits.ts
@@ -0,0 +1,5 @@
+export class UserLimits {
+	maxGuilds: number = 1048576;
+	maxUsername: number = 127;
+	maxFriends: number = 5000;
+}
diff --git a/src/util/config/types/subconfigurations/limits/index.ts b/src/util/config/types/subconfigurations/limits/index.ts
new file mode 100644
index 00000000..a4911542
--- /dev/null
+++ b/src/util/config/types/subconfigurations/limits/index.ts
@@ -0,0 +1,6 @@
+export * from "./ChannelLimits";
+export * from "./GuildLimits";
+export * from "./MessageLimits";
+export * from "./RateLimits";
+export * from "./ratelimits/index";
+export * from "./UserLimits";
diff --git a/src/util/config/types/subconfigurations/limits/ratelimits/Auth.ts b/src/util/config/types/subconfigurations/limits/ratelimits/Auth.ts
new file mode 100644
index 00000000..0f363e7f
--- /dev/null
+++ b/src/util/config/types/subconfigurations/limits/ratelimits/Auth.ts
@@ -0,0 +1,12 @@
+import { RateLimitOptions } from "./RateLimitOptions";
+
+export class AuthRateLimit {
+	login: RateLimitOptions = {
+		count: 5,
+		window: 60
+	};
+	register: RateLimitOptions = {
+		count: 2,
+		window: 60 * 60 * 12
+	};
+}
diff --git a/src/util/config/types/subconfigurations/limits/ratelimits/RateLimitOptions.ts b/src/util/config/types/subconfigurations/limits/ratelimits/RateLimitOptions.ts
new file mode 100644
index 00000000..829813fb
--- /dev/null
+++ b/src/util/config/types/subconfigurations/limits/ratelimits/RateLimitOptions.ts
@@ -0,0 +1,6 @@
+export interface RateLimitOptions {
+	bot?: number;
+	count: number;
+	window: number;
+	onyIp?: boolean;
+}
diff --git a/src/util/config/types/subconfigurations/limits/ratelimits/Route.ts b/src/util/config/types/subconfigurations/limits/ratelimits/Route.ts
new file mode 100644
index 00000000..6890699e
--- /dev/null
+++ b/src/util/config/types/subconfigurations/limits/ratelimits/Route.ts
@@ -0,0 +1,19 @@
+import { AuthRateLimit } from "./Auth";
+import { RateLimitOptions } from "./RateLimitOptions";
+
+export class RouteRateLimit {
+	guild: RateLimitOptions = {
+		count: 5,
+		window: 5
+	};
+	webhook: RateLimitOptions = {
+		count: 10,
+		window: 5
+	};
+	channel: RateLimitOptions = {
+		count: 10,
+		window: 5
+	};
+	auth: AuthRateLimit = new AuthRateLimit();
+	// TODO: rate limit configuration for all routes
+}
diff --git a/src/util/config/types/subconfigurations/limits/ratelimits/index.ts b/src/util/config/types/subconfigurations/limits/ratelimits/index.ts
new file mode 100644
index 00000000..432eb601
--- /dev/null
+++ b/src/util/config/types/subconfigurations/limits/ratelimits/index.ts
@@ -0,0 +1,3 @@
+export * from "./Auth";
+export * from "./RateLimitOptions";
+export * from "./Route";
diff --git a/src/util/config/types/subconfigurations/region/Region.ts b/src/util/config/types/subconfigurations/region/Region.ts
new file mode 100644
index 00000000..c1bcfd01
--- /dev/null
+++ b/src/util/config/types/subconfigurations/region/Region.ts
@@ -0,0 +1,12 @@
+export interface Region {
+	id: string;
+	name: string;
+	endpoint: string;
+	location?: {
+		latitude: number;
+		longitude: number;
+	};
+	vip: boolean;
+	custom: boolean;
+	deprecated: boolean;
+}
diff --git a/src/util/config/types/subconfigurations/region/index.ts b/src/util/config/types/subconfigurations/region/index.ts
new file mode 100644
index 00000000..2beb8de7
--- /dev/null
+++ b/src/util/config/types/subconfigurations/region/index.ts
@@ -0,0 +1 @@
+export * from "./Region";
diff --git a/src/util/config/types/subconfigurations/register/DateOfBirth.ts b/src/util/config/types/subconfigurations/register/DateOfBirth.ts
new file mode 100644
index 00000000..4831a4b7
--- /dev/null
+++ b/src/util/config/types/subconfigurations/register/DateOfBirth.ts
@@ -0,0 +1,4 @@
+export class DateOfBirthConfiguration {
+	required: boolean = true;
+	minimum: number = 13; // in years
+}
diff --git a/src/util/config/types/subconfigurations/register/Email.ts b/src/util/config/types/subconfigurations/register/Email.ts
new file mode 100644
index 00000000..7f54faa7
--- /dev/null
+++ b/src/util/config/types/subconfigurations/register/Email.ts
@@ -0,0 +1,7 @@
+export class EmailConfiguration {
+	required: boolean = false;
+	allowlist: boolean = false;
+	blocklist: boolean = true;
+	domains: string[] = []; // TODO: efficiently save domain blocklist in database
+	// domains: fs.readFileSync(__dirname + "/blockedEmailDomains.txt", { encoding: "utf8" }).split("\n"),
+}
diff --git a/src/util/config/types/subconfigurations/register/Password.ts b/src/util/config/types/subconfigurations/register/Password.ts
new file mode 100644
index 00000000..383bdcfa
--- /dev/null
+++ b/src/util/config/types/subconfigurations/register/Password.ts
@@ -0,0 +1,7 @@
+export class PasswordConfiguration {
+	required: boolean = false;
+	minLength: number = 8;
+	minNumbers: number = 2;
+	minUpperCase: number = 2;
+	minSymbols: number = 0;
+}
diff --git a/src/util/config/types/subconfigurations/register/index.ts b/src/util/config/types/subconfigurations/register/index.ts
new file mode 100644
index 00000000..d9738120
--- /dev/null
+++ b/src/util/config/types/subconfigurations/register/index.ts
@@ -0,0 +1,3 @@
+export * from "./DateOfBirth";
+export * from "./Email";
+export * from "./Password";
diff --git a/src/util/config/types/subconfigurations/security/Captcha.ts b/src/util/config/types/subconfigurations/security/Captcha.ts
new file mode 100644
index 00000000..21c4ef44
--- /dev/null
+++ b/src/util/config/types/subconfigurations/security/Captcha.ts
@@ -0,0 +1,6 @@
+export class CaptchaConfiguration {
+	enabled: boolean = false;
+	service: "recaptcha" | "hcaptcha" | null = null; // TODO: hcaptcha, custom
+	sitekey: string | null = null;
+	secret: string | null = null;
+}
diff --git a/src/util/config/types/subconfigurations/security/TwoFactor.ts b/src/util/config/types/subconfigurations/security/TwoFactor.ts
new file mode 100644
index 00000000..20d2f9ab
--- /dev/null
+++ b/src/util/config/types/subconfigurations/security/TwoFactor.ts
@@ -0,0 +1,3 @@
+export class TwoFactorConfiguration {
+	generateBackupCodes: boolean = true;
+}
diff --git a/src/util/config/types/subconfigurations/security/index.ts b/src/util/config/types/subconfigurations/security/index.ts
new file mode 100644
index 00000000..17619589
--- /dev/null
+++ b/src/util/config/types/subconfigurations/security/index.ts
@@ -0,0 +1,2 @@
+export * from "./Captcha";
+export * from "./TwoFactor";
diff --git a/src/util/dtos/DmChannelDTO.ts b/src/util/dtos/DmChannelDTO.ts
new file mode 100644
index 00000000..93b1adfa
--- /dev/null
+++ b/src/util/dtos/DmChannelDTO.ts
@@ -0,0 +1,41 @@
+import { Channel, PublicUserProjection, User } from "../entities";
+import { MinimalPublicUserDTO } from "./UserDTO";
+
+export class DmChannelDTO {
+	icon: string | null;
+	id: string;
+	last_message_id: string | null;
+	name: string | null;
+	origin_channel_id: string | null;
+	owner_id?: string;
+	recipients: MinimalPublicUserDTO[];
+	type: number;
+
+	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;
+		obj.last_message_id = channel.last_message_id || null;
+		obj.name = channel.name || null;
+		obj.origin_channel_id = origin_channel_id || null;
+		obj.owner_id = channel.owner_id;
+		obj.type = channel.type;
+		obj.recipients = (
+			await Promise.all(
+				channel
+					.recipients!.filter((r) => !excluded_recipients.includes(r.user_id))
+					.map(async (r) => {
+						return await User.findOneOrFail({ where: { id: r.user_id }, select: PublicUserProjection });
+					})
+			)
+		).map((u) => new MinimalPublicUserDTO(u));
+		return obj;
+	}
+
+	excludedRecipients(excluded_recipients: string[]): DmChannelDTO {
+		return {
+			...this,
+			recipients: this.recipients.filter((r) => !excluded_recipients.includes(r.id))
+		};
+	}
+}
diff --git a/src/util/dtos/UserDTO.ts b/src/util/dtos/UserDTO.ts
new file mode 100644
index 00000000..ee2752a4
--- /dev/null
+++ b/src/util/dtos/UserDTO.ts
@@ -0,0 +1,17 @@
+import { User } from "../entities";
+
+export class MinimalPublicUserDTO {
+	avatar?: string | null;
+	discriminator: string;
+	id: string;
+	public_flags: number;
+	username: string;
+
+	constructor(user: User) {
+		this.avatar = user.avatar;
+		this.discriminator = user.discriminator;
+		this.id = user.id;
+		this.public_flags = user.public_flags;
+		this.username = user.username;
+	}
+}
diff --git a/src/util/dtos/index.ts b/src/util/dtos/index.ts
new file mode 100644
index 00000000..0e8f8459
--- /dev/null
+++ b/src/util/dtos/index.ts
@@ -0,0 +1,2 @@
+export * from "./DmChannelDTO";
+export * from "./UserDTO";
diff --git a/src/util/entities/Application.ts b/src/util/entities/Application.ts
new file mode 100644
index 00000000..35fc496d
--- /dev/null
+++ b/src/util/entities/Application.ts
@@ -0,0 +1,154 @@
+import { Column, Entity, JoinColumn, ManyToOne, OneToOne } from "typeorm";
+import { BaseClass } from "./BaseClass";
+import { Team } from "./Team";
+import { User } from "./User";
+
+@Entity("applications")
+export class Application extends BaseClass {
+	@Column()
+	name: string;
+
+	@Column({ nullable: true })
+	icon?: string;
+
+	@Column({ nullable: true })
+	description: string;
+
+	@Column({ nullable: true })
+	summary: string = "";
+
+	@Column({ type: "simple-json", nullable: true })
+	type?: any;
+
+	@Column()
+	hook: boolean = true;
+
+	@Column()
+	bot_public?: boolean = true;
+
+	@Column()
+	bot_require_code_grant?: boolean = false;
+
+	@Column()
+	verify_key: string;
+
+	@JoinColumn({ name: "owner_id" })
+	@ManyToOne(() => User)
+	owner: User;
+
+	@Column()
+	flags: number = 0;
+
+	@Column({ type: "simple-array", nullable: true })
+	redirect_uris: string[] = [];
+
+	@Column({ nullable: true })
+	rpc_application_state: number = 0;
+
+	@Column({ nullable: true })
+	store_application_state: number = 1;
+
+	@Column({ nullable: true })
+	verification_state: number = 1;
+
+	@Column({ nullable: true })
+	interactions_endpoint_url?: string;
+
+	@Column({ nullable: true })
+	integration_public: boolean = true;
+
+	@Column({ nullable: true })
+	integration_require_code_grant: boolean = false;
+
+	@Column({ nullable: true })
+	discoverability_state: number = 1;
+
+	@Column({ nullable: true })
+	discovery_eligibility_flags: number = 2240;
+
+	@JoinColumn({ name: "bot_user_id" })
+	@OneToOne(() => User)
+	bot?: User;
+
+	@Column({ type: "simple-array", nullable: true })
+	tags?: string[];
+
+	@Column({ nullable: true })
+	cover_image?: string; // the application's default rich presence invite cover image hash
+
+	@Column({ type: "simple-json", nullable: true })
+	install_params?: { scopes: string[]; permissions: string };
+
+	@Column({ nullable: true })
+	terms_of_service_url?: string;
+
+	@Column({ nullable: true })
+	privacy_policy_url?: string;
+
+	//just for us
+
+	//@Column({ type: "simple-array", nullable: true })
+	//rpc_origins?: string[];
+
+	//@JoinColumn({ name: "guild_id" })
+	//@ManyToOne(() => Guild)
+	//guild?: Guild; // if this application is a game sold, this field will be the guild to which it has been linked
+
+	//@Column({ nullable: true })
+	//primary_sku_id?: string; // if this application is a game sold, this field will be the id of the "Game SKU" that is created,
+
+	//@Column({ nullable: true })
+	//slug?: string; // if this application is a game sold, this field will be the URL slug that links to the store page
+
+	@JoinColumn({ name: "team_id" })
+	@ManyToOne(() => Team, {
+		onDelete: "CASCADE",
+		nullable: true
+	})
+	team?: Team;
+}
+
+export interface ApplicationCommand {
+	id: string;
+	application_id: string;
+	name: string;
+	description: string;
+	options?: ApplicationCommandOption[];
+}
+
+export interface ApplicationCommandOption {
+	type: ApplicationCommandOptionType;
+	name: string;
+	description: string;
+	required?: boolean;
+	choices?: ApplicationCommandOptionChoice[];
+	options?: ApplicationCommandOption[];
+}
+
+export interface ApplicationCommandOptionChoice {
+	name: string;
+	value: string | number;
+}
+
+export enum ApplicationCommandOptionType {
+	SUB_COMMAND = 1,
+	SUB_COMMAND_GROUP = 2,
+	STRING = 3,
+	INTEGER = 4,
+	BOOLEAN = 5,
+	USER = 6,
+	CHANNEL = 7,
+	ROLE = 8
+}
+
+export interface ApplicationCommandInteractionData {
+	id: string;
+	name: string;
+	options?: ApplicationCommandInteractionDataOption[];
+}
+
+export interface ApplicationCommandInteractionDataOption {
+	name: string;
+	value?: any;
+	options?: ApplicationCommandInteractionDataOption[];
+}
diff --git a/src/util/entities/Attachment.ts b/src/util/entities/Attachment.ts
new file mode 100644
index 00000000..8392f415
--- /dev/null
+++ b/src/util/entities/Attachment.ts
@@ -0,0 +1,43 @@
+import { BeforeRemove, Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
+import { URL } from "url";
+import { deleteFile } from "../util/cdn";
+import { BaseClass } from "./BaseClass";
+
+@Entity("attachments")
+export class Attachment extends BaseClass {
+	@Column()
+	filename: string; // name of file attached
+
+	@Column()
+	size: number; // size of file in bytes
+
+	@Column()
+	url: string; // source url of file
+
+	@Column()
+	proxy_url: string; // a proxied url of file
+
+	@Column({ nullable: true })
+	height?: number; // height of file (if image)
+
+	@Column({ nullable: true })
+	width?: number; // width of file (if image)
+
+	@Column({ nullable: true })
+	content_type?: string;
+
+	@Column({ nullable: true })
+	@RelationId((attachment: Attachment) => attachment.message)
+	message_id: string;
+
+	@JoinColumn({ name: "message_id" })
+	@ManyToOne(() => require("./Message").Message, (message: import("./Message").Message) => message.attachments, {
+		onDelete: "CASCADE"
+	})
+	message: import("./Message").Message;
+
+	@BeforeRemove()
+	onDelete() {
+		return deleteFile(new URL(this.url).pathname);
+	}
+}
diff --git a/src/util/entities/AuditLog.ts b/src/util/entities/AuditLog.ts
new file mode 100644
index 00000000..6f394f42
--- /dev/null
+++ b/src/util/entities/AuditLog.ts
@@ -0,0 +1,194 @@
+import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
+import { BaseClass } from "./BaseClass";
+import { ChannelPermissionOverwrite } from "./Channel";
+import { User } from "./User";
+
+export enum AuditLogEvents {
+	// guild level
+	GUILD_UPDATE = 1,
+	GUILD_IMPORT = 2,
+	GUILD_EXPORTED = 3,
+	GUILD_ARCHIVE = 4,
+	GUILD_UNARCHIVE = 5,
+	// join-leave
+	USER_JOIN = 6,
+	USER_LEAVE = 7,
+	// channels
+	CHANNEL_CREATE = 10,
+	CHANNEL_UPDATE = 11,
+	CHANNEL_DELETE = 12,
+	// permission overrides
+	CHANNEL_OVERWRITE_CREATE = 13,
+	CHANNEL_OVERWRITE_UPDATE = 14,
+	CHANNEL_OVERWRITE_DELETE = 15,
+	// kick and ban
+	MEMBER_KICK = 20,
+	MEMBER_PRUNE = 21,
+	MEMBER_BAN_ADD = 22,
+	MEMBER_BAN_REMOVE = 23,
+	// member updates
+	MEMBER_UPDATE = 24,
+	MEMBER_ROLE_UPDATE = 25,
+	MEMBER_MOVE = 26,
+	MEMBER_DISCONNECT = 27,
+	BOT_ADD = 28,
+	// roles
+	ROLE_CREATE = 30,
+	ROLE_UPDATE = 31,
+	ROLE_DELETE = 32,
+	ROLE_SWAP = 33,
+	// invites
+	INVITE_CREATE = 40,
+	INVITE_UPDATE = 41,
+	INVITE_DELETE = 42,
+	// webhooks
+	WEBHOOK_CREATE = 50,
+	WEBHOOK_UPDATE = 51,
+	WEBHOOK_DELETE = 52,
+	WEBHOOK_SWAP = 53,
+	// custom emojis
+	EMOJI_CREATE = 60,
+	EMOJI_UPDATE = 61,
+	EMOJI_DELETE = 62,
+	EMOJI_SWAP = 63,
+	// deletion
+	MESSAGE_CREATE = 70, // messages sent using non-primary seat of the user only
+	MESSAGE_EDIT = 71, // non-self edits only
+	MESSAGE_DELETE = 72,
+	MESSAGE_BULK_DELETE = 73,
+	// pinning
+	MESSAGE_PIN = 74,
+	MESSAGE_UNPIN = 75,
+	// integrations
+	INTEGRATION_CREATE = 80,
+	INTEGRATION_UPDATE = 81,
+	INTEGRATION_DELETE = 82,
+	// stage actions
+	STAGE_INSTANCE_CREATE = 83,
+	STAGE_INSTANCE_UPDATE = 84,
+	STAGE_INSTANCE_DELETE = 85,
+	// stickers
+	STICKER_CREATE = 90,
+	STICKER_UPDATE = 91,
+	STICKER_DELETE = 92,
+	STICKER_SWAP = 93,
+	// threads
+	THREAD_CREATE = 110,
+	THREAD_UPDATE = 111,
+	THREAD_DELETE = 112,
+	// application commands
+	APPLICATION_COMMAND_PERMISSION_UPDATE = 121,
+	// automod
+	POLICY_CREATE = 140,
+	POLICY_UPDATE = 141,
+	POLICY_DELETE = 142,
+	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_UPDATE = 226
+}
+
+@Entity("audit_logs")
+export class AuditLog extends BaseClass {
+	@JoinColumn({ name: "target_id" })
+	@ManyToOne(() => User)
+	target?: User;
+
+	@Column({ nullable: true })
+	@RelationId((auditlog: AuditLog) => auditlog.user)
+	user_id: string;
+
+	@JoinColumn({ name: "user_id" })
+	@ManyToOne(() => User, (user: User) => user.id)
+	user: User;
+
+	@Column({ type: "int" })
+	action_type: AuditLogEvents;
+
+	@Column({ type: "simple-json", nullable: true })
+	options?: {
+		delete_member_days?: string;
+		members_removed?: string;
+		channel_id?: string;
+		messaged_id?: string;
+		count?: string;
+		id?: string;
+		type?: string;
+		role_name?: string;
+	};
+
+	@Column()
+	@Column({ type: "simple-json" })
+	changes: AuditLogChange[];
+
+	@Column({ nullable: true })
+	reason?: string;
+}
+
+export interface AuditLogChange {
+	new_value?: AuditLogChangeValue;
+	old_value?: AuditLogChangeValue;
+	key: string;
+}
+
+export interface AuditLogChangeValue {
+	name?: string;
+	description?: string;
+	icon_hash?: string;
+	splash_hash?: string;
+	discovery_splash_hash?: string;
+	banner_hash?: string;
+	owner_id?: string;
+	region?: string;
+	preferred_locale?: string;
+	afk_channel_id?: string;
+	afk_timeout?: number;
+	rules_channel_id?: string;
+	public_updates_channel_id?: string;
+	mfa_level?: number;
+	verification_level?: number;
+	explicit_content_filter?: number;
+	default_message_notifications?: number;
+	vanity_url_code?: string;
+	$add?: {}[];
+	$remove?: {}[];
+	prune_delete_days?: number;
+	widget_enabled?: boolean;
+	widget_channel_id?: string;
+	system_channel_id?: string;
+	position?: number;
+	topic?: string;
+	bitrate?: number;
+	permission_overwrites?: ChannelPermissionOverwrite[];
+	nsfw?: boolean;
+	application_id?: string;
+	rate_limit_per_user?: number;
+	permissions?: string;
+	color?: number;
+	hoist?: boolean;
+	mentionable?: boolean;
+	allow?: string;
+	deny?: string;
+	code?: string;
+	channel_id?: string;
+	inviter_id?: string;
+	max_uses?: number;
+	uses?: number;
+	max_age?: number;
+	temporary?: boolean;
+	deaf?: boolean;
+	mute?: boolean;
+	nick?: string;
+	avatar_hash?: string;
+	id?: string;
+	type?: number;
+	enable_emoticons?: boolean;
+	expire_behavior?: number;
+	expire_grace_period?: number;
+	user_limit?: number;
+}
diff --git a/src/util/entities/BackupCodes.ts b/src/util/entities/BackupCodes.ts
new file mode 100644
index 00000000..503b1dbd
--- /dev/null
+++ b/src/util/entities/BackupCodes.ts
@@ -0,0 +1,19 @@
+import { Column, Entity, JoinColumn, ManyToOne } from "typeorm";
+import { BaseClass } from "./BaseClass";
+import { User } from "./User";
+
+@Entity("backup_codes")
+export class BackupCode extends BaseClass {
+	@JoinColumn({ name: "user_id" })
+	@ManyToOne(() => User, { onDelete: "CASCADE" })
+	user: User;
+
+	@Column()
+	code: string;
+
+	@Column()
+	consumed: boolean;
+
+	@Column()
+	expired: boolean;
+}
diff --git a/src/util/entities/Ban.ts b/src/util/entities/Ban.ts
new file mode 100644
index 00000000..27c75278
--- /dev/null
+++ b/src/util/entities/Ban.ts
@@ -0,0 +1,41 @@
+import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
+import { BaseClass } from "./BaseClass";
+import { Guild } from "./Guild";
+import { User } from "./User";
+
+@Entity("bans")
+export class Ban extends BaseClass {
+	@Column({ nullable: true })
+	@RelationId((ban: Ban) => ban.user)
+	user_id: string;
+
+	@JoinColumn({ name: "user_id" })
+	@ManyToOne(() => User, {
+		onDelete: "CASCADE"
+	})
+	user: User;
+
+	@Column({ nullable: true })
+	@RelationId((ban: Ban) => ban.guild)
+	guild_id: string;
+
+	@JoinColumn({ name: "guild_id" })
+	@ManyToOne(() => Guild, {
+		onDelete: "CASCADE"
+	})
+	guild: Guild;
+
+	@Column({ nullable: true })
+	@RelationId((ban: Ban) => ban.executor)
+	executor_id: string;
+
+	@JoinColumn({ name: "executor_id" })
+	@ManyToOne(() => User)
+	executor: User;
+
+	@Column()
+	ip: string;
+
+	@Column({ nullable: true })
+	reason?: string;
+}
diff --git a/src/util/entities/BaseClass.ts b/src/util/entities/BaseClass.ts
new file mode 100644
index 00000000..aecc2465
--- /dev/null
+++ b/src/util/entities/BaseClass.ts
@@ -0,0 +1,26 @@
+import "reflect-metadata";
+import { BaseEntity, ObjectIdColumn, PrimaryColumn, SaveOptions } from "typeorm";
+import { Snowflake } from "../util/Snowflake";
+
+export class BaseClassWithoutId extends BaseEntity {
+	constructor() {
+		super();
+	}
+}
+
+export const PrimaryIdColumn = process.env.DATABASE?.startsWith("mongodb") ? ObjectIdColumn : PrimaryColumn;
+
+export class BaseClass extends BaseClassWithoutId {
+	@PrimaryIdColumn()
+	id: string;
+
+	constructor() {
+		super();
+		if (!this.id) this.id = Snowflake.generate();
+	}
+
+	save(options?: SaveOptions | undefined): Promise<this> {
+		if (!this.id) this.id = Snowflake.generate();
+		return super.save(options);
+	}
+}
diff --git a/src/util/entities/Categories.ts b/src/util/entities/Categories.ts
new file mode 100644
index 00000000..08a79112
--- /dev/null
+++ b/src/util/entities/Categories.ts
@@ -0,0 +1,33 @@
+import { Column, Entity, PrimaryColumn } from "typeorm";
+import { BaseClassWithoutId } from "./BaseClass";
+
+// TODO: categories:
+// [{
+// 	"id": 16,
+// 	"default": "Anime & Manga",
+// 	"localizations": {
+// 			"de": "Anime & Manga",
+// 			"fr": "Anim\u00e9s et mangas",
+// 			"ru": "\u0410\u043d\u0438\u043c\u0435 \u0438 \u043c\u0430\u043d\u0433\u0430"
+// 		}
+// 	},
+// 	"is_primary": false/true
+// }]
+// Also populate discord default categories
+
+@Entity("categories")
+export class Categories extends BaseClassWithoutId {
+	// Not using snowflake
+
+	@PrimaryColumn()
+	id: number;
+
+	@Column({ nullable: true })
+	name: string;
+
+	@Column({ type: "simple-json" })
+	localizations: string;
+
+	@Column({ nullable: true })
+	is_primary: boolean;
+}
diff --git a/src/util/entities/Channel.ts b/src/util/entities/Channel.ts
new file mode 100644
index 00000000..b17fdba0
--- /dev/null
+++ b/src/util/entities/Channel.ts
@@ -0,0 +1,389 @@
+import { Column, Entity, JoinColumn, ManyToOne, OneToMany, RelationId } from "typeorm";
+import { DmChannelDTO } from "../dtos";
+import { ChannelCreateEvent, ChannelRecipientRemoveEvent } from "../interfaces";
+import { containsAll, emitEvent, getPermission, InvisibleCharacters, Snowflake, trimSpecial } from "../util";
+import { HTTPError } from "../util/imports/HTTPError";
+import { OrmUtils } from "../util/imports/OrmUtils";
+import { BaseClass } from "./BaseClass";
+import { Guild } from "./Guild";
+import { Invite } from "./Invite";
+import { Message } from "./Message";
+import { ReadState } from "./ReadState";
+import { Recipient } from "./Recipient";
+import { PublicUserProjection, User } from "./User";
+import { VoiceState } from "./VoiceState";
+import { Webhook } from "./Webhook";
+
+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({ nullable: true })
+	nsfw?: boolean;
+
+	@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[];
+
+	@Column({ nullable: true })
+	flags?: number = 0;
+
+	@Column({ nullable: true })
+	default_thread_rate_limit_per_user?: number = 0;
+
+	// 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 (let character of InvisibleCharacters)
+					if (channel.name.includes(character)) throw new HTTPError("Channel name cannot include invalid characters", 403);
+
+				// Categories and voice skip these checks on discord.com
+				const skipChecksTypes = [ChannelType.GUILD_CATEGORY, ChannelType.GUILD_VOICE];
+				if ((channel.type && !skipChecksTypes.includes(channel.type)) || guild.features.includes("IRC_LIKE_CHANNEL_NAMES")) {
+					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([
+			OrmUtils.mergeDeep(new Channel(), 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);
+		const otherRecipientsUsers = await User.find({ where: recipients.map((x) => ({ id: x })) });
+
+		// TODO: check config for max number of recipients
+		/** if you want to disallow note to self channels, uncomment the conditional below
+		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;
+						ur = OrmUtils.mergeDeep(ur, { closed: false });
+						await ur.save();
+					}
+				}
+			}
+		}
+
+		if (channel == null) {
+			name = trimSpecial(name);
+
+			channel = await (
+				OrmUtils.mergeDeep(new Channel(), {
+					name,
+					type,
+					owner_id: type === ChannelType.DM ? undefined : null, // 1:1 DMs are ownerless in fosscord-server
+					created_at: new Date(),
+					last_message_id: null,
+					recipients: channelRecipients.map((x) =>
+						OrmUtils.mergeDeep(new Recipient(), {
+							user_id: x,
+							closed: !(type === ChannelType.GROUP_DM || x === creator_user_id)
+						})
+					)
+				}) as Channel
+			).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
new file mode 100644
index 00000000..2723ab67
--- /dev/null
+++ b/src/util/entities/ClientRelease.ts
@@ -0,0 +1,26 @@
+import { Column, Entity } from "typeorm";
+import { BaseClass } from "./BaseClass";
+
+@Entity("client_release")
+export class Release extends BaseClass {
+	@Column()
+	name: string;
+
+	@Column()
+	pub_date: string;
+
+	@Column()
+	url: string;
+
+	@Column()
+	deb_url: string;
+
+	@Column()
+	osx_url: string;
+
+	@Column()
+	win_url: string;
+
+	@Column({ nullable: true })
+	notes?: string;
+}
diff --git a/src/util/entities/Config.ts b/src/util/entities/Config.ts
new file mode 100644
index 00000000..fc33bb65
--- /dev/null
+++ b/src/util/entities/Config.ts
@@ -0,0 +1,11 @@
+import { Column, Entity } from "typeorm";
+import { BaseClassWithoutId, PrimaryIdColumn } from "./BaseClass";
+
+@Entity("config")
+export class ConfigEntity extends BaseClassWithoutId {
+	@PrimaryIdColumn()
+	key: string;
+
+	@Column({ type: "simple-json", nullable: true })
+	value: number | boolean | null | string | undefined;
+}
diff --git a/src/util/entities/ConnectedAccount.ts b/src/util/entities/ConnectedAccount.ts
new file mode 100644
index 00000000..018b3995
--- /dev/null
+++ b/src/util/entities/ConnectedAccount.ts
@@ -0,0 +1,42 @@
+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"> {}
+
+@Entity("connected_accounts")
+export class ConnectedAccount extends BaseClass {
+	@Column({ nullable: true })
+	@RelationId((account: ConnectedAccount) => account.user)
+	user_id: string;
+
+	@JoinColumn({ name: "user_id" })
+	@ManyToOne(() => User, {
+		onDelete: "CASCADE"
+	})
+	user: User;
+
+	@Column({ select: false })
+	access_token: string;
+
+	@Column({ select: false })
+	friend_sync: boolean;
+
+	@Column()
+	name: string;
+
+	@Column({ select: false })
+	revoked: boolean;
+
+	@Column({ select: false })
+	show_activity: boolean;
+
+	@Column()
+	type: string;
+
+	@Column()
+	verified: boolean;
+
+	@Column({ select: false })
+	visibility: number;
+}
diff --git a/src/util/entities/Emoji.ts b/src/util/entities/Emoji.ts
new file mode 100644
index 00000000..a2552995
--- /dev/null
+++ b/src/util/entities/Emoji.ts
@@ -0,0 +1,45 @@
+import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
+import { User } from ".";
+import { BaseClass } from "./BaseClass";
+import { Guild } from "./Guild";
+
+@Entity("emojis")
+export class Emoji extends BaseClass {
+	@Column()
+	animated: boolean;
+
+	@Column()
+	available: boolean; // whether this emoji can be used, may be false due to various reasons
+
+	@Column()
+	guild_id: string;
+
+	@JoinColumn({ name: "guild_id" })
+	@ManyToOne(() => Guild, {
+		onDelete: "CASCADE"
+	})
+	guild: Guild;
+
+	@Column({ nullable: true })
+	@RelationId((emoji: Emoji) => emoji.user)
+	user_id: string;
+
+	@JoinColumn({ name: "user_id" })
+	@ManyToOne(() => User)
+	user: User;
+
+	@Column()
+	managed: boolean;
+
+	@Column()
+	name: string;
+
+	@Column()
+	require_colons: boolean;
+
+	@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
new file mode 100644
index 00000000..43f02962
--- /dev/null
+++ b/src/util/entities/Encryption.ts
@@ -0,0 +1,25 @@
+import { Column, Entity } from "typeorm";
+import { Snowflake } from "../util";
+import { BitField } from "../util/BitField";
+import { BaseClass } from "./BaseClass";
+
+@Entity("security_settings")
+export class SecuritySettings extends BaseClass {
+	@Column({ nullable: true })
+	guild_id: Snowflake;
+
+	@Column({ nullable: true })
+	channel_id: Snowflake;
+
+	@Column()
+	encryption_permission_mask: BitField;
+
+	@Column()
+	allowed_algorithms: string[];
+
+	@Column()
+	current_algorithm: string;
+
+	@Column({ nullable: true })
+	used_since_message: Snowflake;
+}
diff --git a/src/util/entities/Group.ts b/src/util/entities/Group.ts
new file mode 100644
index 00000000..23aaabf2
--- /dev/null
+++ b/src/util/entities/Group.ts
@@ -0,0 +1,33 @@
+import { Column, Entity } from "typeorm";
+
+import { BaseClass } from "./BaseClass";
+
+@Entity("groups")
+export class UserGroup extends BaseClass {
+	@Column({ nullable: true })
+	parent?: BigInt;
+
+	@Column()
+	color: number;
+
+	@Column()
+	hoist: boolean;
+
+	@Column()
+	mentionable: boolean;
+
+	@Column()
+	name: string;
+
+	@Column()
+	rights: BigInt;
+
+	@Column()
+	position: number;
+
+	@Column({ nullable: true })
+	icon: BigInt;
+
+	@Column({ nullable: true })
+	unicode_emoji: BigInt;
+}
diff --git a/src/util/entities/Guild.ts b/src/util/entities/Guild.ts
new file mode 100644
index 00000000..015c6d04
--- /dev/null
+++ b/src/util/entities/Guild.ts
@@ -0,0 +1,357 @@
+import { Column, Entity, JoinColumn, ManyToOne, OneToMany, RelationId } from "typeorm";
+import { Config, handleFile, Snowflake } from "..";
+import { OrmUtils } from "../util/imports/OrmUtils";
+import { Ban } from "./Ban";
+import { BaseClass } from "./BaseClass";
+import { Channel } from "./Channel";
+import { Emoji } from "./Emoji";
+import { Invite } from "./Invite";
+import { Member } from "./Member";
+import { Role } from "./Role";
+import { Sticker } from "./Sticker";
+import { Template } from "./Template";
+import { User } from "./User";
+import { VoiceState } from "./VoiceState";
+import { Webhook } from "./Webhook";
+
+// TODO: application_command_count, application_command_counts: {1: 0, 2: 0, 3: 0}
+// TODO: guild_scheduled_events
+// TODO: stage_instances
+// TODO: threads
+// TODO:
+// "keywords": [
+// 		"Genshin Impact",
+// 		"Paimon",
+// 		"Honkai Impact",
+// 		"ARPG",
+// 		"Open-World",
+// 		"Waifu",
+// 		"Anime",
+// 		"Genshin",
+// 		"miHoYo",
+// 		"Gacha"
+// 	],
+
+export const PublicGuildRelations = ["channels", "emojis", "members", "roles", "stickers", "voice_states", "members.user"];
+
+@Entity("guilds")
+export class Guild extends BaseClass {
+	@Column({ nullable: true })
+	@RelationId((guild: Guild) => guild.afk_channel)
+	afk_channel_id?: string;
+
+	@JoinColumn({ name: "afk_channel_id" })
+	@ManyToOne(() => Channel)
+	afk_channel?: Channel;
+
+	@Column({ nullable: true })
+	afk_timeout?: number = Config.get().defaults.guild.afkTimeout;
+
+	// * commented out -> use owner instead
+	// application id of the guild creator if it is bot-created
+	// @Column({ nullable: true })
+	// application?: string;
+
+	@JoinColumn({ name: "ban_ids" })
+	@OneToMany(() => Ban, (ban: Ban) => ban.guild, {
+		cascade: true,
+		orphanedRowAction: "delete"
+	})
+	bans: Ban[];
+
+	@Column({ nullable: true })
+	banner?: string;
+
+	@Column({ nullable: true })
+	default_message_notifications?: number = Config.get().defaults.guild.defaultMessageNotifications;
+
+	@Column({ nullable: true })
+	description?: string;
+
+	@Column({ nullable: true })
+	discovery_splash?: string;
+
+	@Column({ nullable: true })
+	explicit_content_filter?: number = Config.get().defaults.guild.explicitContentFilter;
+
+	@Column({ type: "simple-array" })
+	features: string[]; //TODO use enum
+	//TODO: https://discord.com/developers/docs/resources/guild#guild-object-guild-features
+
+	@Column({ nullable: true })
+	primary_category_id: number;
+
+	@Column({ nullable: true })
+	icon?: string;
+
+	@Column({ nullable: true })
+	large?: boolean;
+
+	@Column({ nullable: true })
+	max_members?: number = Config.get().limits.guild.maxMembers; // e.g. default 100.000
+
+	@Column({ nullable: true })
+	max_presences?: number = Config.get().defaults.guild.maxPresences;
+
+	@Column({ nullable: true })
+	max_video_channel_users?: number = Config.get().defaults.guild.maxVideoChannelUsers; // ? default: 25, is this max 25 streaming or watching
+
+	@Column({ nullable: true })
+	member_count?: number = 0;
+
+	@Column({ nullable: true })
+	presence_count?: number = 0; // users online
+
+	@OneToMany(() => Member, (member: Member) => member.guild, {
+		cascade: true,
+		orphanedRowAction: "delete",
+		onDelete: "CASCADE"
+	})
+	members: Member[];
+
+	@JoinColumn({ name: "role_ids" })
+	@OneToMany(() => Role, (role: Role) => role.guild, {
+		cascade: true,
+		orphanedRowAction: "delete",
+		onDelete: "CASCADE"
+	})
+	roles: Role[];
+
+	@JoinColumn({ name: "channel_ids" })
+	@OneToMany(() => Channel, (channel: Channel) => channel.guild, {
+		cascade: true,
+		orphanedRowAction: "delete"
+	})
+	channels: Channel[];
+
+	@Column({ nullable: true })
+	@RelationId((guild: Guild) => guild.template)
+	template_id?: string;
+
+	@JoinColumn({ name: "template_id", referencedColumnName: "id" })
+	@ManyToOne(() => Template)
+	template: Template;
+
+	@JoinColumn({ name: "emoji_ids" })
+	@OneToMany(() => Emoji, (emoji: Emoji) => emoji.guild, {
+		cascade: true,
+		orphanedRowAction: "delete",
+		onDelete: "CASCADE"
+	})
+	emojis: Emoji[];
+
+	@JoinColumn({ name: "sticker_ids" })
+	@OneToMany(() => Sticker, (sticker: Sticker) => sticker.guild, {
+		cascade: true,
+		orphanedRowAction: "delete",
+		onDelete: "CASCADE"
+	})
+	stickers: Sticker[];
+
+	@JoinColumn({ name: "invite_ids" })
+	@OneToMany(() => Invite, (invite: Invite) => invite.guild, {
+		cascade: true,
+		orphanedRowAction: "delete",
+		onDelete: "CASCADE"
+	})
+	invites: Invite[];
+
+	@JoinColumn({ name: "voice_state_ids" })
+	@OneToMany(() => VoiceState, (voicestate: VoiceState) => voicestate.guild, {
+		cascade: true,
+		orphanedRowAction: "delete",
+		onDelete: "CASCADE"
+	})
+	voice_states: VoiceState[];
+
+	@JoinColumn({ name: "webhook_ids" })
+	@OneToMany(() => Webhook, (webhook: Webhook) => webhook.guild, {
+		cascade: true,
+		orphanedRowAction: "delete",
+		onDelete: "CASCADE"
+	})
+	webhooks: Webhook[];
+
+	@Column({ nullable: true })
+	mfa_level?: number;
+
+	@Column()
+	name: string;
+
+	@Column({ nullable: true })
+	@RelationId((guild: Guild) => guild.owner)
+	owner_id?: string; // optional to allow for ownerless guilds
+
+	@JoinColumn({ name: "owner_id", referencedColumnName: "id" })
+	@ManyToOne(() => User)
+	owner?: User; // optional to allow for ownerless guilds
+
+	@Column({ nullable: true })
+	preferred_locale?: string;
+
+	@Column({ nullable: true })
+	premium_subscription_count?: number;
+
+	@Column({ nullable: true })
+	premium_tier?: number; // crowd premium level
+
+	@Column({ nullable: true })
+	@RelationId((guild: Guild) => guild.public_updates_channel)
+	public_updates_channel_id: string;
+
+	@JoinColumn({ name: "public_updates_channel_id" })
+	@ManyToOne(() => Channel)
+	public_updates_channel?: Channel;
+
+	@Column({ nullable: true })
+	@RelationId((guild: Guild) => guild.rules_channel)
+	rules_channel_id?: string;
+
+	@JoinColumn({ name: "rules_channel_id" })
+	@ManyToOne(() => Channel)
+	rules_channel?: string;
+
+	@Column({ nullable: true })
+	region?: string;
+
+	@Column({ nullable: true })
+	splash?: string;
+
+	@Column({ nullable: true })
+	@RelationId((guild: Guild) => guild.system_channel)
+	system_channel_id?: string;
+
+	@JoinColumn({ name: "system_channel_id" })
+	@ManyToOne(() => Channel)
+	system_channel?: Channel;
+
+	@Column({ nullable: true })
+	system_channel_flags?: number;
+
+	@Column({ nullable: true })
+	unavailable?: boolean;
+
+	@Column({ nullable: true })
+	verification_level?: number;
+
+	@Column({ type: "simple-json" })
+	welcome_screen: {
+		enabled: boolean;
+		description: string;
+		welcome_channels: {
+			description: string;
+			emoji_id?: string;
+			emoji_name: string;
+			channel_id: string;
+		}[];
+	};
+
+	@Column({ nullable: true })
+	@RelationId((guild: Guild) => guild.widget_channel)
+	widget_channel_id?: string;
+
+	@JoinColumn({ name: "widget_channel_id" })
+	@ManyToOne(() => Channel)
+	widget_channel?: Channel;
+
+	@Column({ nullable: true })
+	widget_enabled?: boolean;
+
+	@Column({ nullable: true })
+	nsfw_level?: number;
+
+	@Column({ nullable: true })
+	nsfw?: boolean;
+
+	// TODO: nested guilds
+	@Column({ nullable: true })
+	parent?: string;
+
+	// only for developer portal
+	permissions?: number;
+
+	//new guild settings, 11/08/2022:
+	@Column({ nullable: true })
+	premium_progress_bar_enabled: boolean = false;
+
+	static async createGuild(body: { name?: string; icon?: string | null; owner_id?: string; channels?: Partial<Channel>[] }) {
+		const guild_id = Snowflake.generate();
+
+		const guild: Guild = OrmUtils.mergeDeep(new Guild(), {
+			name: body.name || "Fosscord",
+			icon: await handleFile(`/icons/${guild_id}`, body.icon as string),
+			region: Config.get().regions.default,
+			owner_id: body.owner_id, // TODO: need to figure out a way for ownerless guilds and multiply-owned guilds
+			afk_timeout: 300,
+			default_message_notifications: 1, // defaults effect: setting the push default at mentions-only will save a lot
+			explicit_content_filter: 0,
+			features: [],
+			primary_category_id: null,
+			id: guild_id,
+			max_members: 250000,
+			max_presences: 250000,
+			max_video_channel_users: 200,
+			presence_count: 0,
+			member_count: 0, // will automatically be increased by addMember()
+			mfa_level: 0,
+			preferred_locale: "en-US",
+			premium_subscription_count: 0,
+			premium_tier: 0,
+			system_channel_flags: 4, // defaults effect: suppress the setup tips to save performance
+			unavailable: false,
+			nsfw: false,
+			nsfw_level: 0,
+			verification_level: 0,
+			welcome_screen: {
+				enabled: false,
+				description: "Fill in your description",
+				welcome_channels: []
+			},
+			widget_enabled: true // NB: don't set it as false to prevent artificial restrictions
+		});
+		await guild.save();
+
+		// we have to create the role _after_ the guild because else we would get a "SQLITE_CONSTRAINT: FOREIGN KEY constraint failed" error
+		// TODO: make the @everyone a pseudorole that is dynamically generated at runtime so we can save storage
+		let role: Role = OrmUtils.mergeDeep(new Role(), {
+			id: guild_id,
+			guild_id: guild_id,
+			color: 0,
+			hoist: false,
+			managed: false,
+			// NB: in Fosscord, every role will be non-managed, as we use user-groups instead of roles for managed groups
+			mentionable: false,
+			name: "@everyone",
+			permissions: String("2251804225"),
+			position: 0,
+			icon: null,
+			unicode_emoji: null
+		});
+		await role.save();
+
+		if (!body.channels || !body.channels.length) body.channels = [{ id: "01", type: 0, name: "general" }];
+
+		const ids = new Map();
+
+		body.channels.forEach((x) => {
+			if (x.id) {
+				ids.set(x.id, Snowflake.generate());
+			}
+		});
+
+		for (const channel of body.channels?.sort((a, b) => (a.parent_id ? 1 : -1))) {
+			let id = ids.get(channel.id) || Snowflake.generate();
+
+			let 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
+			});
+		}
+
+		return guild;
+	}
+}
diff --git a/src/util/entities/Invite.ts b/src/util/entities/Invite.ts
new file mode 100644
index 00000000..f6ba85d7
--- /dev/null
+++ b/src/util/entities/Invite.ts
@@ -0,0 +1,88 @@
+import { random } from "@fosscord/api";
+import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn, RelationId } from "typeorm";
+import { BaseClassWithoutId } from "./BaseClass";
+import { Channel } from "./Channel";
+import { Guild } from "./Guild";
+import { Member } from "./Member";
+import { User } from "./User";
+
+export const PublicInviteRelation = ["inviter", "guild", "channel"];
+
+@Entity("invites")
+export class Invite extends BaseClassWithoutId {
+	@PrimaryColumn()
+	code: string = random();
+
+	@Column()
+	temporary: boolean = true;
+
+	@Column()
+	uses: number = 0;
+
+	@Column()
+	max_uses: number;
+
+	@Column()
+	max_age: number;
+
+	@Column()
+	created_at: Date = new Date();
+
+	@Column()
+	expires_at: Date;
+
+	@Column({ nullable: true })
+	@RelationId((invite: Invite) => invite.guild)
+	guild_id: string;
+
+	@JoinColumn({ name: "guild_id" })
+	@ManyToOne(() => Guild, {
+		onDelete: "CASCADE"
+	})
+	guild: Guild;
+
+	@Column({ nullable: true })
+	@RelationId((invite: Invite) => invite.channel)
+	channel_id: string;
+
+	@JoinColumn({ name: "channel_id" })
+	@ManyToOne(() => Channel, {
+		onDelete: "CASCADE"
+	})
+	channel: Channel;
+
+	@Column({ nullable: true })
+	@RelationId((invite: Invite) => invite.inviter)
+	inviter_id: string;
+
+	@JoinColumn({ name: "inviter_id" })
+	@ManyToOne(() => User, {
+		onDelete: "CASCADE"
+	})
+	inviter: User;
+
+	@Column({ nullable: true })
+	@RelationId((invite: Invite) => invite.target_user)
+	target_user_id: string;
+
+	@JoinColumn({ name: "target_user_id" })
+	@ManyToOne(() => User, {
+		onDelete: "CASCADE"
+	})
+	target_user?: string; // could be used for "User specific invites" https://github.com/fosscord/fosscord/issues/62
+
+	@Column({ nullable: true })
+	target_user_type?: number;
+
+	@Column({ nullable: true })
+	vanity_url?: boolean;
+
+	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 });
+		else await invite.save();
+
+		await Member.addToGuild(user_id, invite.guild_id);
+		return invite;
+	}
+}
diff --git a/src/util/entities/Member.ts b/src/util/entities/Member.ts
new file mode 100644
index 00000000..42a014d4
--- /dev/null
+++ b/src/util/entities/Member.ts
@@ -0,0 +1,334 @@
+import { Column, Entity, Index, JoinColumn, JoinTable, ManyToMany, ManyToOne, PrimaryGeneratedColumn, RelationId } from "typeorm";
+import { Ban, PublicGuildRelations } from ".";
+import { GuildCreateEvent, GuildDeleteEvent, GuildMemberAddEvent, GuildMemberRemoveEvent, GuildMemberUpdateEvent } from "../interfaces";
+import { Config, emitEvent } from "../util";
+import { DiscordApiErrors } from "../util/Constants";
+import { HTTPError } from "../util/imports/HTTPError";
+import { OrmUtils } from "../util/imports/OrmUtils";
+import { BaseClassWithoutId } from "./BaseClass";
+import { Guild } from "./Guild";
+import { Role } from "./Role";
+import { PublicUser, User } from "./User";
+
+export const MemberPrivateProjection: (keyof Member)[] = [
+	"id",
+	"guild",
+	"guild_id",
+	"deaf",
+	"joined_at",
+	"last_message_id",
+	"mute",
+	"nick",
+	"pending",
+	"premium_since",
+	"roles",
+	"settings",
+	"user"
+];
+
+@Entity("members")
+@Index(["id", "guild_id"], { unique: true })
+export class Member extends BaseClassWithoutId {
+	@PrimaryGeneratedColumn()
+	index: string;
+
+	@Column()
+	@RelationId((member: Member) => member.user)
+	id: string;
+
+	@JoinColumn({ name: "id" })
+	@ManyToOne(() => User, {
+		onDelete: "CASCADE"
+	})
+	user: User;
+
+	@Column()
+	@RelationId((member: Member) => member.guild)
+	guild_id: string;
+
+	@JoinColumn({ name: "guild_id" })
+	@ManyToOne(() => Guild, {
+		onDelete: "CASCADE"
+	})
+	guild: Guild;
+
+	@Column({ nullable: true })
+	nick?: string;
+
+	@JoinTable({
+		name: "member_roles",
+		joinColumn: { name: "index", referencedColumnName: "index" },
+		inverseJoinColumn: {
+			name: "role_id",
+			referencedColumnName: "id"
+		}
+	})
+	@ManyToMany(() => Role, { cascade: true })
+	roles: Role[];
+
+	@Column()
+	joined_at: Date;
+
+	@Column({ nullable: true })
+	premium_since?: Date;
+
+	@Column()
+	deaf: boolean;
+
+	@Column()
+	mute: boolean;
+
+	@Column()
+	pending: boolean;
+
+	@Column({ type: "simple-json", select: false })
+	settings: UserGuildSettings;
+
+	@Column({ nullable: true })
+	last_message_id?: string;
+
+	/**
+	@JoinColumn({ name: "id" })
+	@ManyToOne(() => User, {
+		onDelete: "DO NOTHING",
+	// do not auto-kick force-joined members just because their joiners left the server
+	}) **/
+	@Column({ nullable: true })
+	joined_by?: string;
+
+	// TODO: add this when we have proper read receipts
+	// @Column({ type: "simple-json" })
+	// read_state: ReadState;
+
+	static async IsInGuildOrFail(user_id: string, guild_id: string) {
+		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", "member_count"], 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
+		//TODO: check for bugs
+		if (guild.member_count) guild.member_count--;
+		return Promise.all([
+			Member.delete({
+				id: user_id,
+				guild_id
+			}),
+			//Guild.decrement({ id: guild_id }, "member_count", -1),
+
+			emitEvent({
+				event: "GUILD_DELETE",
+				data: {
+					id: guild_id
+				},
+				user_id: user_id
+			} as GuildDeleteEvent),
+			emitEvent({
+				event: "GUILD_MEMBER_REMOVE",
+				data: { guild_id, user: member.user },
+				guild_id
+			} as GuildMemberRemoveEvent)
+		]);
+	}
+
+	static async addRole(user_id: string, guild_id: string, role_id: string) {
+		const [member, role] = await Promise.all([
+			// @ts-ignore
+			Member.findOneOrFail({
+				where: { id: user_id, guild_id },
+				relations: ["user", "roles"], // we don't want to load  the role objects just the ids
+				select: ["index"]
+			}),
+			Role.findOneOrFail({ where: { id: role_id, guild_id }, select: ["id"] })
+		]);
+		member.roles.push(OrmUtils.mergeDeep(new Role(), { id: role_id }));
+
+		await Promise.all([
+			member.save(),
+			emitEvent({
+				event: "GUILD_MEMBER_UPDATE",
+				data: {
+					guild_id,
+					user: member.user,
+					roles: member.roles.map((x) => x.id)
+				},
+				guild_id
+			} as GuildMemberUpdateEvent)
+		]);
+	}
+
+	static async removeRole(user_id: string, guild_id: string, role_id: string) {
+		const [member] = await Promise.all([
+			// @ts-ignore
+			Member.findOneOrFail({
+				where: { id: user_id, guild_id },
+				relations: ["user", "roles"], // we don't want to load  the role objects just the ids
+				select: ["index"]
+			}),
+			await Role.findOneOrFail({ where: { id: role_id, guild_id } })
+		]);
+		member.roles = member.roles.filter((x) => x.id == role_id);
+
+		await Promise.all([
+			member.save(),
+			emitEvent({
+				event: "GUILD_MEMBER_UPDATE",
+				data: {
+					guild_id,
+					user: member.user,
+					roles: member.roles.map((x) => x.id)
+				},
+				guild_id
+			} as GuildMemberUpdateEvent)
+		]);
+	}
+
+	static async changeNickname(user_id: string, guild_id: string, nickname: string) {
+		const member = await Member.findOneOrFail({
+			where: {
+				id: user_id,
+				guild_id
+			},
+			relations: ["user"]
+		});
+		member.nick = nickname;
+
+		await Promise.all([
+			member.save(),
+
+			emitEvent({
+				event: "GUILD_MEMBER_UPDATE",
+				data: {
+					guild_id,
+					user: member.user,
+					nick: nickname
+				},
+				guild_id
+			} as GuildMemberUpdateEvent)
+		]);
+	}
+
+	static async addToGuild(user_id: string, guild_id: string) {
+		const user = await User.getPublicUser(user_id);
+		const isBanned = await Ban.count({ where: { guild_id, user_id } });
+		if (isBanned) {
+			throw DiscordApiErrors.USER_BANNED;
+		}
+		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);
+		}
+
+		const guild = await Guild.findOneOrFail({
+			where: {
+				id: guild_id
+			},
+			relations: PublicGuildRelations
+		});
+
+		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 = {
+			id: user_id,
+			guild_id,
+			nick: undefined,
+			roles: [guild_id], // @everyone role
+			joined_at: new Date(),
+			premium_since: null,
+			deaf: false,
+			mute: false,
+			pending: false
+		};
+		//TODO: check for bugs
+		if (guild.member_count) guild.member_count++;
+		await Promise.all([
+			OrmUtils.mergeDeep(new Member(), {
+				...member,
+				roles: [OrmUtils.mergeDeep(new Role(), { id: guild_id })],
+				// read_state: {},
+				settings: {
+					channel_overrides: [],
+					message_notifications: 0,
+					mobile_push: true,
+					muted: false,
+					suppress_everyone: false,
+					suppress_roles: false,
+					version: 0
+				}
+				// Member.save is needed because else the roles relations wouldn't be updated
+			}).save(),
+			//Guild.increment({ id: guild_id }, "member_count", 1),
+			emitEvent({
+				event: "GUILD_MEMBER_ADD",
+				data: {
+					...member,
+					user,
+					guild_id
+				},
+				guild_id
+			} as GuildMemberAddEvent),
+			emitEvent({
+				event: "GUILD_CREATE",
+				data: {
+					...guild,
+					members: [...guild.members, { ...member, user }],
+					member_count: (guild.member_count || 0) + 1,
+					guild_hashes: {},
+					guild_scheduled_events: [],
+					joined_at: member.joined_at,
+					presences: [],
+					stage_instances: [],
+					threads: []
+				},
+				user_id
+			} as GuildCreateEvent)
+		]);
+	}
+}
+
+export interface UserGuildSettings {
+	channel_overrides: {
+		channel_id: string;
+		message_notifications: number;
+		mute_config: MuteConfig;
+		muted: boolean;
+	}[];
+	message_notifications: number;
+	mobile_push: boolean;
+	mute_config: MuteConfig;
+	muted: boolean;
+	suppress_everyone: boolean;
+	suppress_roles: boolean;
+	version: number;
+}
+
+export interface MuteConfig {
+	end_time: number;
+	selected_time_window: number;
+}
+
+export type PublicMemberKeys = "id" | "guild_id" | "nick" | "roles" | "joined_at" | "pending" | "deaf" | "mute" | "premium_since";
+
+export const PublicMemberProjection: PublicMemberKeys[] = [
+	"id",
+	"guild_id",
+	"nick",
+	"roles",
+	"joined_at",
+	"pending",
+	"deaf",
+	"mute",
+	"premium_since"
+];
+
+// @ts-ignore
+export type PublicMember = Pick<Member, Omit<PublicMemberKeys, "roles">> & {
+	user: PublicUser;
+	roles: string[]; // only role ids not objects
+};
diff --git a/src/util/entities/Message.ts b/src/util/entities/Message.ts
new file mode 100644
index 00000000..8122b532
--- /dev/null
+++ b/src/util/entities/Message.ts
@@ -0,0 +1,271 @@
+import { Column, CreateDateColumn, Entity, Index, JoinColumn, JoinTable, ManyToMany, ManyToOne, OneToMany, RelationId } from "typeorm";
+import { InteractionType } from "../interfaces/Interaction";
+import { Application } from "./Application";
+import { Attachment } from "./Attachment";
+import { BaseClass } from "./BaseClass";
+import { Channel } from "./Channel";
+import { Guild } from "./Guild";
+import { Member } from "./Member";
+import { Role } from "./Role";
+import { Sticker } from "./Sticker";
+import { User } from "./User";
+import { Webhook } from "./Webhook";
+
+export enum MessageType {
+	DEFAULT = 0,
+	RECIPIENT_ADD = 1,
+	RECIPIENT_REMOVE = 2,
+	CALL = 3,
+	CHANNEL_NAME_CHANGE = 4,
+	CHANNEL_ICON_CHANGE = 5,
+	CHANNEL_PINNED_MESSAGE = 6,
+	GUILD_MEMBER_JOIN = 7,
+	USER_PREMIUM_GUILD_SUBSCRIPTION = 8,
+	USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_1 = 9,
+	USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_2 = 10,
+	USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_3 = 11,
+	CHANNEL_FOLLOW_ADD = 12,
+	ACTION = 13, // /me messages
+	GUILD_DISCOVERY_DISQUALIFIED = 14,
+	GUILD_DISCOVERY_REQUALIFIED = 15,
+	ENCRYPTED = 16,
+	REPLY = 19,
+	APPLICATION_COMMAND = 20, // application command or self command invocation
+	ROUTE_ADDED = 41, // custom message routing: new route affecting that channel
+	ROUTE_DISABLED = 42, // custom message routing: given route no longer affecting that channel
+	SELF_COMMAND_SCRIPT = 43, // self command scripts
+	ENCRYPTION = 50,
+	CUSTOM_START = 63,
+	UNHANDLED = 255
+}
+
+@Entity("messages")
+@Index(["channel_id", "id"], { unique: true })
+export class Message extends BaseClass {
+	@Column({ nullable: true })
+	@RelationId((message: Message) => message.channel)
+	@Index()
+	channel_id: string;
+
+	@JoinColumn({ name: "channel_id" })
+	@ManyToOne(() => Channel, {
+		onDelete: "CASCADE"
+	})
+	channel: Channel;
+
+	@Column({ nullable: true })
+	@RelationId((message: Message) => message.guild)
+	guild_id?: string;
+
+	@JoinColumn({ name: "guild_id" })
+	@ManyToOne(() => Guild, {
+		onDelete: "CASCADE"
+	})
+	guild?: Guild;
+
+	@Column({ nullable: true })
+	@RelationId((message: Message) => message.author)
+	@Index()
+	author_id: string;
+
+	@JoinColumn({ name: "author_id", referencedColumnName: "id" })
+	@ManyToOne(() => User, {
+		onDelete: "CASCADE"
+	})
+	author?: User;
+
+	@Column({ nullable: true })
+	@RelationId((message: Message) => message.member)
+	member_id: string;
+
+	@JoinColumn({ name: "member_id", referencedColumnName: "id" })
+	@ManyToOne(() => User, {
+		onDelete: "CASCADE"
+	})
+	member?: Member;
+
+	@Column({ nullable: true })
+	@RelationId((message: Message) => message.webhook)
+	webhook_id: string;
+
+	@JoinColumn({ name: "webhook_id" })
+	@ManyToOne(() => Webhook)
+	webhook?: Webhook;
+
+	@Column({ nullable: true })
+	@RelationId((message: Message) => message.application)
+	application_id: string;
+
+	@JoinColumn({ name: "application_id" })
+	@ManyToOne(() => Application)
+	application?: Application;
+
+	@Column({ nullable: true })
+	content?: string;
+
+	@Column()
+	@CreateDateColumn()
+	timestamp: Date;
+
+	@Column({ nullable: true })
+	edited_timestamp?: Date;
+
+	@Column({ nullable: true })
+	tts?: boolean;
+
+	@Column({ nullable: true })
+	mention_everyone?: boolean;
+
+	@JoinTable({ name: "message_user_mentions" })
+	@ManyToMany(() => User)
+	mentions: User[];
+
+	@JoinTable({ name: "message_role_mentions" })
+	@ManyToMany(() => Role)
+	mention_roles: Role[];
+
+	@JoinTable({ name: "message_channel_mentions" })
+	@ManyToMany(() => Channel)
+	mention_channels: Channel[];
+
+	@JoinTable({ name: "message_stickers" })
+	@ManyToMany(() => Sticker, { cascade: true, onDelete: "CASCADE" })
+	sticker_items?: Sticker[];
+
+	@OneToMany(() => Attachment, (attachment: Attachment) => attachment.message, {
+		cascade: true,
+		orphanedRowAction: "delete"
+	})
+	attachments?: Attachment[];
+
+	@Column({ type: "simple-json" })
+	embeds: Embed[];
+
+	@Column({ type: "simple-json" })
+	reactions: Reaction[];
+
+	@Column({ type: "text", nullable: true })
+	nonce?: string;
+
+	@Column({ nullable: true })
+	pinned?: boolean;
+
+	@Column({ type: "int" })
+	type: MessageType;
+
+	@Column({ type: "simple-json", nullable: true })
+	activity?: {
+		type: number;
+		party_id: string;
+	};
+
+	@Column({ nullable: true })
+	flags?: string;
+	@Column({ type: "simple-json", nullable: true })
+	message_reference?: {
+		message_id: string;
+		channel_id?: string;
+		guild_id?: string;
+	};
+
+	@JoinColumn({ name: "message_reference_id" })
+	@ManyToOne(() => Message)
+	referenced_message?: Message;
+
+	@Column({ type: "simple-json", nullable: true })
+	interaction?: {
+		id: string;
+		type: InteractionType;
+		name: string;
+		user_id: string; // the user who invoked the interaction
+		// user: User; // TODO: autopopulate user
+	};
+
+	@Column({ type: "simple-json", nullable: true })
+	components?: MessageComponent[];
+}
+
+export interface MessageComponent {
+	type: number;
+	style?: number;
+	label?: string;
+	emoji?: PartialEmoji;
+	custom_id?: string;
+	url?: string;
+	disabled?: boolean;
+	components: MessageComponent[];
+}
+
+export enum MessageComponentType {
+	Script = 0, // self command script
+	ActionRow = 1,
+	Button = 2
+}
+
+export interface Embed {
+	title?: string; //title of embed
+	type?: EmbedType; // type of embed (always "rich" for webhook embeds)
+	description?: string; // description of embed
+	url?: string; // url of embed
+	timestamp?: Date; // timestamp of embed content
+	color?: number; // color code of the embed
+	footer?: {
+		text: string;
+		icon_url?: string;
+		proxy_icon_url?: string;
+	}; // footer object	footer information
+	image?: EmbedImage; // image object	image information
+	thumbnail?: EmbedImage; // thumbnail object	thumbnail information
+	video?: EmbedImage; // video object	video information
+	provider?: {
+		name?: string;
+		url?: string;
+	}; // provider object	provider information
+	author?: {
+		name?: string;
+		url?: string;
+		icon_url?: string;
+		proxy_icon_url?: string;
+	}; // author object	author information
+	fields?: {
+		name: string;
+		value: string;
+		inline?: boolean;
+	}[];
+}
+
+export enum EmbedType {
+	rich = "rich",
+	image = "image",
+	video = "video",
+	gifv = "gifv",
+	article = "article",
+	link = "link"
+}
+
+export interface EmbedImage {
+	url?: string;
+	proxy_url?: string;
+	height?: number;
+	width?: number;
+}
+
+export interface Reaction {
+	count: number;
+	//// not saved in the database // me: boolean; // whether the current user reacted using this emoji
+	emoji: PartialEmoji;
+	user_ids: string[];
+}
+
+export interface PartialEmoji {
+	id?: string;
+	name: string;
+	animated?: boolean;
+}
+
+export interface AllowedMentions {
+	parse?: ("users" | "roles" | "everyone")[];
+	roles?: string[];
+	users?: string[];
+	replied_user?: boolean;
+}
diff --git a/src/util/entities/Migration.ts b/src/util/entities/Migration.ts
new file mode 100644
index 00000000..626ec429
--- /dev/null
+++ b/src/util/entities/Migration.ts
@@ -0,0 +1,16 @@
+import { Column, Entity, ObjectIdColumn, PrimaryGeneratedColumn } from "typeorm";
+import { BaseClassWithoutId } from ".";
+
+export const PrimaryIdAutoGenerated = process.env.DATABASE?.startsWith("mongodb") ? ObjectIdColumn : PrimaryGeneratedColumn;
+
+@Entity("migrations")
+export class Migration extends BaseClassWithoutId {
+	@PrimaryIdAutoGenerated()
+	id: number;
+
+	@Column({ type: "bigint" })
+	timestamp: number;
+
+	@Column()
+	name: string;
+}
diff --git a/src/util/entities/Note.ts b/src/util/entities/Note.ts
new file mode 100644
index 00000000..b3ac45ee
--- /dev/null
+++ b/src/util/entities/Note.ts
@@ -0,0 +1,18 @@
+import { Column, Entity, JoinColumn, ManyToOne, Unique } from "typeorm";
+import { BaseClass } from "./BaseClass";
+import { User } from "./User";
+
+@Entity("notes")
+@Unique(["owner", "target"])
+export class Note extends BaseClass {
+	@JoinColumn({ name: "owner_id" })
+	@ManyToOne(() => User, { onDelete: "CASCADE" })
+	owner: User;
+
+	@JoinColumn({ name: "target_id" })
+	@ManyToOne(() => User, { onDelete: "CASCADE" })
+	target: User;
+
+	@Column()
+	content: string;
+}
diff --git a/src/util/entities/RateLimit.ts b/src/util/entities/RateLimit.ts
new file mode 100644
index 00000000..f5916f6b
--- /dev/null
+++ b/src/util/entities/RateLimit.ts
@@ -0,0 +1,17 @@
+import { Column, Entity } from "typeorm";
+import { BaseClass } from "./BaseClass";
+
+@Entity("rate_limits")
+export class RateLimit extends BaseClass {
+	@Column() // no relation as it also
+	executor_id: string;
+
+	@Column()
+	hits: number;
+
+	@Column()
+	blocked: boolean;
+
+	@Column()
+	expires_at: Date;
+}
diff --git a/src/util/entities/ReadState.ts b/src/util/entities/ReadState.ts
new file mode 100644
index 00000000..77d2c08a
--- /dev/null
+++ b/src/util/entities/ReadState.ts
@@ -0,0 +1,54 @@
+import { Column, Entity, Index, JoinColumn, ManyToOne, RelationId } from "typeorm";
+import { BaseClass } from "./BaseClass";
+import { Channel } from "./Channel";
+import { User } from "./User";
+
+// for read receipts
+// notification cursor and public read receipt need to be forwards-only (the former to prevent re-pinging when marked as unread, and the latter to be acceptable as a legal acknowledgement in criminal proceedings), and private read marker needs to be advance-rewind capable
+// public read receipt ≥ notification cursor ≥ private fully read marker
+
+@Entity("read_states")
+@Index(["channel_id", "user_id"], { unique: true })
+export class ReadState extends BaseClass {
+	@Column()
+	@RelationId((read_state: ReadState) => read_state.channel)
+	channel_id: string;
+
+	@JoinColumn({ name: "channel_id" })
+	@ManyToOne(() => Channel, {
+		onDelete: "CASCADE"
+	})
+	channel: Channel;
+
+	@Column()
+	@RelationId((read_state: ReadState) => read_state.user)
+	user_id: string;
+
+	@JoinColumn({ name: "user_id" })
+	@ManyToOne(() => User, {
+		onDelete: "CASCADE"
+	})
+	user: User;
+
+	// fully read marker
+	@Column({ nullable: true })
+	last_message_id: string;
+
+	// public read receipt
+	@Column({ nullable: true })
+	public_ack: string;
+
+	// notification cursor / private read receipt
+	@Column({ nullable: true })
+	notifications_cursor: string;
+
+	@Column({ nullable: true })
+	last_pin_timestamp?: Date;
+
+	@Column({ nullable: true })
+	mention_count: number;
+
+	// @Column({ nullable: true })
+	// TODO: derive this from (last_message_id=notifications_cursor=public_ack)=true
+	manual: boolean;
+}
diff --git a/src/util/entities/Recipient.ts b/src/util/entities/Recipient.ts
new file mode 100644
index 00000000..fc9e629b
--- /dev/null
+++ b/src/util/entities/Recipient.ts
@@ -0,0 +1,30 @@
+import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
+import { BaseClass } from "./BaseClass";
+
+@Entity("recipients")
+export class Recipient extends BaseClass {
+	@Column()
+	@RelationId((recipient: Recipient) => recipient.channel)
+	channel_id: string;
+
+	@JoinColumn({ name: "channel_id" })
+	@ManyToOne(() => require("./Channel").Channel, {
+		onDelete: "CASCADE"
+	})
+	channel: import("./Channel").Channel;
+
+	@Column()
+	@RelationId((recipient: Recipient) => recipient.user)
+	user_id: string;
+
+	@JoinColumn({ name: "user_id" })
+	@ManyToOne(() => require("./User").User, {
+		onDelete: "CASCADE"
+	})
+	user: import("./User").User;
+
+	@Column({ default: false })
+	closed: boolean;
+
+	// TODO: settings/mute/nick/added at/encryption keys/read_state
+}
diff --git a/src/util/entities/Relationship.ts b/src/util/entities/Relationship.ts
new file mode 100644
index 00000000..b55d9e64
--- /dev/null
+++ b/src/util/entities/Relationship.ts
@@ -0,0 +1,49 @@
+import { Column, Entity, Index, JoinColumn, ManyToOne, RelationId } from "typeorm";
+import { BaseClass } from "./BaseClass";
+import { User } from "./User";
+
+export enum RelationshipType {
+	outgoing = 4,
+	incoming = 3,
+	blocked = 2,
+	friends = 1
+}
+
+@Entity("relationships")
+@Index(["from_id", "to_id"], { unique: true })
+export class Relationship extends BaseClass {
+	@Column({})
+	@RelationId((relationship: Relationship) => relationship.from)
+	from_id: string;
+
+	@JoinColumn({ name: "from_id" })
+	@ManyToOne(() => User, {
+		onDelete: "CASCADE"
+	})
+	from: User;
+
+	@Column({})
+	@RelationId((relationship: Relationship) => relationship.to)
+	to_id: string;
+
+	@JoinColumn({ name: "to_id" })
+	@ManyToOne(() => User, {
+		onDelete: "CASCADE"
+	})
+	to: User;
+
+	@Column({ nullable: true })
+	nickname?: string;
+
+	@Column({ type: "int" })
+	type: RelationshipType;
+
+	toPublicRelationship() {
+		return {
+			id: this.to?.id || this.to_id,
+			type: this.type,
+			nickname: this.nickname,
+			user: this.to?.toPublicUser()
+		};
+	}
+}
diff --git a/src/util/entities/Role.ts b/src/util/entities/Role.ts
new file mode 100644
index 00000000..b1fd9bb1
--- /dev/null
+++ b/src/util/entities/Role.ts
@@ -0,0 +1,51 @@
+import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
+
+import { BaseClass } from "./BaseClass";
+import { Guild } from "./Guild";
+
+@Entity("roles")
+export class Role extends BaseClass {
+	@Column({ nullable: true })
+	@RelationId((role: Role) => role.guild)
+	guild_id: string;
+
+	@JoinColumn({ name: "guild_id" })
+	@ManyToOne(() => Guild, {
+		onDelete: "CASCADE"
+	})
+	guild: Guild;
+
+	@Column()
+	color: number;
+
+	@Column()
+	hoist: boolean;
+
+	@Column()
+	managed: boolean;
+
+	@Column()
+	mentionable: boolean;
+
+	@Column()
+	name: string;
+
+	@Column()
+	permissions: string;
+
+	@Column()
+	position: number;
+
+	@Column({ nullable: true })
+	icon: string;
+
+	@Column({ nullable: true })
+	unicode_emoji: string;
+
+	@Column({ type: "simple-json", nullable: true })
+	tags?: {
+		bot_id?: string;
+		integration_id?: string;
+		premium_subscriber?: boolean;
+	};
+}
diff --git a/src/util/entities/Session.ts b/src/util/entities/Session.ts
new file mode 100644
index 00000000..0cb4c309
--- /dev/null
+++ b/src/util/entities/Session.ts
@@ -0,0 +1,40 @@
+import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
+import { Activity } from "../interfaces/Activity";
+import { Status } from "../interfaces/Status";
+import { BaseClass } from "./BaseClass";
+import { User } from "./User";
+
+//TODO we need to remove all sessions on server start because if the server crashes without closing websockets it won't delete them
+
+@Entity("sessions")
+export class Session extends BaseClass {
+	@Column({ nullable: true })
+	@RelationId((session: Session) => session.user)
+	user_id: string;
+
+	@JoinColumn({ name: "user_id" })
+	@ManyToOne(() => User, {
+		onDelete: "CASCADE"
+	})
+	user: User;
+
+	//TODO check, should be 32 char long hex string
+	@Column({ nullable: false, select: false })
+	session_id: string;
+
+	@Column({ type: "simple-json", nullable: true })
+	activities: Activity[];
+
+	// TODO client_status
+	@Column({ type: "simple-json", select: false })
+	client_info: {
+		client: string;
+		os: string;
+		version: number;
+	};
+
+	@Column({ nullable: false, type: "varchar" })
+	status: Status; //TODO enum
+}
+
+export const PrivateSessionProjection: (keyof Session)[] = ["user_id", "session_id", "activities", "client_info", "status"];
diff --git a/src/util/entities/Sticker.ts b/src/util/entities/Sticker.ts
new file mode 100644
index 00000000..69836e62
--- /dev/null
+++ b/src/util/entities/Sticker.ts
@@ -0,0 +1,66 @@
+import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
+import { BaseClass } from "./BaseClass";
+import { Guild } from "./Guild";
+import { User } from "./User";
+
+export enum StickerType {
+	STANDARD = 1,
+	GUILD = 2
+}
+
+export enum StickerFormatType {
+	GIF = 0, // gif is a custom format type and not in discord spec
+	PNG = 1,
+	APNG = 2,
+	LOTTIE = 3
+}
+
+@Entity("stickers")
+export class Sticker extends BaseClass {
+	@Column()
+	name: string;
+
+	@Column({ nullable: true })
+	description?: string;
+
+	@Column({ nullable: true })
+	available?: boolean;
+
+	@Column({ nullable: true })
+	tags?: string;
+
+	@Column({ nullable: true })
+	@RelationId((sticker: Sticker) => sticker.pack)
+	pack_id?: string;
+
+	@JoinColumn({ name: "pack_id" })
+	@ManyToOne(() => require("./StickerPack").StickerPack, {
+		onDelete: "CASCADE",
+		nullable: true
+	})
+	pack: import("./StickerPack").StickerPack;
+
+	@Column({ nullable: true })
+	guild_id?: string;
+
+	@JoinColumn({ name: "guild_id" })
+	@ManyToOne(() => Guild, {
+		onDelete: "CASCADE"
+	})
+	guild?: Guild;
+
+	@Column({ nullable: true })
+	user_id?: string;
+
+	@JoinColumn({ name: "user_id" })
+	@ManyToOne(() => User, {
+		onDelete: "CASCADE"
+	})
+	user?: User;
+
+	@Column({ type: "int" })
+	type: StickerType;
+
+	@Column({ type: "int" })
+	format_type: StickerFormatType;
+}
diff --git a/src/util/entities/StickerPack.ts b/src/util/entities/StickerPack.ts
new file mode 100644
index 00000000..4619af34
--- /dev/null
+++ b/src/util/entities/StickerPack.ts
@@ -0,0 +1,31 @@
+import { Column, Entity, JoinColumn, ManyToOne, OneToMany, RelationId } from "typeorm";
+import { Sticker } from ".";
+import { BaseClass } from "./BaseClass";
+
+@Entity("sticker_packs")
+export class StickerPack extends BaseClass {
+	@Column()
+	name: string;
+
+	@Column({ nullable: true })
+	description?: string;
+
+	@Column({ nullable: true })
+	banner_asset_id?: string;
+
+	@OneToMany(() => Sticker, (sticker: Sticker) => sticker.pack, {
+		cascade: true,
+		orphanedRowAction: "delete"
+	})
+	stickers: Sticker[];
+
+	// sku_id: string
+
+	@Column({ nullable: true })
+	@RelationId((pack: StickerPack) => pack.cover_sticker)
+	cover_sticker_id?: string;
+
+	@ManyToOne(() => Sticker, { nullable: true })
+	@JoinColumn()
+	cover_sticker?: Sticker;
+}
diff --git a/src/util/entities/Team.ts b/src/util/entities/Team.ts
new file mode 100644
index 00000000..1d2d7002
--- /dev/null
+++ b/src/util/entities/Team.ts
@@ -0,0 +1,27 @@
+import { Column, Entity, JoinColumn, ManyToOne, OneToMany, RelationId } from "typeorm";
+import { BaseClass } from "./BaseClass";
+import { TeamMember } from "./TeamMember";
+import { User } from "./User";
+
+@Entity("teams")
+export class Team extends BaseClass {
+	@Column({ nullable: true })
+	icon?: string;
+
+	@JoinColumn({ name: "member_ids" })
+	@OneToMany(() => TeamMember, (member: TeamMember) => member.team, {
+		orphanedRowAction: "delete"
+	})
+	members: TeamMember[];
+
+	@Column()
+	name: string;
+
+	@Column({ nullable: true })
+	@RelationId((team: Team) => team.owner_user)
+	owner_user_id: string;
+
+	@JoinColumn({ name: "owner_user_id" })
+	@ManyToOne(() => User)
+	owner_user: User;
+}
diff --git a/src/util/entities/TeamMember.ts b/src/util/entities/TeamMember.ts
new file mode 100644
index 00000000..d11ebf95
--- /dev/null
+++ b/src/util/entities/TeamMember.ts
@@ -0,0 +1,37 @@
+import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
+import { BaseClass } from "./BaseClass";
+import { User } from "./User";
+
+export enum TeamMemberState {
+	INVITED = 1,
+	ACCEPTED = 2
+}
+
+@Entity("team_members")
+export class TeamMember extends BaseClass {
+	@Column({ type: "int" })
+	membership_state: TeamMemberState;
+
+	@Column({ type: "simple-array" })
+	permissions: string[];
+
+	@Column({ nullable: true })
+	@RelationId((member: TeamMember) => member.team)
+	team_id: string;
+
+	@JoinColumn({ name: "team_id" })
+	@ManyToOne(() => require("./Team").Team, (team: import("./Team").Team) => team.members, {
+		onDelete: "CASCADE"
+	})
+	team: import("./Team").Team;
+
+	@Column({ nullable: true })
+	@RelationId((member: TeamMember) => member.user)
+	user_id: string;
+
+	@JoinColumn({ name: "user_id" })
+	@ManyToOne(() => User, {
+		onDelete: "CASCADE"
+	})
+	user: User;
+}
diff --git a/src/util/entities/Template.ts b/src/util/entities/Template.ts
new file mode 100644
index 00000000..1d952283
--- /dev/null
+++ b/src/util/entities/Template.ts
@@ -0,0 +1,44 @@
+import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
+import { BaseClass } from "./BaseClass";
+import { Guild } from "./Guild";
+import { User } from "./User";
+
+@Entity("templates")
+export class Template extends BaseClass {
+	@Column({ unique: true })
+	code: string;
+
+	@Column()
+	name: string;
+
+	@Column({ nullable: true })
+	description?: string;
+
+	@Column({ nullable: true })
+	usage_count?: number;
+
+	@Column({ nullable: true })
+	@RelationId((template: Template) => template.creator)
+	creator_id: string;
+
+	@JoinColumn({ name: "creator_id" })
+	@ManyToOne(() => User)
+	creator: User;
+
+	@Column()
+	created_at: Date;
+
+	@Column()
+	updated_at: Date;
+
+	@Column({ nullable: true })
+	@RelationId((template: Template) => template.source_guild)
+	source_guild_id: string;
+
+	@JoinColumn({ name: "source_guild_id" })
+	@ManyToOne(() => Guild)
+	source_guild: Guild;
+
+	@Column({ type: "simple-json" })
+	serialized_source_guild: Guild;
+}
diff --git a/src/util/entities/User.ts b/src/util/entities/User.ts
new file mode 100644
index 00000000..1237b676
--- /dev/null
+++ b/src/util/entities/User.ts
@@ -0,0 +1,321 @@
+import { Column, Entity, FindOneOptions, FindOptionsSelectByString, JoinColumn, OneToMany, OneToOne } from "typeorm";
+import { Member, Session, UserSettings } from ".";
+import { Config, FieldErrors, Snowflake, trimSpecial } from "..";
+import { BitField } from "../util/BitField";
+import { OrmUtils } from "../util/imports/OrmUtils";
+import { BaseClass } from "./BaseClass";
+import { ConnectedAccount } from "./ConnectedAccount";
+import { Relationship } from "./Relationship";
+
+export enum PublicUserEnum {
+	username,
+	discriminator,
+	id,
+	public_flags,
+	avatar,
+	accent_color,
+	banner,
+	bio,
+	bot,
+	premium_since
+}
+export type PublicUserKeys = keyof typeof PublicUserEnum;
+
+export enum PrivateUserEnum {
+	flags,
+	mfa_enabled,
+	email,
+	phone,
+	verified,
+	nsfw_allowed,
+	premium,
+	premium_type,
+	disabled,
+	settings
+	// locale
+}
+export type PrivateUserKeys = keyof typeof PrivateUserEnum | PublicUserKeys;
+
+export const PublicUserProjection = Object.values(PublicUserEnum).filter((x) => typeof x === "string") as PublicUserKeys[];
+export const PrivateUserProjection = [
+	...PublicUserProjection,
+	...Object.values(PrivateUserEnum).filter((x) => typeof x === "string")
+] as PrivateUserKeys[];
+
+// 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 UserPrivate extends Pick<User, PrivateUserKeys> {
+	locale: string;
+}
+
+// TODO: add purchased_flags, premium_usage_flags
+
+@Entity("users")
+export class User extends BaseClass {
+	@Column()
+	username: string; // username max length 32, min 2 (should be configurable)
+
+	@Column()
+	discriminator: string; // opaque string: 4 digits on discord.com
+
+	setDiscriminator(val: string) {
+		const number = Number(val);
+		if (isNaN(number)) throw new Error("invalid discriminator");
+		if (number <= 0 || number >= 10000) throw new Error("discriminator must be between 1 and 9999");
+		this.discriminator = val.toString().padStart(4, "0");
+	}
+
+	@Column({ nullable: true })
+	avatar?: string; // hash of the user avatar
+
+	@Column({ nullable: true })
+	accent_color?: number; // banner color of user
+
+	@Column({ nullable: true })
+	banner?: string; // hash of the user banner
+
+	@Column({ nullable: true, select: false })
+	phone?: string; // phone number of the user
+
+	@Column({ select: false })
+	desktop: boolean = false; // if the user has desktop app installed
+
+	@Column({ select: false })
+	mobile: boolean = false; // if the user has mobile app installed
+
+	@Column()
+	premium: boolean = Config.get().defaults.user.premium; // if user bought individual premium
+
+	@Column()
+	premium_type: number = Config.get().defaults.user.premium_type; // individual premium level
+
+	@Column()
+	bot: boolean = false; // if user is bot
+
+	@Column({ nullable: true })
+	bio: string; // short description of the user (max 190 chars -> should be configurable)
+
+	@Column()
+	system: boolean = false; // shouldn't be used, the api sends this field type true, if the generated message comes from a system generated author
+
+	@Column({ select: false })
+	nsfw_allowed: boolean = true; // if the user can do age-restricted actions (NSFW channels/guilds/commands) // TODO: depending on age
+
+	@Column({ select: false, nullable: true })
+	mfa_enabled: boolean; // if multi factor authentication is enabled
+
+	@Column({ select: false, nullable: true })
+	totp_secret?: string;
+
+	@Column({ nullable: true, select: false })
+	totp_last_ticket?: string;
+
+	@Column()
+	created_at: Date = new Date(); // registration date
+
+	@Column({ nullable: true })
+	premium_since: Date = new Date(); // premium date
+
+	@Column({ select: false })
+	verified: boolean = Config.get().defaults.user.verified; // if the user is offically verified
+
+	@Column()
+	disabled: boolean = false; // if the account is disabled
+
+	@Column()
+	deleted: boolean = false; // if the user was deleted
+
+	@Column({ nullable: true, select: false })
+	email?: string; // email of the user
+
+	@Column()
+	flags: string = "0"; // UserFlags // TODO: generate
+
+	@Column()
+	public_flags: number = 0;
+
+	@Column({ type: "bigint" })
+	rights: string = Config.get().register.defaultRights; // Rights
+
+	@OneToMany(() => Session, (session: Session) => session.user)
+	sessions: Session[];
+
+	@JoinColumn({ name: "relationship_ids" })
+	@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"
+	})
+	connected_accounts: ConnectedAccount[];
+
+	@Column({ type: "simple-json", select: false })
+	data: {
+		valid_tokens_since: Date; // all tokens with a previous issue date are invalid
+		hash?: string; // hash of the password, salt is saved in password (bcrypt)
+	};
+
+	@Column({ type: "simple-array", select: false })
+	fingerprints: string[] = []; // array of fingerprints -> used to prevent multiple accounts
+
+	@OneToOne(() => UserSettings, {
+		cascade: true,
+		orphanedRowAction: "delete",
+		eager: false
+	})
+	@JoinColumn()
+	settings: UserSettings;
+
+	// workaround to prevent fossord-unaware clients from deleting settings not used by them
+	@Column({ type: "simple-json", select: false })
+	extended_settings: string = "{}";
+
+	@Column({ type: "simple-json" })
+	notes: { [key: string]: string } = {}; //key is ID of user
+
+	async save(): Promise<any> {
+		if (!this.settings) this.settings = new UserSettings();
+		this.settings.id = this.id;
+		//await this.settings.save();
+		return super.save();
+	}
+
+	toPublicUser() {
+		const user: any = {};
+		PublicUserProjection.forEach((x) => {
+			user[x] = this[x];
+		});
+		return user as PublicUser;
+	}
+
+	static async getPublicUser(user_id: string, opts?: FindOneOptions<User>) {
+		return await User.findOneOrFail({
+			where: { id: user_id },
+			select: [...PublicUserProjection, ...((opts?.select as FindOptionsSelectByString<User>) || [])],
+			...opts
+		});
+	}
+
+	public 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 discriminator = highestDiscriminator + 1;
+			if (discriminator >= 10000) {
+				return undefined;
+			}
+
+			return discriminator.toString().padStart(4, "0");
+		} else {
+			// discriminator will be randomly generated
+
+			// 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"] });
+				if (!exists) return discriminator;
+			}
+
+			return undefined;
+		}
+	}
+
+	static async register({
+		email,
+		username,
+		password,
+		date_of_birth,
+		req
+	}: {
+		username: string;
+		password?: string;
+		email?: string;
+		date_of_birth?: Date; // "2000-04-03"
+		req?: any;
+	}) {
+		// trim special uf8 control characters -> Backspace, Newline, ...
+		username = trimSpecial(username);
+
+		const discriminator = await User.generateDiscriminator(username);
+		if (!discriminator) {
+			// We've failed to generate a valid and unused discriminator
+			throw FieldErrors({
+				username: {
+					code: "USERNAME_TOO_MANY_USERS",
+					message: req?.t("auth:register.USERNAME_TOO_MANY_USERS")
+				}
+			});
+		}
+
+		// 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 user = OrmUtils.mergeDeep(new User(), {
+			//required:
+			username: username,
+			discriminator,
+			id: Snowflake.generate(),
+			email: email,
+			data: {
+				hash: password,
+				valid_tokens_since: new Date()
+			},
+			settings: { ...new UserSettings(), locale: language }
+		});
+
+		//await (user.settings as UserSettings).save();
+		await user.save();
+
+		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) => {});
+				}
+			}
+		});
+
+		return user;
+	}
+}
+
+export const CUSTOM_USER_FLAG_OFFSET = BigInt(1) << BigInt(32);
+
+export class UserFlags extends BitField {
+	static FLAGS = {
+		DISCORD_EMPLOYEE: BigInt(1) << BigInt(0),
+		PARTNERED_SERVER_OWNER: BigInt(1) << BigInt(1),
+		HYPESQUAD_EVENTS: BigInt(1) << BigInt(2),
+		BUGHUNTER_LEVEL_1: BigInt(1) << BigInt(3),
+		MFA_SMS: BigInt(1) << BigInt(4),
+		PREMIUM_PROMO_DISMISSED: BigInt(1) << BigInt(5),
+		HOUSE_BRAVERY: BigInt(1) << BigInt(6),
+		HOUSE_BRILLIANCE: BigInt(1) << BigInt(7),
+		HOUSE_BALANCE: BigInt(1) << BigInt(8),
+		EARLY_SUPPORTER: BigInt(1) << BigInt(9),
+		TEAM_USER: BigInt(1) << BigInt(10),
+		TRUST_AND_SAFETY: BigInt(1) << BigInt(11),
+		SYSTEM: BigInt(1) << BigInt(12),
+		HAS_UNREAD_URGENT_MESSAGES: BigInt(1) << BigInt(13),
+		BUGHUNTER_LEVEL_2: BigInt(1) << BigInt(14),
+		UNDERAGE_DELETED: BigInt(1) << BigInt(15),
+		VERIFIED_BOT: BigInt(1) << BigInt(16),
+		EARLY_VERIFIED_BOT_DEVELOPER: BigInt(1) << BigInt(17),
+		CERTIFIED_MODERATOR: BigInt(1) << BigInt(18),
+		BOT_HTTP_INTERACTIONS: BigInt(1) << BigInt(19)
+	};
+}
diff --git a/src/util/entities/UserGroup.ts b/src/util/entities/UserGroup.ts
new file mode 100644
index 00000000..08d68a4e
--- /dev/null
+++ b/src/util/entities/UserGroup.ts
@@ -0,0 +1,35 @@
+import { Column, Entity, JoinColumn, ManyToOne } from "typeorm";
+
+import { BaseClass } from "./BaseClass";
+import { User } from "./User";
+
+@Entity("groups")
+export class UserGroup extends BaseClass {
+	@Column()
+	color: number;
+
+	@Column()
+	hoist: boolean;
+
+	@JoinColumn({ name: "controller", referencedColumnName: "id" })
+	@ManyToOne(() => User)
+	controller?: User;
+
+	@Column()
+	mentionable_by?: string;
+
+	@Column()
+	name: string;
+
+	@Column()
+	rights: string;
+
+	@Column({ nullable: true })
+	icon: string;
+
+	@Column({ nullable: true })
+	parent?: string;
+
+	@Column({ type: "simple-array", nullable: true })
+	associciations: string[];
+}
diff --git a/src/util/entities/UserSettings.ts b/src/util/entities/UserSettings.ts
new file mode 100644
index 00000000..9fa18a4d
--- /dev/null
+++ b/src/util/entities/UserSettings.ts
@@ -0,0 +1,119 @@
+import { Column, Entity } from "typeorm";
+import { BaseClassWithoutId, PrimaryIdColumn } from ".";
+
+@Entity("user_settings")
+export class UserSettings extends BaseClassWithoutId {
+	@PrimaryIdColumn()
+	id: string;
+
+	@Column({ nullable: true })
+	afk_timeout: number = 3600;
+
+	@Column({ nullable: true })
+	allow_accessibility_detection: boolean = true;
+
+	@Column({ nullable: true })
+	animate_emoji: boolean = true;
+
+	@Column({ nullable: true })
+	animate_stickers: number = 0;
+
+	@Column({ nullable: true })
+	contact_sync_enabled: boolean = false;
+
+	@Column({ nullable: true })
+	convert_emoticons: boolean = false;
+
+	@Column({ nullable: true, type: "simple-json" })
+	custom_status: CustomStatus | null = null;
+
+	@Column({ nullable: true })
+	default_guilds_restricted: boolean = false;
+
+	@Column({ nullable: true })
+	detect_platform_accounts: boolean = false;
+
+	@Column({ nullable: true })
+	developer_mode: boolean = true;
+
+	@Column({ nullable: true })
+	disable_games_tab: boolean = true;
+
+	@Column({ nullable: true })
+	enable_tts_command: boolean = false;
+
+	@Column({ nullable: true })
+	explicit_content_filter: number = 0;
+
+	@Column({ nullable: true, type: "simple-json" })
+	friend_source_flags: FriendSourceFlags = { all: true };
+
+	@Column({ nullable: true })
+	gateway_connected: boolean = false;
+
+	@Column({ nullable: true })
+	gif_auto_play: boolean = false;
+
+	@Column({ nullable: true, type: "simple-json" })
+	guild_folders: GuildFolder[] = []; // every top guild is displayed as a "folder"
+
+	@Column({ nullable: true, type: "simple-json" })
+	guild_positions: string[] = []; // guild ids ordered by position
+
+	@Column({ nullable: true })
+	inline_attachment_media: boolean = true;
+
+	@Column({ nullable: true })
+	inline_embed_media: boolean = true;
+
+	@Column({ nullable: true })
+	locale: string = "en-US"; // en_US
+
+	@Column({ nullable: true })
+	message_display_compact: boolean = false;
+
+	@Column({ nullable: true })
+	native_phone_integration_enabled: boolean = true;
+
+	@Column({ nullable: true })
+	render_embeds: boolean = true;
+
+	@Column({ nullable: true })
+	render_reactions: boolean = true;
+
+	@Column({ nullable: true, type: "simple-json" })
+	restricted_guilds: string[] = [];
+
+	@Column({ nullable: true })
+	show_current_game: boolean = true;
+
+	@Column({ nullable: true })
+	status: "online" | "offline" | "dnd" | "idle" | "invisible" = "online";
+
+	@Column({ nullable: true })
+	stream_notifications_enabled: boolean = false;
+
+	@Column({ nullable: true })
+	theme: "dark" | "white" = "dark"; // dark
+
+	@Column({ nullable: true })
+	timezone_offset: number = 0; // e.g -60
+}
+
+interface CustomStatus {
+	emoji_id?: string;
+	emoji_name?: string;
+	expires_at?: number;
+	text?: string;
+}
+
+interface GuildFolder {
+	color: number;
+	guild_ids: string[];
+	id: number;
+	name: string;
+}
+
+interface FriendSourceFlags {
+	all: boolean;
+}
diff --git a/src/util/entities/VoiceState.ts b/src/util/entities/VoiceState.ts
new file mode 100644
index 00000000..baf2c687
--- /dev/null
+++ b/src/util/entities/VoiceState.ts
@@ -0,0 +1,77 @@
+import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
+import { BaseClass } from "./BaseClass";
+import { Channel } from "./Channel";
+import { Guild } from "./Guild";
+import { Member } from "./Member";
+import { User } from "./User";
+
+//https://gist.github.com/vassjozsef/e482c65df6ee1facaace8b3c9ff66145#file-voice_state-ex
+@Entity("voice_states")
+export class VoiceState extends BaseClass {
+	@Column({ nullable: true })
+	@RelationId((voice_state: VoiceState) => voice_state.guild)
+	guild_id: string;
+
+	@JoinColumn({ name: "guild_id" })
+	@ManyToOne(() => Guild, {
+		onDelete: "CASCADE"
+	})
+	guild?: Guild;
+
+	@Column({ nullable: true })
+	@RelationId((voice_state: VoiceState) => voice_state.channel)
+	channel_id: string;
+
+	@JoinColumn({ name: "channel_id" })
+	@ManyToOne(() => Channel, {
+		onDelete: "CASCADE"
+	})
+	channel: Channel;
+
+	@Column({ nullable: true })
+	@RelationId((voice_state: VoiceState) => voice_state.user)
+	user_id: string;
+
+	@JoinColumn({ name: "user_id" })
+	@ManyToOne(() => User, {
+		onDelete: "CASCADE"
+	})
+	user: User;
+
+	// @JoinColumn([{ name: "user_id", referencedColumnName: "id" },{ name: "guild_id", referencedColumnName: "guild_id" }])
+	// @ManyToOne(() => Member, {
+	// 	onDelete: "CASCADE",
+	// })
+	//TODO find a way to make it work without breaking Guild.voice_states
+	member: Member;
+
+	@Column()
+	session_id: string;
+
+	@Column({ nullable: true })
+	token: string;
+
+	@Column()
+	deaf: boolean;
+
+	@Column()
+	mute: boolean;
+
+	@Column()
+	self_deaf: boolean;
+
+	@Column()
+	self_mute: boolean;
+
+	@Column({ nullable: true })
+	self_stream?: boolean;
+
+	@Column()
+	self_video: boolean;
+
+	@Column()
+	suppress: boolean; // whether this user is muted by the current user
+
+	@Column({ nullable: true, default: null })
+	request_to_speak_timestamp?: Date;
+}
diff --git a/src/util/entities/Webhook.ts b/src/util/entities/Webhook.ts
new file mode 100644
index 00000000..3d94ddb6
--- /dev/null
+++ b/src/util/entities/Webhook.ts
@@ -0,0 +1,76 @@
+import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
+import { Application } from "./Application";
+import { BaseClass } from "./BaseClass";
+import { Channel } from "./Channel";
+import { Guild } from "./Guild";
+import { User } from "./User";
+
+export enum WebhookType {
+	Incoming = 1,
+	ChannelFollower = 2
+}
+
+@Entity("webhooks")
+export class Webhook extends BaseClass {
+	@Column({ type: "int" })
+	type: WebhookType;
+
+	@Column({ nullable: true })
+	name?: string;
+
+	@Column({ nullable: true })
+	avatar?: string;
+
+	@Column({ nullable: true })
+	token?: string;
+
+	@Column({ nullable: true })
+	@RelationId((webhook: Webhook) => webhook.guild)
+	guild_id: string;
+
+	@JoinColumn({ name: "guild_id" })
+	@ManyToOne(() => Guild, {
+		onDelete: "CASCADE"
+	})
+	guild: Guild;
+
+	@Column({ nullable: true })
+	@RelationId((webhook: Webhook) => webhook.channel)
+	channel_id: string;
+
+	@JoinColumn({ name: "channel_id" })
+	@ManyToOne(() => Channel, {
+		onDelete: "CASCADE"
+	})
+	channel: Channel;
+
+	@Column({ nullable: true })
+	@RelationId((webhook: Webhook) => webhook.application)
+	application_id: string;
+
+	@JoinColumn({ name: "application_id" })
+	@ManyToOne(() => Application, {
+		onDelete: "CASCADE"
+	})
+	application: Application;
+
+	@Column({ nullable: true })
+	@RelationId((webhook: Webhook) => webhook.user)
+	user_id: string;
+
+	@JoinColumn({ name: "user_id" })
+	@ManyToOne(() => User, {
+		onDelete: "CASCADE"
+	})
+	user: User;
+
+	@Column({ nullable: true })
+	@RelationId((webhook: Webhook) => webhook.guild)
+	source_guild_id: string;
+
+	@JoinColumn({ name: "source_guild_id" })
+	@ManyToOne(() => Guild, {
+		onDelete: "CASCADE"
+	})
+	source_guild: Guild;
+}
diff --git a/src/util/entities/index.ts b/src/util/entities/index.ts
new file mode 100644
index 00000000..2b91c2ba
--- /dev/null
+++ b/src/util/entities/index.ts
@@ -0,0 +1,33 @@
+export * from "./Application";
+export * from "./Attachment";
+export * from "./AuditLog";
+export * from "./BackupCodes";
+export * from "./Ban";
+export * from "./BaseClass";
+export * from "./Categories";
+export * from "./Channel";
+export * from "./ClientRelease";
+export * from "./Config";
+export * from "./ConnectedAccount";
+export * from "./Emoji";
+export * from "./Guild";
+export * from "./Invite";
+export * from "./Member";
+export * from "./Message";
+export * from "./Migration";
+export * from "./Note";
+export * from "./RateLimit";
+export * from "./ReadState";
+export * from "./Recipient";
+export * from "./Relationship";
+export * from "./Role";
+export * from "./Session";
+export * from "./Sticker";
+export * from "./StickerPack";
+export * from "./Team";
+export * from "./TeamMember";
+export * from "./Template";
+export * from "./User";
+export * from "./UserSettings";
+export * from "./VoiceState";
+export * from "./Webhook";
diff --git a/src/util/index.ts b/src/util/index.ts
new file mode 100644
index 00000000..b26ed278
--- /dev/null
+++ b/src/util/index.ts
@@ -0,0 +1,9 @@
+import "reflect-metadata";
+
+export * from "./config/index";
+export * from "./dtos/index";
+export * from "./entities/index";
+export * from "./interfaces/index";
+export * from "./schemas";
+export * from "./util/index";
+export * from "./util/MFA";
diff --git a/src/util/interfaces/Activity.ts b/src/util/interfaces/Activity.ts
new file mode 100644
index 00000000..3b36b4a6
--- /dev/null
+++ b/src/util/interfaces/Activity.ts
@@ -0,0 +1,44 @@
+export interface Activity {
+	name: string; // the activity's name
+	type: ActivityType; // activity type // TODO: check if its between range 0-5
+	url?: string; // stream url, is validated when type is 1
+	created_at?: number; // unix timestamp of when the activity was added to the user's session
+	timestamps?: {
+		// unix timestamps for start and/or end of the game
+		start: number;
+		end: number;
+	};
+	application_id?: string; // application id for the game
+	details?: string;
+	state?: string;
+	emoji?: {
+		name: string;
+		id?: string;
+		animated: boolean;
+	};
+	party?: {
+		id?: string;
+		size?: [number]; // used to show the party's current and maximum size // TODO: array length 2
+	};
+	assets?: {
+		large_image?: string; // the id for a large asset of the activity, usually a snowflake
+		large_text?: string; // text displayed when hovering over the large image of the activity
+		small_image?: string; // the id for a small asset of the activity, usually a snowflake
+		small_text?: string; // text displayed when hovering over the small image of the activity
+	};
+	secrets?: {
+		join?: string; // the secret for joining a party
+		spectate?: string; // the secret for spectating a game
+		match?: string; // the secret for a specific instanced match
+	};
+	instance?: boolean;
+	flags: string; // activity flags OR d together, describes what the payload includes
+}
+
+export enum ActivityType {
+	GAME = 0,
+	STREAMING = 1,
+	LISTENING = 2,
+	CUSTOM = 4,
+	COMPETING = 5
+}
diff --git a/src/util/interfaces/Event.ts b/src/util/interfaces/Event.ts
new file mode 100644
index 00000000..f97f4615
--- /dev/null
+++ b/src/util/interfaces/Event.ts
@@ -0,0 +1,640 @@
+import { Activity, Status } from ".";
+import { Sticker, UserSettings } from "..";
+import { ApplicationCommand } from "../entities/Application";
+import { Channel } from "../entities/Channel";
+import { ConnectedAccount } from "../entities/ConnectedAccount";
+import { Emoji } from "../entities/Emoji";
+import { Guild } from "../entities/Guild";
+import { Invite } from "../entities/Invite";
+import { PublicMember, UserGuildSettings } from "../entities/Member";
+import { Message, PartialEmoji } from "../entities/Message";
+import { RelationshipType } from "../entities/Relationship";
+import { Role } from "../entities/Role";
+import { PublicUser, User } from "../entities/User";
+import { VoiceState } from "../entities/VoiceState";
+import { Interaction } from "./Interaction";
+import { Presence } from "./Presence";
+
+export interface Event {
+	guild_id?: string;
+	user_id?: string;
+	channel_id?: string;
+	created_at?: Date;
+	event: EVENT;
+	data?: any;
+}
+
+// ! Custom Events that shouldn't get sent to the client but processed by the server
+
+export interface InvalidatedEvent extends Event {
+	event: "INVALIDATED";
+}
+
+export interface PublicRelationship {
+	id: string;
+	user: PublicUser;
+	type: RelationshipType;
+}
+
+// ! END Custom Events that shouldn't get sent to the client but processed by the server
+
+export interface ReadyEventData {
+	v: number;
+	user: PublicUser & {
+		mobile: boolean;
+		desktop: boolean;
+		email: string | undefined;
+		flags: string;
+		mfa_enabled: boolean;
+		nsfw_allowed: boolean;
+		phone: string | undefined;
+		premium: boolean;
+		premium_type: number;
+		verified: boolean;
+		bot: boolean;
+	};
+	private_channels: Channel[]; // this will be empty for bots
+	session_id: string; // resuming
+	guilds: Guild[];
+	analytics_token?: string;
+	connected_accounts?: ConnectedAccount[];
+	consents?: {
+		personalization?: {
+			consented?: boolean;
+		};
+	};
+	country_code?: string; // e.g. DE
+	friend_suggestion_count?: number;
+	geo_ordered_rtc_regions?: string[]; // ["europe","russie","india","us-east","us-central"]
+	experiments?: [number, number, number, number, number][];
+	guild_experiments?: [
+		// ? what are guild_experiments?
+		// this is the structure of it:
+		number,
+		null,
+		number,
+		[[number, { e: number; s: number }[]]],
+		[number, [[number, [number, number]]]],
+		{ b: number; k: bigint[] }[]
+	][];
+	guild_join_requests?: any[]; // ? what is this? this is new
+	shard?: [number, number];
+	user_settings?: UserSettings;
+	relationships?: PublicRelationship[]; // TODO
+	read_state: {
+		entries: any[]; // TODO
+		partial: boolean;
+		version: number;
+	};
+	user_guild_settings?: {
+		entries: UserGuildSettings[];
+		version: number;
+		partial: boolean;
+	};
+	application?: {
+		id: string;
+		flags: number;
+	};
+	merged_members?: PublicMember[][];
+	// probably all users who the user is in contact with
+	users?: PublicUser[];
+}
+
+export interface ReadyEvent extends Event {
+	event: "READY";
+	data: ReadyEventData;
+}
+
+export interface ChannelCreateEvent extends Event {
+	event: "CHANNEL_CREATE";
+	data: Channel;
+}
+
+export interface ChannelUpdateEvent extends Event {
+	event: "CHANNEL_UPDATE";
+	data: Channel;
+}
+
+export interface ChannelDeleteEvent extends Event {
+	event: "CHANNEL_DELETE";
+	data: Channel;
+}
+
+export interface ChannelPinsUpdateEvent extends Event {
+	event: "CHANNEL_PINS_UPDATE";
+	data: {
+		guild_id?: string;
+		channel_id: string;
+		last_pin_timestamp?: number;
+	};
+}
+
+export interface ChannelRecipientAddEvent extends Event {
+	event: "CHANNEL_RECIPIENT_ADD";
+	data: {
+		channel_id: string;
+		user: User;
+	};
+}
+
+export interface ChannelRecipientRemoveEvent extends Event {
+	event: "CHANNEL_RECIPIENT_REMOVE";
+	data: {
+		channel_id: string;
+		user: User;
+	};
+}
+
+export interface GuildCreateEvent extends Event {
+	event: "GUILD_CREATE";
+	data: Guild & {
+		joined_at: Date;
+		// TODO: add them to guild
+		guild_scheduled_events: never[];
+		guild_hashes: {};
+		presences: never[];
+		stage_instances: never[];
+		threads: never[];
+	};
+}
+
+export interface GuildUpdateEvent extends Event {
+	event: "GUILD_UPDATE";
+	data: Guild;
+}
+
+export interface GuildDeleteEvent extends Event {
+	event: "GUILD_DELETE";
+	data: {
+		id: string;
+		unavailable?: boolean;
+	};
+}
+
+export interface GuildBanAddEvent extends Event {
+	event: "GUILD_BAN_ADD";
+	data: {
+		guild_id: string;
+		user: User;
+	};
+}
+
+export interface GuildBanRemoveEvent extends Event {
+	event: "GUILD_BAN_REMOVE";
+	data: {
+		guild_id: string;
+		user: User;
+	};
+}
+
+export interface GuildEmojisUpdateEvent extends Event {
+	event: "GUILD_EMOJIS_UPDATE";
+	data: {
+		guild_id: string;
+		emojis: Emoji[];
+	};
+}
+
+export interface GuildStickersUpdateEvent extends Event {
+	event: "GUILD_STICKERS_UPDATE";
+	data: {
+		guild_id: string;
+		stickers: Sticker[];
+	};
+}
+
+export interface GuildIntegrationUpdateEvent extends Event {
+	event: "GUILD_INTEGRATIONS_UPDATE";
+	data: {
+		guild_id: string;
+	};
+}
+
+export interface GuildMemberAddEvent extends Event {
+	event: "GUILD_MEMBER_ADD";
+	data: PublicMember & {
+		guild_id: string;
+	};
+}
+
+export interface GuildMemberRemoveEvent extends Event {
+	event: "GUILD_MEMBER_REMOVE";
+	data: {
+		guild_id: string;
+		user: User;
+	};
+}
+
+export interface GuildMemberUpdateEvent extends Event {
+	event: "GUILD_MEMBER_UPDATE";
+	data: {
+		guild_id: string;
+		roles: string[];
+		user: User;
+		nick?: string;
+		joined_at?: Date;
+		premium_since?: number;
+		pending?: boolean;
+	};
+}
+
+export interface GuildMembersChunkEvent extends Event {
+	event: "GUILD_MEMBERS_CHUNK";
+	data: {
+		guild_id: string;
+		members: PublicMember[];
+		chunk_index: number;
+		chunk_count: number;
+		not_found: string[];
+		presences: Presence[];
+		nonce?: string;
+	};
+}
+
+export interface GuildRoleCreateEvent extends Event {
+	event: "GUILD_ROLE_CREATE";
+	data: {
+		guild_id: string;
+		role: Role;
+	};
+}
+
+export interface GuildRoleUpdateEvent extends Event {
+	event: "GUILD_ROLE_UPDATE";
+	data: {
+		guild_id: string;
+		role: Role;
+	};
+}
+
+export interface GuildRoleDeleteEvent extends Event {
+	event: "GUILD_ROLE_DELETE";
+	data: {
+		guild_id: string;
+		role_id: string;
+	};
+}
+
+export interface InviteCreateEvent extends Event {
+	event: "INVITE_CREATE";
+	data: Omit<Invite, "guild" | "channel"> & {
+		channel_id: string;
+		guild_id?: string;
+	};
+}
+
+export interface InviteDeleteEvent extends Event {
+	event: "INVITE_DELETE";
+	data: {
+		channel_id: string;
+		guild_id?: string;
+		code: string;
+	};
+}
+
+export interface MessageCreateEvent extends Event {
+	event: "MESSAGE_CREATE";
+	data: Message;
+}
+
+export interface MessageUpdateEvent extends Event {
+	event: "MESSAGE_UPDATE";
+	data: Message;
+}
+
+export interface MessageDeleteEvent extends Event {
+	event: "MESSAGE_DELETE";
+	data: {
+		id: string;
+		channel_id: string;
+		guild_id?: string;
+	};
+}
+
+export interface MessageDeleteBulkEvent extends Event {
+	event: "MESSAGE_DELETE_BULK";
+	data: {
+		ids: string[];
+		channel_id: string;
+		guild_id?: string;
+	};
+}
+
+export interface MessageReactionAddEvent extends Event {
+	event: "MESSAGE_REACTION_ADD";
+	data: {
+		user_id: string;
+		channel_id: string;
+		message_id: string;
+		guild_id?: string;
+		member?: PublicMember;
+		emoji: PartialEmoji;
+	};
+}
+
+export interface MessageReactionRemoveEvent extends Event {
+	event: "MESSAGE_REACTION_REMOVE";
+	data: {
+		user_id: string;
+		channel_id: string;
+		message_id: string;
+		guild_id?: string;
+		emoji: PartialEmoji;
+	};
+}
+
+export interface MessageReactionRemoveAllEvent extends Event {
+	event: "MESSAGE_REACTION_REMOVE_ALL";
+	data: {
+		channel_id: string;
+		message_id: string;
+		guild_id?: string;
+	};
+}
+
+export interface MessageReactionRemoveEmojiEvent extends Event {
+	event: "MESSAGE_REACTION_REMOVE_EMOJI";
+	data: {
+		channel_id: string;
+		message_id: string;
+		guild_id?: string;
+		emoji: PartialEmoji;
+	};
+}
+
+export interface PresenceUpdateEvent extends Event {
+	event: "PRESENCE_UPDATE";
+	data: Presence;
+}
+
+export interface TypingStartEvent extends Event {
+	event: "TYPING_START";
+	data: {
+		channel_id: string;
+		user_id: string;
+		timestamp: number;
+		guild_id?: string;
+		member?: PublicMember;
+	};
+}
+
+export interface UserUpdateEvent extends Event {
+	event: "USER_UPDATE";
+	data: User;
+}
+
+export interface VoiceStateUpdateEvent extends Event {
+	event: "VOICE_STATE_UPDATE";
+	data: VoiceState & {
+		member: PublicMember;
+	};
+}
+
+export interface VoiceServerUpdateEvent extends Event {
+	event: "VOICE_SERVER_UPDATE";
+	data: {
+		token: string;
+		guild_id: string;
+		endpoint: string;
+	};
+}
+
+export interface WebhooksUpdateEvent extends Event {
+	event: "WEBHOOKS_UPDATE";
+	data: {
+		guild_id: string;
+		channel_id: string;
+	};
+}
+
+export type ApplicationCommandPayload = ApplicationCommand & {
+	guild_id: string;
+};
+
+export interface ApplicationCommandCreateEvent extends Event {
+	event: "APPLICATION_COMMAND_CREATE";
+	data: ApplicationCommandPayload;
+}
+
+export interface ApplicationCommandUpdateEvent extends Event {
+	event: "APPLICATION_COMMAND_UPDATE";
+	data: ApplicationCommandPayload;
+}
+
+export interface ApplicationCommandDeleteEvent extends Event {
+	event: "APPLICATION_COMMAND_DELETE";
+	data: ApplicationCommandPayload;
+}
+
+export interface InteractionCreateEvent extends Event {
+	event: "INTERACTION_CREATE";
+	data: Interaction;
+}
+
+export interface MessageAckEvent extends Event {
+	event: "MESSAGE_ACK";
+	data: {
+		channel_id: string;
+		message_id: string;
+		version?: number;
+		manual?: boolean;
+		mention_count?: number;
+	};
+}
+
+export interface RelationshipAddEvent extends Event {
+	event: "RELATIONSHIP_ADD";
+	data: PublicRelationship & {
+		should_notify?: boolean;
+		user: PublicUser;
+	};
+}
+
+export interface RelationshipRemoveEvent extends Event {
+	event: "RELATIONSHIP_REMOVE";
+	data: Omit<PublicRelationship, "nickname">;
+}
+
+export interface SessionsReplace extends Event {
+	event: "SESSIONS_REPLACE";
+	data: {
+		activities: Activity[];
+		client_info: {
+			version: number;
+			os: string;
+			client: string;
+		};
+		status: Status;
+	}[];
+}
+
+export interface GuildMemberListUpdate extends Event {
+	event: "GUILD_MEMBER_LIST_UPDATE";
+	data: {
+		groups: { id: string; count: number }[];
+		guild_id: string;
+		id: string;
+		member_count: number;
+		online_count: number;
+		ops: {
+			index: number;
+			item: {
+				member?: PublicMember & { presence: Presence };
+				group?: { id: string; count: number }[];
+			};
+		}[];
+	};
+}
+
+export type EventData =
+	| InvalidatedEvent
+	| ReadyEvent
+	| ChannelCreateEvent
+	| ChannelUpdateEvent
+	| ChannelDeleteEvent
+	| ChannelPinsUpdateEvent
+	| ChannelRecipientAddEvent
+	| ChannelRecipientRemoveEvent
+	| GuildCreateEvent
+	| GuildUpdateEvent
+	| GuildDeleteEvent
+	| GuildBanAddEvent
+	| GuildBanRemoveEvent
+	| GuildEmojisUpdateEvent
+	| GuildIntegrationUpdateEvent
+	| GuildMemberAddEvent
+	| GuildMemberRemoveEvent
+	| GuildMemberUpdateEvent
+	| GuildMembersChunkEvent
+	| GuildMemberListUpdate
+	| GuildRoleCreateEvent
+	| GuildRoleUpdateEvent
+	| GuildRoleDeleteEvent
+	| InviteCreateEvent
+	| InviteDeleteEvent
+	| MessageCreateEvent
+	| MessageUpdateEvent
+	| MessageDeleteEvent
+	| MessageDeleteBulkEvent
+	| MessageReactionAddEvent
+	| MessageReactionRemoveEvent
+	| MessageReactionRemoveAllEvent
+	| MessageReactionRemoveEmojiEvent
+	| PresenceUpdateEvent
+	| TypingStartEvent
+	| UserUpdateEvent
+	| VoiceStateUpdateEvent
+	| VoiceServerUpdateEvent
+	| WebhooksUpdateEvent
+	| ApplicationCommandCreateEvent
+	| ApplicationCommandUpdateEvent
+	| ApplicationCommandDeleteEvent
+	| InteractionCreateEvent
+	| MessageAckEvent
+	| RelationshipAddEvent
+	| RelationshipRemoveEvent;
+
+// located in collection events
+
+export enum EVENTEnum {
+	Ready = "READY",
+	ChannelCreate = "CHANNEL_CREATE",
+	ChannelUpdate = "CHANNEL_UPDATE",
+	ChannelDelete = "CHANNEL_DELETE",
+	ChannelPinsUpdate = "CHANNEL_PINS_UPDATE",
+	ChannelRecipientAdd = "CHANNEL_RECIPIENT_ADD",
+	ChannelRecipientRemove = "CHANNEL_RECIPIENT_REMOVE",
+	GuildCreate = "GUILD_CREATE",
+	GuildUpdate = "GUILD_UPDATE",
+	GuildDelete = "GUILD_DELETE",
+	GuildBanAdd = "GUILD_BAN_ADD",
+	GuildBanRemove = "GUILD_BAN_REMOVE",
+	GuildEmojUpdate = "GUILD_EMOJI_UPDATE",
+	GuildIntegrationsUpdate = "GUILD_INTEGRATIONS_UPDATE",
+	GuildMemberAdd = "GUILD_MEMBER_ADD",
+	GuildMemberRempve = "GUILD_MEMBER_REMOVE",
+	GuildMemberUpdate = "GUILD_MEMBER_UPDATE",
+	GuildMemberSpeaking = "GUILD_MEMBER_SPEAKING",
+	GuildMembersChunk = "GUILD_MEMBERS_CHUNK",
+	GuildMemberListUpdate = "GUILD_MEMBER_LIST_UPDATE",
+	GuildRoleCreate = "GUILD_ROLE_CREATE",
+	GuildRoleDelete = "GUILD_ROLE_DELETE",
+	GuildRoleUpdate = "GUILD_ROLE_UPDATE",
+	InviteCreate = "INVITE_CREATE",
+	InviteDelete = "INVITE_DELETE",
+	MessageCreate = "MESSAGE_CREATE",
+	MessageUpdate = "MESSAGE_UPDATE",
+	MessageDelete = "MESSAGE_DELETE",
+	MessageDeleteBulk = "MESSAGE_DELETE_BULK",
+	MessageReactionAdd = "MESSAGE_REACTION_ADD",
+	MessageReactionRemove = "MESSAGE_REACTION_REMOVE",
+	MessageReactionRemoveAll = "MESSAGE_REACTION_REMOVE_ALL",
+	MessageReactionRemoveEmoji = "MESSAGE_REACTION_REMOVE_EMOJI",
+	PresenceUpdate = "PRESENCE_UPDATE",
+	TypingStart = "TYPING_START",
+	UserUpdate = "USER_UPDATE",
+	WebhooksUpdate = "WEBHOOKS_UPDATE",
+	InteractionCreate = "INTERACTION_CREATE",
+	VoiceStateUpdate = "VOICE_STATE_UPDATE",
+	VoiceServerUpdate = "VOICE_SERVER_UPDATE",
+	ApplicationCommandCreate = "APPLICATION_COMMAND_CREATE",
+	ApplicationCommandUpdate = "APPLICATION_COMMAND_UPDATE",
+	ApplicationCommandDelete = "APPLICATION_COMMAND_DELETE",
+	SessionsReplace = "SESSIONS_REPLACE"
+}
+
+export type EVENT =
+	| "READY"
+	| "CHANNEL_CREATE"
+	| "CHANNEL_UPDATE"
+	| "CHANNEL_DELETE"
+	| "CHANNEL_PINS_UPDATE"
+	| "CHANNEL_RECIPIENT_ADD"
+	| "CHANNEL_RECIPIENT_REMOVE"
+	| "GUILD_CREATE"
+	| "GUILD_UPDATE"
+	| "GUILD_DELETE"
+	| "GUILD_BAN_ADD"
+	| "GUILD_BAN_REMOVE"
+	| "GUILD_EMOJIS_UPDATE"
+	| "GUILD_STICKERS_UPDATE"
+	| "GUILD_INTEGRATIONS_UPDATE"
+	| "GUILD_MEMBER_ADD"
+	| "GUILD_MEMBER_REMOVE"
+	| "GUILD_MEMBER_UPDATE"
+	| "GUILD_MEMBER_SPEAKING"
+	| "GUILD_MEMBERS_CHUNK"
+	| "GUILD_MEMBER_LIST_UPDATE"
+	| "GUILD_ROLE_CREATE"
+	| "GUILD_ROLE_DELETE"
+	| "GUILD_ROLE_UPDATE"
+	| "INVITE_CREATE"
+	| "INVITE_DELETE"
+	| "MESSAGE_CREATE"
+	| "MESSAGE_UPDATE"
+	| "MESSAGE_DELETE"
+	| "MESSAGE_DELETE_BULK"
+	| "MESSAGE_REACTION_ADD"
+	// TODO: add a new event: bulk add reaction:
+	// | "MESSAGE_REACTION_BULK_ADD"
+	| "MESSAGE_REACTION_REMOVE"
+	| "MESSAGE_REACTION_REMOVE_ALL"
+	| "MESSAGE_REACTION_REMOVE_EMOJI"
+	| "PRESENCE_UPDATE"
+	| "TYPING_START"
+	| "USER_UPDATE"
+	| "USER_NOTE_UPDATE"
+	| "WEBHOOKS_UPDATE"
+	| "INTERACTION_CREATE"
+	| "VOICE_STATE_UPDATE"
+	| "VOICE_SERVER_UPDATE"
+	| "APPLICATION_COMMAND_CREATE"
+	| "APPLICATION_COMMAND_UPDATE"
+	| "APPLICATION_COMMAND_DELETE"
+	| "MESSAGE_ACK"
+	| "RELATIONSHIP_ADD"
+	| "RELATIONSHIP_REMOVE"
+	| "SESSIONS_REPLACE"
+	| CUSTOMEVENTS;
+
+export type CUSTOMEVENTS = "INVALIDATED" | "RATELIMIT";
diff --git a/src/util/interfaces/Interaction.ts b/src/util/interfaces/Interaction.ts
new file mode 100644
index 00000000..c53a1ed4
--- /dev/null
+++ b/src/util/interfaces/Interaction.ts
@@ -0,0 +1,34 @@
+import { AllowedMentions, Embed } from "../entities/Message";
+
+export interface Interaction {
+	id: string;
+	type: InteractionType;
+	data?: {};
+	guild_id: string;
+	channel_id: string;
+	member_id: string;
+	token: string;
+	version: number;
+}
+
+export enum InteractionType {
+	SelfCommand = 0,
+	Ping = 1,
+	ApplicationCommand = 2
+}
+
+export enum InteractionResponseType {
+	SelfCommandResponse = 0,
+	Pong = 1,
+	Acknowledge = 2,
+	ChannelMessage = 3,
+	ChannelMessageWithSource = 4,
+	AcknowledgeWithSource = 5
+}
+
+export interface InteractionApplicationCommandCallbackData {
+	tts?: boolean;
+	content: string;
+	embeds?: Embed[];
+	allowed_mentions?: AllowedMentions;
+}
diff --git a/src/util/interfaces/Presence.ts b/src/util/interfaces/Presence.ts
new file mode 100644
index 00000000..5b66139e
--- /dev/null
+++ b/src/util/interfaces/Presence.ts
@@ -0,0 +1,12 @@
+import { PublicUser } from "../entities/User";
+import { Activity } from "./Activity";
+import { ClientStatus, Status } from "./Status";
+
+export interface Presence {
+	user: PublicUser;
+	guild_id?: string;
+	status: Status;
+	activities: Activity[];
+	client_status: ClientStatus;
+	// TODO: game
+}
diff --git a/src/util/interfaces/Status.ts b/src/util/interfaces/Status.ts
new file mode 100644
index 00000000..5d2e1bba
--- /dev/null
+++ b/src/util/interfaces/Status.ts
@@ -0,0 +1,7 @@
+export type Status = "idle" | "dnd" | "online" | "offline" | "invisible";
+
+export interface ClientStatus {
+	desktop?: string; // e.g. Windows/Linux/Mac
+	mobile?: string; // e.g. iOS/Android
+	web?: string; // e.g. browser, bot account
+}
diff --git a/src/util/interfaces/index.ts b/src/util/interfaces/index.ts
new file mode 100644
index 00000000..a074030e
--- /dev/null
+++ b/src/util/interfaces/index.ts
@@ -0,0 +1,5 @@
+export * from "./Activity";
+export * from "./Event";
+export * from "./Interaction";
+export * from "./Presence";
+export * from "./Status";
diff --git a/src/util/migrations/mariadb/1659901151025-initial.ts b/src/util/migrations/mariadb/1659901151025-initial.ts
new file mode 100644
index 00000000..1e1f64db
--- /dev/null
+++ b/src/util/migrations/mariadb/1659901151025-initial.ts
@@ -0,0 +1,1218 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class initial1659901151025 implements MigrationInterface {
+	name = "initial1659901151025";
+
+	public async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            CREATE TABLE \`config\` (
+                \`key\` varchar(255) NOT NULL,
+                \`value\` text NULL,
+                PRIMARY KEY (\`key\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`relationships\` (
+                \`id\` varchar(255) NOT NULL,
+                \`from_id\` varchar(255) NOT NULL,
+                \`to_id\` varchar(255) NOT NULL,
+                \`nickname\` varchar(255) NULL,
+                \`type\` int NOT NULL,
+                UNIQUE INDEX \`IDX_a0b2ff0a598df0b0d055934a17\` (\`from_id\`, \`to_id\`),
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`connected_accounts\` (
+                \`id\` varchar(255) NOT NULL,
+                \`user_id\` varchar(255) NULL,
+                \`access_token\` varchar(255) NOT NULL,
+                \`friend_sync\` tinyint NOT NULL,
+                \`name\` varchar(255) NOT NULL,
+                \`revoked\` tinyint NOT NULL,
+                \`show_activity\` tinyint NOT NULL,
+                \`type\` varchar(255) NOT NULL,
+                \`verified\` tinyint NOT NULL,
+                \`visibility\` int NOT NULL,
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`users\` (
+                \`id\` varchar(255) NOT NULL,
+                \`username\` varchar(255) NOT NULL,
+                \`discriminator\` varchar(255) NOT NULL,
+                \`avatar\` varchar(255) NULL,
+                \`accent_color\` int NULL,
+                \`banner\` varchar(255) NULL,
+                \`phone\` varchar(255) NULL,
+                \`desktop\` tinyint NOT NULL,
+                \`mobile\` tinyint NOT NULL,
+                \`premium\` tinyint NOT NULL,
+                \`premium_type\` int NOT NULL,
+                \`bot\` tinyint NOT NULL,
+                \`bio\` varchar(255) NOT NULL,
+                \`system\` tinyint NOT NULL,
+                \`nsfw_allowed\` tinyint NOT NULL,
+                \`mfa_enabled\` tinyint NOT NULL,
+                \`totp_secret\` varchar(255) NULL,
+                \`totp_last_ticket\` varchar(255) NULL,
+                \`created_at\` datetime NOT NULL,
+                \`premium_since\` datetime NULL,
+                \`verified\` tinyint NOT NULL,
+                \`disabled\` tinyint NOT NULL,
+                \`deleted\` tinyint NOT NULL,
+                \`email\` varchar(255) NULL,
+                \`flags\` varchar(255) NOT NULL,
+                \`public_flags\` int NOT NULL,
+                \`rights\` bigint NOT NULL,
+                \`data\` text NOT NULL,
+                \`fingerprints\` text NOT NULL,
+                \`settings\` text NOT NULL,
+                \`extended_settings\` text NOT NULL,
+                \`notes\` text NOT NULL,
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`backup_codes\` (
+                \`id\` varchar(255) NOT NULL,
+                \`code\` varchar(255) NOT NULL,
+                \`consumed\` tinyint NOT NULL,
+                \`expired\` tinyint NOT NULL,
+                \`user_id\` varchar(255) NULL,
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`bans\` (
+                \`id\` varchar(255) NOT NULL,
+                \`user_id\` varchar(255) NULL,
+                \`guild_id\` varchar(255) NULL,
+                \`executor_id\` varchar(255) NULL,
+                \`ip\` varchar(255) NOT NULL,
+                \`reason\` varchar(255) NULL,
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`recipients\` (
+                \`id\` varchar(255) NOT NULL,
+                \`channel_id\` varchar(255) NOT NULL,
+                \`user_id\` varchar(255) NOT NULL,
+                \`closed\` tinyint NOT NULL DEFAULT 0,
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`roles\` (
+                \`id\` varchar(255) NOT NULL,
+                \`guild_id\` varchar(255) NULL,
+                \`color\` int NOT NULL,
+                \`hoist\` tinyint NOT NULL,
+                \`managed\` tinyint NOT NULL,
+                \`mentionable\` tinyint NOT NULL,
+                \`name\` varchar(255) NOT NULL,
+                \`permissions\` varchar(255) NOT NULL,
+                \`position\` int NOT NULL,
+                \`icon\` varchar(255) NULL,
+                \`unicode_emoji\` varchar(255) NULL,
+                \`tags\` text NULL,
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`members\` (
+                \`index\` int NOT NULL AUTO_INCREMENT,
+                \`id\` varchar(255) NOT NULL,
+                \`guild_id\` varchar(255) NOT NULL,
+                \`nick\` varchar(255) NULL,
+                \`joined_at\` datetime NOT NULL,
+                \`premium_since\` bigint NULL,
+                \`deaf\` tinyint NOT NULL,
+                \`mute\` tinyint NOT NULL,
+                \`pending\` tinyint NOT NULL,
+                \`settings\` text NOT NULL,
+                \`last_message_id\` varchar(255) NULL,
+                \`joined_by\` varchar(255) NULL,
+                UNIQUE INDEX \`IDX_bb2bf9386ac443afbbbf9f12d3\` (\`id\`, \`guild_id\`),
+                PRIMARY KEY (\`index\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`webhooks\` (
+                \`id\` varchar(255) NOT NULL,
+                \`type\` int NOT NULL,
+                \`name\` varchar(255) NULL,
+                \`avatar\` varchar(255) NULL,
+                \`token\` varchar(255) NULL,
+                \`guild_id\` varchar(255) NULL,
+                \`channel_id\` varchar(255) NULL,
+                \`application_id\` varchar(255) NULL,
+                \`user_id\` varchar(255) NULL,
+                \`source_guild_id\` varchar(255) NULL,
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`stickers\` (
+                \`id\` varchar(255) NOT NULL,
+                \`name\` varchar(255) NOT NULL,
+                \`description\` varchar(255) NULL,
+                \`available\` tinyint NULL,
+                \`tags\` varchar(255) NULL,
+                \`pack_id\` varchar(255) NULL,
+                \`guild_id\` varchar(255) NULL,
+                \`user_id\` varchar(255) NULL,
+                \`type\` int NOT NULL,
+                \`format_type\` int NOT NULL,
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`attachments\` (
+                \`id\` varchar(255) NOT NULL,
+                \`filename\` varchar(255) NOT NULL,
+                \`size\` int NOT NULL,
+                \`url\` varchar(255) NOT NULL,
+                \`proxy_url\` varchar(255) NOT NULL,
+                \`height\` int NULL,
+                \`width\` int NULL,
+                \`content_type\` varchar(255) NULL,
+                \`message_id\` varchar(255) NULL,
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`messages\` (
+                \`id\` varchar(255) NOT NULL,
+                \`channel_id\` varchar(255) NULL,
+                \`guild_id\` varchar(255) NULL,
+                \`author_id\` varchar(255) NULL,
+                \`member_id\` varchar(255) NULL,
+                \`webhook_id\` varchar(255) NULL,
+                \`application_id\` varchar(255) NULL,
+                \`content\` varchar(255) NULL,
+                \`timestamp\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
+                \`edited_timestamp\` datetime NULL,
+                \`tts\` tinyint NULL,
+                \`mention_everyone\` tinyint NULL,
+                \`embeds\` text NOT NULL,
+                \`reactions\` text NOT NULL,
+                \`nonce\` text NULL,
+                \`pinned\` tinyint NULL,
+                \`type\` int NOT NULL,
+                \`activity\` text NULL,
+                \`flags\` varchar(255) NULL,
+                \`message_reference\` text NULL,
+                \`interaction\` text NULL,
+                \`components\` text NULL,
+                \`message_reference_id\` varchar(255) NULL,
+                INDEX \`IDX_86b9109b155eb70c0a2ca3b4b6\` (\`channel_id\`),
+                INDEX \`IDX_05535bc695e9f7ee104616459d\` (\`author_id\`),
+                UNIQUE INDEX \`IDX_3ed7a60fb7dbe04e1ba9332a8b\` (\`channel_id\`, \`id\`),
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`read_states\` (
+                \`id\` varchar(255) NOT NULL,
+                \`channel_id\` varchar(255) NOT NULL,
+                \`user_id\` varchar(255) NOT NULL,
+                \`last_message_id\` varchar(255) NULL,
+                \`public_ack\` varchar(255) NULL,
+                \`notifications_cursor\` varchar(255) NULL,
+                \`last_pin_timestamp\` datetime NULL,
+                \`mention_count\` int NULL,
+                UNIQUE INDEX \`IDX_0abf8b443321bd3cf7f81ee17a\` (\`channel_id\`, \`user_id\`),
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`invites\` (
+                \`code\` varchar(255) NOT NULL,
+                \`temporary\` tinyint NOT NULL,
+                \`uses\` int NOT NULL,
+                \`max_uses\` int NOT NULL,
+                \`max_age\` int NOT NULL,
+                \`created_at\` datetime NOT NULL,
+                \`expires_at\` datetime NOT NULL,
+                \`guild_id\` varchar(255) NULL,
+                \`channel_id\` varchar(255) NULL,
+                \`inviter_id\` varchar(255) NULL,
+                \`target_user_id\` varchar(255) NULL,
+                \`target_user_type\` int NULL,
+                \`vanity_url\` tinyint NULL,
+                PRIMARY KEY (\`code\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`voice_states\` (
+                \`id\` varchar(255) NOT NULL,
+                \`guild_id\` varchar(255) NULL,
+                \`channel_id\` varchar(255) NULL,
+                \`user_id\` varchar(255) NULL,
+                \`session_id\` varchar(255) NOT NULL,
+                \`token\` varchar(255) NULL,
+                \`deaf\` tinyint NOT NULL,
+                \`mute\` tinyint NOT NULL,
+                \`self_deaf\` tinyint NOT NULL,
+                \`self_mute\` tinyint NOT NULL,
+                \`self_stream\` tinyint NULL,
+                \`self_video\` tinyint NOT NULL,
+                \`suppress\` tinyint NOT NULL,
+                \`request_to_speak_timestamp\` datetime NULL,
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`channels\` (
+                \`id\` varchar(255) NOT NULL,
+                \`created_at\` datetime NOT NULL,
+                \`name\` varchar(255) NULL,
+                \`icon\` text NULL,
+                \`type\` int NOT NULL,
+                \`last_message_id\` varchar(255) NULL,
+                \`guild_id\` varchar(255) NULL,
+                \`parent_id\` varchar(255) NULL,
+                \`owner_id\` varchar(255) NULL,
+                \`last_pin_timestamp\` int NULL,
+                \`default_auto_archive_duration\` int NULL,
+                \`position\` int NULL,
+                \`permission_overwrites\` text NULL,
+                \`video_quality_mode\` int NULL,
+                \`bitrate\` int NULL,
+                \`user_limit\` int NULL,
+                \`nsfw\` tinyint NULL,
+                \`rate_limit_per_user\` int NULL,
+                \`topic\` varchar(255) NULL,
+                \`retention_policy_id\` varchar(255) NULL,
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`emojis\` (
+                \`id\` varchar(255) NOT NULL,
+                \`animated\` tinyint NOT NULL,
+                \`available\` tinyint NOT NULL,
+                \`guild_id\` varchar(255) NOT NULL,
+                \`user_id\` varchar(255) NULL,
+                \`managed\` tinyint NOT NULL,
+                \`name\` varchar(255) NOT NULL,
+                \`require_colons\` tinyint NOT NULL,
+                \`roles\` text NOT NULL,
+                \`groups\` text NULL,
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`templates\` (
+                \`id\` varchar(255) NOT NULL,
+                \`code\` varchar(255) NOT NULL,
+                \`name\` varchar(255) NOT NULL,
+                \`description\` varchar(255) NULL,
+                \`usage_count\` int NULL,
+                \`creator_id\` varchar(255) NULL,
+                \`created_at\` datetime NOT NULL,
+                \`updated_at\` datetime NOT NULL,
+                \`source_guild_id\` varchar(255) NULL,
+                \`serialized_source_guild\` text NOT NULL,
+                UNIQUE INDEX \`IDX_be38737bf339baf63b1daeffb5\` (\`code\`),
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`guilds\` (
+                \`id\` varchar(255) NOT NULL,
+                \`afk_channel_id\` varchar(255) NULL,
+                \`afk_timeout\` int NULL,
+                \`banner\` varchar(255) NULL,
+                \`default_message_notifications\` int NULL,
+                \`description\` varchar(255) NULL,
+                \`discovery_splash\` varchar(255) NULL,
+                \`explicit_content_filter\` int NULL,
+                \`features\` text NOT NULL,
+                \`primary_category_id\` int NULL,
+                \`icon\` varchar(255) NULL,
+                \`large\` tinyint NULL,
+                \`max_members\` int NULL,
+                \`max_presences\` int NULL,
+                \`max_video_channel_users\` int NULL,
+                \`member_count\` int NULL,
+                \`presence_count\` int NULL,
+                \`template_id\` varchar(255) NULL,
+                \`mfa_level\` int NULL,
+                \`name\` varchar(255) NOT NULL,
+                \`owner_id\` varchar(255) NULL,
+                \`preferred_locale\` varchar(255) NULL,
+                \`premium_subscription_count\` int NULL,
+                \`premium_tier\` int NULL,
+                \`public_updates_channel_id\` varchar(255) NULL,
+                \`rules_channel_id\` varchar(255) NULL,
+                \`region\` varchar(255) NULL,
+                \`splash\` varchar(255) NULL,
+                \`system_channel_id\` varchar(255) NULL,
+                \`system_channel_flags\` int NULL,
+                \`unavailable\` tinyint NULL,
+                \`verification_level\` int NULL,
+                \`welcome_screen\` text NOT NULL,
+                \`widget_channel_id\` varchar(255) NULL,
+                \`widget_enabled\` tinyint NULL,
+                \`nsfw_level\` int NULL,
+                \`nsfw\` tinyint NULL,
+                \`parent\` varchar(255) NULL,
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`team_members\` (
+                \`id\` varchar(255) NOT NULL,
+                \`membership_state\` int NOT NULL,
+                \`permissions\` text NOT NULL,
+                \`team_id\` varchar(255) NULL,
+                \`user_id\` varchar(255) NULL,
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`teams\` (
+                \`id\` varchar(255) NOT NULL,
+                \`icon\` varchar(255) NULL,
+                \`name\` varchar(255) NOT NULL,
+                \`owner_user_id\` varchar(255) NULL,
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`applications\` (
+                \`id\` varchar(255) NOT NULL,
+                \`name\` varchar(255) NOT NULL,
+                \`icon\` varchar(255) NULL,
+                \`description\` varchar(255) NOT NULL,
+                \`rpc_origins\` text NULL,
+                \`bot_public\` tinyint NOT NULL,
+                \`bot_require_code_grant\` tinyint NOT NULL,
+                \`terms_of_service_url\` varchar(255) NULL,
+                \`privacy_policy_url\` varchar(255) NULL,
+                \`summary\` varchar(255) NULL,
+                \`verify_key\` varchar(255) NOT NULL,
+                \`primary_sku_id\` varchar(255) NULL,
+                \`slug\` varchar(255) NULL,
+                \`cover_image\` varchar(255) NULL,
+                \`flags\` varchar(255) NOT NULL,
+                \`owner_id\` varchar(255) NULL,
+                \`team_id\` varchar(255) NULL,
+                \`guild_id\` varchar(255) NULL,
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`audit_logs\` (
+                \`id\` varchar(255) NOT NULL,
+                \`user_id\` varchar(255) NULL,
+                \`action_type\` int NOT NULL,
+                \`options\` text NULL,
+                \`changes\` text NOT NULL,
+                \`reason\` varchar(255) NULL,
+                \`target_id\` varchar(255) NULL,
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`categories\` (
+                \`id\` int NOT NULL,
+                \`name\` varchar(255) NULL,
+                \`localizations\` text NOT NULL,
+                \`is_primary\` tinyint NULL,
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`rate_limits\` (
+                \`id\` varchar(255) NOT NULL,
+                \`executor_id\` varchar(255) NOT NULL,
+                \`hits\` int NOT NULL,
+                \`blocked\` tinyint NOT NULL,
+                \`expires_at\` datetime NOT NULL,
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`sessions\` (
+                \`id\` varchar(255) NOT NULL,
+                \`user_id\` varchar(255) NULL,
+                \`session_id\` varchar(255) NOT NULL,
+                \`activities\` text NULL,
+                \`client_info\` text NOT NULL,
+                \`status\` varchar(255) NOT NULL,
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`sticker_packs\` (
+                \`id\` varchar(255) NOT NULL,
+                \`name\` varchar(255) NOT NULL,
+                \`description\` varchar(255) NULL,
+                \`banner_asset_id\` varchar(255) NULL,
+                \`cover_sticker_id\` varchar(255) NULL,
+                \`coverStickerId\` varchar(255) NULL,
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`client_release\` (
+                \`id\` varchar(255) NOT NULL,
+                \`name\` varchar(255) NOT NULL,
+                \`pub_date\` varchar(255) NOT NULL,
+                \`url\` varchar(255) NOT NULL,
+                \`deb_url\` varchar(255) NOT NULL,
+                \`osx_url\` varchar(255) NOT NULL,
+                \`win_url\` varchar(255) NOT NULL,
+                \`notes\` varchar(255) NULL,
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`notes\` (
+                \`id\` varchar(255) NOT NULL,
+                \`content\` varchar(255) NOT NULL,
+                \`owner_id\` varchar(255) NULL,
+                \`target_id\` varchar(255) NULL,
+                UNIQUE INDEX \`IDX_74e6689b9568cc965b8bfc9150\` (\`owner_id\`, \`target_id\`),
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`member_roles\` (
+                \`index\` int NOT NULL,
+                \`role_id\` varchar(255) NOT NULL,
+                INDEX \`IDX_5d7ddc8a5f9c167f548625e772\` (\`index\`),
+                INDEX \`IDX_e9080e7a7997a0170026d5139c\` (\`role_id\`),
+                PRIMARY KEY (\`index\`, \`role_id\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`message_user_mentions\` (
+                \`messagesId\` varchar(255) NOT NULL,
+                \`usersId\` varchar(255) NOT NULL,
+                INDEX \`IDX_a343387fc560ef378760681c23\` (\`messagesId\`),
+                INDEX \`IDX_b831eb18ceebd28976239b1e2f\` (\`usersId\`),
+                PRIMARY KEY (\`messagesId\`, \`usersId\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`message_role_mentions\` (
+                \`messagesId\` varchar(255) NOT NULL,
+                \`rolesId\` varchar(255) NOT NULL,
+                INDEX \`IDX_a8242cf535337a490b0feaea0b\` (\`messagesId\`),
+                INDEX \`IDX_29d63eb1a458200851bc37d074\` (\`rolesId\`),
+                PRIMARY KEY (\`messagesId\`, \`rolesId\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`message_channel_mentions\` (
+                \`messagesId\` varchar(255) NOT NULL,
+                \`channelsId\` varchar(255) NOT NULL,
+                INDEX \`IDX_2a27102ecd1d81b4582a436092\` (\`messagesId\`),
+                INDEX \`IDX_bdb8c09e1464cabf62105bf4b9\` (\`channelsId\`),
+                PRIMARY KEY (\`messagesId\`, \`channelsId\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`message_stickers\` (
+                \`messagesId\` varchar(255) NOT NULL,
+                \`stickersId\` varchar(255) NOT NULL,
+                INDEX \`IDX_40bb6f23e7cc133292e92829d2\` (\`messagesId\`),
+                INDEX \`IDX_e22a70819d07659c7a71c112a1\` (\`stickersId\`),
+                PRIMARY KEY (\`messagesId\`, \`stickersId\`)
+            ) ENGINE = InnoDB
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`relationships\`
+            ADD CONSTRAINT \`FK_9af4194bab1250b1c584ae4f1d7\` FOREIGN KEY (\`from_id\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`relationships\`
+            ADD CONSTRAINT \`FK_9c7f6b98a9843b76dce1b0c878b\` FOREIGN KEY (\`to_id\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`connected_accounts\`
+            ADD CONSTRAINT \`FK_f47244225a6a1eac04a3463dd90\` FOREIGN KEY (\`user_id\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`backup_codes\`
+            ADD CONSTRAINT \`FK_70066ea80d2f4b871beda32633b\` FOREIGN KEY (\`user_id\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`bans\`
+            ADD CONSTRAINT \`FK_5999e8e449f80a236ff72023559\` FOREIGN KEY (\`user_id\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`bans\`
+            ADD CONSTRAINT \`FK_9d3ab7dd180ebdd245cdb66ecad\` FOREIGN KEY (\`guild_id\`) REFERENCES \`guilds\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`bans\`
+            ADD CONSTRAINT \`FK_07ad88c86d1f290d46748410d58\` FOREIGN KEY (\`executor_id\`) REFERENCES \`users\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`recipients\`
+            ADD CONSTRAINT \`FK_2f18ee1ba667f233ae86c0ea60e\` FOREIGN KEY (\`channel_id\`) REFERENCES \`channels\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`recipients\`
+            ADD CONSTRAINT \`FK_6157e8b6ba4e6e3089616481fe2\` FOREIGN KEY (\`user_id\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`roles\`
+            ADD CONSTRAINT \`FK_c32c1ab1c4dc7dcb0278c4b1b8b\` FOREIGN KEY (\`guild_id\`) REFERENCES \`guilds\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`members\`
+            ADD CONSTRAINT \`FK_28b53062261b996d9c99fa12404\` FOREIGN KEY (\`id\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`members\`
+            ADD CONSTRAINT \`FK_16aceddd5b89825b8ed6029ad1c\` FOREIGN KEY (\`guild_id\`) REFERENCES \`guilds\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`webhooks\`
+            ADD CONSTRAINT \`FK_487a7af59d189f744fe394368fc\` FOREIGN KEY (\`guild_id\`) REFERENCES \`guilds\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`webhooks\`
+            ADD CONSTRAINT \`FK_df528cf77e82f8032230e7e37d8\` FOREIGN KEY (\`channel_id\`) REFERENCES \`channels\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`webhooks\`
+            ADD CONSTRAINT \`FK_c3e5305461931763b56aa905f1c\` FOREIGN KEY (\`application_id\`) REFERENCES \`applications\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`webhooks\`
+            ADD CONSTRAINT \`FK_0d523f6f997c86e052c49b1455f\` FOREIGN KEY (\`user_id\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`webhooks\`
+            ADD CONSTRAINT \`FK_3a285f4f49c40e0706d3018bc9f\` FOREIGN KEY (\`source_guild_id\`) REFERENCES \`guilds\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`stickers\`
+            ADD CONSTRAINT \`FK_e7cfa5cefa6661b3fb8fda8ce69\` FOREIGN KEY (\`pack_id\`) REFERENCES \`sticker_packs\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`stickers\`
+            ADD CONSTRAINT \`FK_193d551d852aca5347ef5c9f205\` FOREIGN KEY (\`guild_id\`) REFERENCES \`guilds\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`stickers\`
+            ADD CONSTRAINT \`FK_8f4ee73f2bb2325ff980502e158\` FOREIGN KEY (\`user_id\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`attachments\`
+            ADD CONSTRAINT \`FK_623e10eec51ada466c5038979e3\` FOREIGN KEY (\`message_id\`) REFERENCES \`messages\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`messages\`
+            ADD CONSTRAINT \`FK_86b9109b155eb70c0a2ca3b4b6d\` FOREIGN KEY (\`channel_id\`) REFERENCES \`channels\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`messages\`
+            ADD CONSTRAINT \`FK_b193588441b085352a4c0109423\` FOREIGN KEY (\`guild_id\`) REFERENCES \`guilds\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`messages\`
+            ADD CONSTRAINT \`FK_05535bc695e9f7ee104616459d3\` FOREIGN KEY (\`author_id\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`messages\`
+            ADD CONSTRAINT \`FK_b0525304f2262b7014245351c76\` FOREIGN KEY (\`member_id\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`messages\`
+            ADD CONSTRAINT \`FK_f83c04bcf1df4e5c0e7a52ed348\` FOREIGN KEY (\`webhook_id\`) REFERENCES \`webhooks\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`messages\`
+            ADD CONSTRAINT \`FK_5d3ec1cb962de6488637fd779d6\` FOREIGN KEY (\`application_id\`) REFERENCES \`applications\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`messages\`
+            ADD CONSTRAINT \`FK_61a92bb65b302a76d9c1fcd3174\` FOREIGN KEY (\`message_reference_id\`) REFERENCES \`messages\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`read_states\`
+            ADD CONSTRAINT \`FK_40da2fca4e0eaf7a23b5bfc5d34\` FOREIGN KEY (\`channel_id\`) REFERENCES \`channels\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`read_states\`
+            ADD CONSTRAINT \`FK_195f92e4dd1254a4e348c043763\` FOREIGN KEY (\`user_id\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`invites\`
+            ADD CONSTRAINT \`FK_3f4939aa1461e8af57fea3fb05d\` FOREIGN KEY (\`guild_id\`) REFERENCES \`guilds\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`invites\`
+            ADD CONSTRAINT \`FK_6a15b051fe5050aa00a4b9ff0f6\` FOREIGN KEY (\`channel_id\`) REFERENCES \`channels\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`invites\`
+            ADD CONSTRAINT \`FK_15c35422032e0b22b4ada95f48f\` FOREIGN KEY (\`inviter_id\`) REFERENCES \`users\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`invites\`
+            ADD CONSTRAINT \`FK_11a0d394f8fc649c19ce5f16b59\` FOREIGN KEY (\`target_user_id\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`voice_states\`
+            ADD CONSTRAINT \`FK_03779ef216d4b0358470d9cb748\` FOREIGN KEY (\`guild_id\`) REFERENCES \`guilds\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`voice_states\`
+            ADD CONSTRAINT \`FK_9f8d389866b40b6657edd026dd4\` FOREIGN KEY (\`channel_id\`) REFERENCES \`channels\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`voice_states\`
+            ADD CONSTRAINT \`FK_5fe1d5f931a67e85039c640001b\` FOREIGN KEY (\`user_id\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`channels\`
+            ADD CONSTRAINT \`FK_c253dafe5f3a03ec00cd8fb4581\` FOREIGN KEY (\`guild_id\`) REFERENCES \`guilds\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`channels\`
+            ADD CONSTRAINT \`FK_3274522d14af40540b1a883fc80\` FOREIGN KEY (\`parent_id\`) REFERENCES \`channels\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`channels\`
+            ADD CONSTRAINT \`FK_3873ed438575cce703ecff4fc7b\` FOREIGN KEY (\`owner_id\`) REFERENCES \`users\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`emojis\`
+            ADD CONSTRAINT \`FK_4b988e0db89d94cebcf07f598cc\` FOREIGN KEY (\`guild_id\`) REFERENCES \`guilds\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`emojis\`
+            ADD CONSTRAINT \`FK_fa7ddd5f9a214e28ce596548421\` FOREIGN KEY (\`user_id\`) REFERENCES \`users\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`templates\`
+            ADD CONSTRAINT \`FK_d7374b7f8f5fbfdececa4fb62e1\` FOREIGN KEY (\`creator_id\`) REFERENCES \`users\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`templates\`
+            ADD CONSTRAINT \`FK_445d00eaaea0e60a017a5ed0c11\` FOREIGN KEY (\`source_guild_id\`) REFERENCES \`guilds\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`guilds\`
+            ADD CONSTRAINT \`FK_f591a66b8019d87b0fe6c12dad6\` FOREIGN KEY (\`afk_channel_id\`) REFERENCES \`channels\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`guilds\`
+            ADD CONSTRAINT \`FK_e2a2f873a64a5cf62526de42325\` FOREIGN KEY (\`template_id\`) REFERENCES \`templates\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`guilds\`
+            ADD CONSTRAINT \`FK_fc1a451727e3643ca572a3bb394\` FOREIGN KEY (\`owner_id\`) REFERENCES \`users\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`guilds\`
+            ADD CONSTRAINT \`FK_8d450b016dc8bec35f36729e4b0\` FOREIGN KEY (\`public_updates_channel_id\`) REFERENCES \`channels\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`guilds\`
+            ADD CONSTRAINT \`FK_95828668aa333460582e0ca6396\` FOREIGN KEY (\`rules_channel_id\`) REFERENCES \`channels\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`guilds\`
+            ADD CONSTRAINT \`FK_cfc3d3ad260f8121c95b31a1fce\` FOREIGN KEY (\`system_channel_id\`) REFERENCES \`channels\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`guilds\`
+            ADD CONSTRAINT \`FK_9d1d665379eefde7876a17afa99\` FOREIGN KEY (\`widget_channel_id\`) REFERENCES \`channels\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`team_members\`
+            ADD CONSTRAINT \`FK_fdad7d5768277e60c40e01cdcea\` FOREIGN KEY (\`team_id\`) REFERENCES \`teams\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`team_members\`
+            ADD CONSTRAINT \`FK_c2bf4967c8c2a6b845dadfbf3d4\` FOREIGN KEY (\`user_id\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`teams\`
+            ADD CONSTRAINT \`FK_13f00abf7cb6096c43ecaf8c108\` FOREIGN KEY (\`owner_user_id\`) REFERENCES \`users\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD CONSTRAINT \`FK_e57508958bf92b9d9d25231b5e8\` FOREIGN KEY (\`owner_id\`) REFERENCES \`users\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD CONSTRAINT \`FK_a36ed02953077f408d0f3ebc424\` FOREIGN KEY (\`team_id\`) REFERENCES \`teams\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD CONSTRAINT \`FK_e5bf78cdbbe9ba91062d74c5aba\` FOREIGN KEY (\`guild_id\`) REFERENCES \`guilds\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`audit_logs\`
+            ADD CONSTRAINT \`FK_3cd01cd3ae7aab010310d96ac8e\` FOREIGN KEY (\`target_id\`) REFERENCES \`users\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`audit_logs\`
+            ADD CONSTRAINT \`FK_bd2726fd31b35443f2245b93ba0\` FOREIGN KEY (\`user_id\`) REFERENCES \`users\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`sessions\`
+            ADD CONSTRAINT \`FK_085d540d9f418cfbdc7bd55bb19\` FOREIGN KEY (\`user_id\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`sticker_packs\`
+            ADD CONSTRAINT \`FK_448fafba4355ee1c837bbc865f1\` FOREIGN KEY (\`coverStickerId\`) REFERENCES \`stickers\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`notes\`
+            ADD CONSTRAINT \`FK_f9e103f8ae67cb1787063597925\` FOREIGN KEY (\`owner_id\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`notes\`
+            ADD CONSTRAINT \`FK_23e08e5b4481711d573e1abecdc\` FOREIGN KEY (\`target_id\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`member_roles\`
+            ADD CONSTRAINT \`FK_5d7ddc8a5f9c167f548625e772e\` FOREIGN KEY (\`index\`) REFERENCES \`members\`(\`index\`) ON DELETE CASCADE ON UPDATE CASCADE
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`member_roles\`
+            ADD CONSTRAINT \`FK_e9080e7a7997a0170026d5139c1\` FOREIGN KEY (\`role_id\`) REFERENCES \`roles\`(\`id\`) ON DELETE CASCADE ON UPDATE CASCADE
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`message_user_mentions\`
+            ADD CONSTRAINT \`FK_a343387fc560ef378760681c236\` FOREIGN KEY (\`messagesId\`) REFERENCES \`messages\`(\`id\`) ON DELETE CASCADE ON UPDATE CASCADE
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`message_user_mentions\`
+            ADD CONSTRAINT \`FK_b831eb18ceebd28976239b1e2f8\` FOREIGN KEY (\`usersId\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE ON UPDATE CASCADE
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`message_role_mentions\`
+            ADD CONSTRAINT \`FK_a8242cf535337a490b0feaea0b4\` FOREIGN KEY (\`messagesId\`) REFERENCES \`messages\`(\`id\`) ON DELETE CASCADE ON UPDATE CASCADE
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`message_role_mentions\`
+            ADD CONSTRAINT \`FK_29d63eb1a458200851bc37d074b\` FOREIGN KEY (\`rolesId\`) REFERENCES \`roles\`(\`id\`) ON DELETE CASCADE ON UPDATE CASCADE
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`message_channel_mentions\`
+            ADD CONSTRAINT \`FK_2a27102ecd1d81b4582a4360921\` FOREIGN KEY (\`messagesId\`) REFERENCES \`messages\`(\`id\`) ON DELETE CASCADE ON UPDATE CASCADE
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`message_channel_mentions\`
+            ADD CONSTRAINT \`FK_bdb8c09e1464cabf62105bf4b9d\` FOREIGN KEY (\`channelsId\`) REFERENCES \`channels\`(\`id\`) ON DELETE CASCADE ON UPDATE CASCADE
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`message_stickers\`
+            ADD CONSTRAINT \`FK_40bb6f23e7cc133292e92829d28\` FOREIGN KEY (\`messagesId\`) REFERENCES \`messages\`(\`id\`) ON DELETE CASCADE ON UPDATE CASCADE
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`message_stickers\`
+            ADD CONSTRAINT \`FK_e22a70819d07659c7a71c112a1f\` FOREIGN KEY (\`stickersId\`) REFERENCES \`stickers\`(\`id\`) ON DELETE CASCADE ON UPDATE CASCADE
+        `);
+		await queryRunner.query(`
+            CREATE TABLE \`query-result-cache\` (
+                \`id\` int NOT NULL AUTO_INCREMENT,
+                \`identifier\` varchar(255) NULL,
+                \`time\` bigint NOT NULL,
+                \`duration\` int NOT NULL,
+                \`query\` text NOT NULL,
+                \`result\` text NOT NULL,
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+	}
+
+	public async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            DROP TABLE \`query-result-cache\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`message_stickers\` DROP FOREIGN KEY \`FK_e22a70819d07659c7a71c112a1f\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`message_stickers\` DROP FOREIGN KEY \`FK_40bb6f23e7cc133292e92829d28\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`message_channel_mentions\` DROP FOREIGN KEY \`FK_bdb8c09e1464cabf62105bf4b9d\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`message_channel_mentions\` DROP FOREIGN KEY \`FK_2a27102ecd1d81b4582a4360921\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`message_role_mentions\` DROP FOREIGN KEY \`FK_29d63eb1a458200851bc37d074b\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`message_role_mentions\` DROP FOREIGN KEY \`FK_a8242cf535337a490b0feaea0b4\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`message_user_mentions\` DROP FOREIGN KEY \`FK_b831eb18ceebd28976239b1e2f8\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`message_user_mentions\` DROP FOREIGN KEY \`FK_a343387fc560ef378760681c236\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`member_roles\` DROP FOREIGN KEY \`FK_e9080e7a7997a0170026d5139c1\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`member_roles\` DROP FOREIGN KEY \`FK_5d7ddc8a5f9c167f548625e772e\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`notes\` DROP FOREIGN KEY \`FK_23e08e5b4481711d573e1abecdc\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`notes\` DROP FOREIGN KEY \`FK_f9e103f8ae67cb1787063597925\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`sticker_packs\` DROP FOREIGN KEY \`FK_448fafba4355ee1c837bbc865f1\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`sessions\` DROP FOREIGN KEY \`FK_085d540d9f418cfbdc7bd55bb19\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`audit_logs\` DROP FOREIGN KEY \`FK_bd2726fd31b35443f2245b93ba0\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`audit_logs\` DROP FOREIGN KEY \`FK_3cd01cd3ae7aab010310d96ac8e\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP FOREIGN KEY \`FK_e5bf78cdbbe9ba91062d74c5aba\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP FOREIGN KEY \`FK_a36ed02953077f408d0f3ebc424\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP FOREIGN KEY \`FK_e57508958bf92b9d9d25231b5e8\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`teams\` DROP FOREIGN KEY \`FK_13f00abf7cb6096c43ecaf8c108\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`team_members\` DROP FOREIGN KEY \`FK_c2bf4967c8c2a6b845dadfbf3d4\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`team_members\` DROP FOREIGN KEY \`FK_fdad7d5768277e60c40e01cdcea\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`guilds\` DROP FOREIGN KEY \`FK_9d1d665379eefde7876a17afa99\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`guilds\` DROP FOREIGN KEY \`FK_cfc3d3ad260f8121c95b31a1fce\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`guilds\` DROP FOREIGN KEY \`FK_95828668aa333460582e0ca6396\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`guilds\` DROP FOREIGN KEY \`FK_8d450b016dc8bec35f36729e4b0\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`guilds\` DROP FOREIGN KEY \`FK_fc1a451727e3643ca572a3bb394\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`guilds\` DROP FOREIGN KEY \`FK_e2a2f873a64a5cf62526de42325\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`guilds\` DROP FOREIGN KEY \`FK_f591a66b8019d87b0fe6c12dad6\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`templates\` DROP FOREIGN KEY \`FK_445d00eaaea0e60a017a5ed0c11\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`templates\` DROP FOREIGN KEY \`FK_d7374b7f8f5fbfdececa4fb62e1\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`emojis\` DROP FOREIGN KEY \`FK_fa7ddd5f9a214e28ce596548421\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`emojis\` DROP FOREIGN KEY \`FK_4b988e0db89d94cebcf07f598cc\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`channels\` DROP FOREIGN KEY \`FK_3873ed438575cce703ecff4fc7b\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`channels\` DROP FOREIGN KEY \`FK_3274522d14af40540b1a883fc80\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`channels\` DROP FOREIGN KEY \`FK_c253dafe5f3a03ec00cd8fb4581\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`voice_states\` DROP FOREIGN KEY \`FK_5fe1d5f931a67e85039c640001b\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`voice_states\` DROP FOREIGN KEY \`FK_9f8d389866b40b6657edd026dd4\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`voice_states\` DROP FOREIGN KEY \`FK_03779ef216d4b0358470d9cb748\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`invites\` DROP FOREIGN KEY \`FK_11a0d394f8fc649c19ce5f16b59\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`invites\` DROP FOREIGN KEY \`FK_15c35422032e0b22b4ada95f48f\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`invites\` DROP FOREIGN KEY \`FK_6a15b051fe5050aa00a4b9ff0f6\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`invites\` DROP FOREIGN KEY \`FK_3f4939aa1461e8af57fea3fb05d\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`read_states\` DROP FOREIGN KEY \`FK_195f92e4dd1254a4e348c043763\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`read_states\` DROP FOREIGN KEY \`FK_40da2fca4e0eaf7a23b5bfc5d34\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`messages\` DROP FOREIGN KEY \`FK_61a92bb65b302a76d9c1fcd3174\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`messages\` DROP FOREIGN KEY \`FK_5d3ec1cb962de6488637fd779d6\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`messages\` DROP FOREIGN KEY \`FK_f83c04bcf1df4e5c0e7a52ed348\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`messages\` DROP FOREIGN KEY \`FK_b0525304f2262b7014245351c76\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`messages\` DROP FOREIGN KEY \`FK_05535bc695e9f7ee104616459d3\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`messages\` DROP FOREIGN KEY \`FK_b193588441b085352a4c0109423\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`messages\` DROP FOREIGN KEY \`FK_86b9109b155eb70c0a2ca3b4b6d\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`attachments\` DROP FOREIGN KEY \`FK_623e10eec51ada466c5038979e3\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`stickers\` DROP FOREIGN KEY \`FK_8f4ee73f2bb2325ff980502e158\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`stickers\` DROP FOREIGN KEY \`FK_193d551d852aca5347ef5c9f205\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`stickers\` DROP FOREIGN KEY \`FK_e7cfa5cefa6661b3fb8fda8ce69\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`webhooks\` DROP FOREIGN KEY \`FK_3a285f4f49c40e0706d3018bc9f\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`webhooks\` DROP FOREIGN KEY \`FK_0d523f6f997c86e052c49b1455f\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`webhooks\` DROP FOREIGN KEY \`FK_c3e5305461931763b56aa905f1c\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`webhooks\` DROP FOREIGN KEY \`FK_df528cf77e82f8032230e7e37d8\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`webhooks\` DROP FOREIGN KEY \`FK_487a7af59d189f744fe394368fc\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`members\` DROP FOREIGN KEY \`FK_16aceddd5b89825b8ed6029ad1c\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`members\` DROP FOREIGN KEY \`FK_28b53062261b996d9c99fa12404\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`roles\` DROP FOREIGN KEY \`FK_c32c1ab1c4dc7dcb0278c4b1b8b\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`recipients\` DROP FOREIGN KEY \`FK_6157e8b6ba4e6e3089616481fe2\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`recipients\` DROP FOREIGN KEY \`FK_2f18ee1ba667f233ae86c0ea60e\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`bans\` DROP FOREIGN KEY \`FK_07ad88c86d1f290d46748410d58\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`bans\` DROP FOREIGN KEY \`FK_9d3ab7dd180ebdd245cdb66ecad\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`bans\` DROP FOREIGN KEY \`FK_5999e8e449f80a236ff72023559\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`backup_codes\` DROP FOREIGN KEY \`FK_70066ea80d2f4b871beda32633b\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`connected_accounts\` DROP FOREIGN KEY \`FK_f47244225a6a1eac04a3463dd90\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`relationships\` DROP FOREIGN KEY \`FK_9c7f6b98a9843b76dce1b0c878b\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`relationships\` DROP FOREIGN KEY \`FK_9af4194bab1250b1c584ae4f1d7\`
+        `);
+		await queryRunner.query(`
+            DROP INDEX \`IDX_e22a70819d07659c7a71c112a1\` ON \`message_stickers\`
+        `);
+		await queryRunner.query(`
+            DROP INDEX \`IDX_40bb6f23e7cc133292e92829d2\` ON \`message_stickers\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`message_stickers\`
+        `);
+		await queryRunner.query(`
+            DROP INDEX \`IDX_bdb8c09e1464cabf62105bf4b9\` ON \`message_channel_mentions\`
+        `);
+		await queryRunner.query(`
+            DROP INDEX \`IDX_2a27102ecd1d81b4582a436092\` ON \`message_channel_mentions\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`message_channel_mentions\`
+        `);
+		await queryRunner.query(`
+            DROP INDEX \`IDX_29d63eb1a458200851bc37d074\` ON \`message_role_mentions\`
+        `);
+		await queryRunner.query(`
+            DROP INDEX \`IDX_a8242cf535337a490b0feaea0b\` ON \`message_role_mentions\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`message_role_mentions\`
+        `);
+		await queryRunner.query(`
+            DROP INDEX \`IDX_b831eb18ceebd28976239b1e2f\` ON \`message_user_mentions\`
+        `);
+		await queryRunner.query(`
+            DROP INDEX \`IDX_a343387fc560ef378760681c23\` ON \`message_user_mentions\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`message_user_mentions\`
+        `);
+		await queryRunner.query(`
+            DROP INDEX \`IDX_e9080e7a7997a0170026d5139c\` ON \`member_roles\`
+        `);
+		await queryRunner.query(`
+            DROP INDEX \`IDX_5d7ddc8a5f9c167f548625e772\` ON \`member_roles\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`member_roles\`
+        `);
+		await queryRunner.query(`
+            DROP INDEX \`IDX_74e6689b9568cc965b8bfc9150\` ON \`notes\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`notes\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`client_release\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`sticker_packs\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`sessions\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`rate_limits\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`categories\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`audit_logs\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`applications\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`teams\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`team_members\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`guilds\`
+        `);
+		await queryRunner.query(`
+            DROP INDEX \`IDX_be38737bf339baf63b1daeffb5\` ON \`templates\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`templates\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`emojis\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`channels\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`voice_states\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`invites\`
+        `);
+		await queryRunner.query(`
+            DROP INDEX \`IDX_0abf8b443321bd3cf7f81ee17a\` ON \`read_states\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`read_states\`
+        `);
+		await queryRunner.query(`
+            DROP INDEX \`IDX_3ed7a60fb7dbe04e1ba9332a8b\` ON \`messages\`
+        `);
+		await queryRunner.query(`
+            DROP INDEX \`IDX_05535bc695e9f7ee104616459d\` ON \`messages\`
+        `);
+		await queryRunner.query(`
+            DROP INDEX \`IDX_86b9109b155eb70c0a2ca3b4b6\` ON \`messages\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`messages\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`attachments\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`stickers\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`webhooks\`
+        `);
+		await queryRunner.query(`
+            DROP INDEX \`IDX_bb2bf9386ac443afbbbf9f12d3\` ON \`members\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`members\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`roles\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`recipients\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`bans\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`backup_codes\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`users\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`connected_accounts\`
+        `);
+		await queryRunner.query(`
+            DROP INDEX \`IDX_a0b2ff0a598df0b0d055934a17\` ON \`relationships\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`relationships\`
+        `);
+		await queryRunner.query(`
+            DROP TABLE \`config\`
+        `);
+	}
+}
diff --git a/src/util/migrations/mariadb/1659921859145-premium_since_as_date.ts b/src/util/migrations/mariadb/1659921859145-premium_since_as_date.ts
new file mode 100644
index 00000000..549d6b9f
--- /dev/null
+++ b/src/util/migrations/mariadb/1659921859145-premium_since_as_date.ts
@@ -0,0 +1,25 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class premiumSinceAsDate1659921859145 implements MigrationInterface {
+	name = "premiumSinceAsDate1659921859145";
+
+	public async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE \`members\` DROP COLUMN \`premium_since\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`members\`
+            ADD \`premium_since\` datetime NULL
+        `);
+	}
+
+	public async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE \`members\` DROP COLUMN \`premium_since\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`members\`
+            ADD \`premium_since\` bigint NULL
+        `);
+	}
+}
diff --git a/src/util/migrations/mariadb/1660130586602-updated-applications.ts b/src/util/migrations/mariadb/1660130586602-updated-applications.ts
new file mode 100644
index 00000000..fea076db
--- /dev/null
+++ b/src/util/migrations/mariadb/1660130586602-updated-applications.ts
@@ -0,0 +1,184 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class updatedApplications1660130586602 implements MigrationInterface {
+	name = "updatedApplications1660130586602";
+
+	public async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP FOREIGN KEY \`FK_e5bf78cdbbe9ba91062d74c5aba\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP COLUMN \`rpc_origins\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP COLUMN \`primary_sku_id\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP COLUMN \`slug\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP COLUMN \`guild_id\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD \`type\` text NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD \`hook\` tinyint NOT NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD \`redirect_uris\` text NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD \`rpc_application_state\` int NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD \`store_application_state\` int NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD \`verification_state\` int NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD \`interactions_endpoint_url\` varchar(255) NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD \`integration_public\` tinyint NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD \`integration_require_code_grant\` tinyint NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD \`discoverability_state\` int NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD \`discovery_eligibility_flags\` int NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD \`tags\` text NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD \`install_params\` text NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD \`bot_user_id\` varchar(255) NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD UNIQUE INDEX \`IDX_2ce5a55796fe4c2f77ece57a64\` (\`bot_user_id\`)
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` CHANGE \`description\` \`description\` varchar(255) NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP COLUMN \`flags\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD \`flags\` int NOT NULL
+        `);
+		await queryRunner.query(`
+            CREATE UNIQUE INDEX \`REL_2ce5a55796fe4c2f77ece57a64\` ON \`applications\` (\`bot_user_id\`)
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD CONSTRAINT \`FK_2ce5a55796fe4c2f77ece57a647\` FOREIGN KEY (\`bot_user_id\`) REFERENCES \`users\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+	}
+
+	public async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP FOREIGN KEY \`FK_2ce5a55796fe4c2f77ece57a647\`
+        `);
+		await queryRunner.query(`
+            DROP INDEX \`REL_2ce5a55796fe4c2f77ece57a64\` ON \`applications\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP COLUMN \`flags\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD \`flags\` varchar(255) NOT NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` CHANGE \`description\` \`description\` varchar(255) NOT NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP INDEX \`IDX_2ce5a55796fe4c2f77ece57a64\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP COLUMN \`bot_user_id\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP COLUMN \`install_params\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP COLUMN \`tags\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP COLUMN \`discovery_eligibility_flags\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP COLUMN \`discoverability_state\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP COLUMN \`integration_require_code_grant\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP COLUMN \`integration_public\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP COLUMN \`interactions_endpoint_url\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP COLUMN \`verification_state\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP COLUMN \`store_application_state\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP COLUMN \`rpc_application_state\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP COLUMN \`redirect_uris\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP COLUMN \`hook\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\` DROP COLUMN \`type\`
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD \`guild_id\` varchar(255) NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD \`slug\` varchar(255) NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD \`primary_sku_id\` varchar(255) NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD \`rpc_origins\` text NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE \`applications\`
+            ADD CONSTRAINT \`FK_e5bf78cdbbe9ba91062d74c5aba\` FOREIGN KEY (\`guild_id\`) REFERENCES \`guilds\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+	}
+}
diff --git a/src/util/migrations/mariadb/1661273147273-test.ts b/src/util/migrations/mariadb/1661273147273-test.ts
new file mode 100644
index 00000000..4e077a11
--- /dev/null
+++ b/src/util/migrations/mariadb/1661273147273-test.ts
@@ -0,0 +1,149 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class test1661273147273 implements MigrationInterface {
+    name = 'test1661273147273'
+
+    public async up(queryRunner: QueryRunner): Promise<void> {
+        await queryRunner.query(`
+            ALTER TABLE \`invites\` DROP FOREIGN KEY \`FK_15c35422032e0b22b4ada95f48f\`
+        `);
+        await queryRunner.query(`
+            DROP INDEX \`IDX_2ce5a55796fe4c2f77ece57a64\` ON \`applications\`
+        `);
+        await queryRunner.query(`
+            CREATE TABLE \`plugin_config\` (
+                \`key\` varchar(255) NOT NULL,
+                \`value\` text NULL,
+                PRIMARY KEY (\`key\`)
+            ) ENGINE = InnoDB
+        `);
+        await queryRunner.query(`
+            CREATE TABLE \`user_settings\` (
+                \`id\` varchar(255) NOT NULL,
+                \`afk_timeout\` int NULL,
+                \`allow_accessibility_detection\` tinyint NULL,
+                \`animate_emoji\` tinyint NULL,
+                \`animate_stickers\` int NULL,
+                \`contact_sync_enabled\` tinyint NULL,
+                \`convert_emoticons\` tinyint NULL,
+                \`custom_status\` text NULL,
+                \`default_guilds_restricted\` tinyint NULL,
+                \`detect_platform_accounts\` tinyint NULL,
+                \`developer_mode\` tinyint NULL,
+                \`disable_games_tab\` tinyint NULL,
+                \`enable_tts_command\` tinyint NULL,
+                \`explicit_content_filter\` int NULL,
+                \`friend_source_flags\` text NULL,
+                \`gateway_connected\` tinyint NULL,
+                \`gif_auto_play\` tinyint NULL,
+                \`guild_folders\` text NULL,
+                \`guild_positions\` text NULL,
+                \`inline_attachment_media\` tinyint NULL,
+                \`inline_embed_media\` tinyint NULL,
+                \`locale\` varchar(255) NULL,
+                \`message_display_compact\` tinyint NULL,
+                \`native_phone_integration_enabled\` tinyint NULL,
+                \`render_embeds\` tinyint NULL,
+                \`render_reactions\` tinyint NULL,
+                \`restricted_guilds\` text NULL,
+                \`show_current_game\` tinyint NULL,
+                \`status\` varchar(255) NULL,
+                \`stream_notifications_enabled\` tinyint NULL,
+                \`theme\` varchar(255) NULL,
+                \`timezone_offset\` int NULL,
+                PRIMARY KEY (\`id\`)
+            ) ENGINE = InnoDB
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`users\` DROP COLUMN \`settings\`
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`users\`
+            ADD \`settingsId\` varchar(255) NULL
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`users\`
+            ADD UNIQUE INDEX \`IDX_76ba283779c8441fd5ff819c8c\` (\`settingsId\`)
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`channels\`
+            ADD \`flags\` int NULL
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`channels\`
+            ADD \`default_thread_rate_limit_per_user\` int NULL
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`guilds\`
+            ADD \`premium_progress_bar_enabled\` tinyint NULL
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`users\` CHANGE \`bio\` \`bio\` varchar(255) NULL
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`users\` CHANGE \`mfa_enabled\` \`mfa_enabled\` tinyint NULL
+        `);
+        await queryRunner.query(`
+            CREATE UNIQUE INDEX \`REL_76ba283779c8441fd5ff819c8c\` ON \`users\` (\`settingsId\`)
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`users\`
+            ADD CONSTRAINT \`FK_76ba283779c8441fd5ff819c8cf\` FOREIGN KEY (\`settingsId\`) REFERENCES \`user_settings\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`invites\`
+            ADD CONSTRAINT \`FK_15c35422032e0b22b4ada95f48f\` FOREIGN KEY (\`inviter_id\`) REFERENCES \`users\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+    }
+
+    public async down(queryRunner: QueryRunner): Promise<void> {
+        await queryRunner.query(`
+            ALTER TABLE \`invites\` DROP FOREIGN KEY \`FK_15c35422032e0b22b4ada95f48f\`
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`users\` DROP FOREIGN KEY \`FK_76ba283779c8441fd5ff819c8cf\`
+        `);
+        await queryRunner.query(`
+            DROP INDEX \`REL_76ba283779c8441fd5ff819c8c\` ON \`users\`
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`users\` CHANGE \`mfa_enabled\` \`mfa_enabled\` tinyint NOT NULL
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`users\` CHANGE \`bio\` \`bio\` varchar(255) NOT NULL
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`guilds\` DROP COLUMN \`premium_progress_bar_enabled\`
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`channels\` DROP COLUMN \`default_thread_rate_limit_per_user\`
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`channels\` DROP COLUMN \`flags\`
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`users\` DROP INDEX \`IDX_76ba283779c8441fd5ff819c8c\`
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`users\` DROP COLUMN \`settingsId\`
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`users\`
+            ADD \`settings\` text NOT NULL
+        `);
+        await queryRunner.query(`
+            DROP TABLE \`user_settings\`
+        `);
+        await queryRunner.query(`
+            DROP TABLE \`plugin_config\`
+        `);
+        await queryRunner.query(`
+            CREATE UNIQUE INDEX \`IDX_2ce5a55796fe4c2f77ece57a64\` ON \`applications\` (\`bot_user_id\`)
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`invites\`
+            ADD CONSTRAINT \`FK_15c35422032e0b22b4ada95f48f\` FOREIGN KEY (\`inviter_id\`) REFERENCES \`users\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+    }
+
+}
diff --git a/src/util/migrations/mariadb/1661273179287-test2.ts b/src/util/migrations/mariadb/1661273179287-test2.ts
new file mode 100644
index 00000000..0f77f284
--- /dev/null
+++ b/src/util/migrations/mariadb/1661273179287-test2.ts
@@ -0,0 +1,18 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class test21661273179287 implements MigrationInterface {
+    name = 'test21661273179287'
+
+    public async up(queryRunner: QueryRunner): Promise<void> {
+        await queryRunner.query(`
+            DROP INDEX \`IDX_76ba283779c8441fd5ff819c8c\` ON \`users\`
+        `);
+    }
+
+    public async down(queryRunner: QueryRunner): Promise<void> {
+        await queryRunner.query(`
+            CREATE UNIQUE INDEX \`IDX_76ba283779c8441fd5ff819c8c\` ON \`users\` (\`settingsId\`)
+        `);
+    }
+
+}
diff --git a/src/util/migrations/postgres/1659899687168-initial.ts b/src/util/migrations/postgres/1659899687168-initial.ts
new file mode 100644
index 00000000..dc89a572
--- /dev/null
+++ b/src/util/migrations/postgres/1659899687168-initial.ts
@@ -0,0 +1,1244 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class initial1659899687168 implements MigrationInterface {
+	name = "initial1659899687168";
+
+	public async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            CREATE TABLE "config" (
+                "key" character varying NOT NULL,
+                "value" text,
+                CONSTRAINT "PK_26489c99ddbb4c91631ef5cc791" PRIMARY KEY ("key")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "relationships" (
+                "id" character varying NOT NULL,
+                "from_id" character varying NOT NULL,
+                "to_id" character varying NOT NULL,
+                "nickname" character varying,
+                "type" integer NOT NULL,
+                CONSTRAINT "PK_ba20e2f5cf487408e08e4dcecaf" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE UNIQUE INDEX "IDX_a0b2ff0a598df0b0d055934a17" ON "relationships" ("from_id", "to_id")
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "connected_accounts" (
+                "id" character varying NOT NULL,
+                "user_id" character varying,
+                "access_token" character varying NOT NULL,
+                "friend_sync" boolean NOT NULL,
+                "name" character varying NOT NULL,
+                "revoked" boolean NOT NULL,
+                "show_activity" boolean NOT NULL,
+                "type" character varying NOT NULL,
+                "verified" boolean NOT NULL,
+                "visibility" integer NOT NULL,
+                CONSTRAINT "PK_70416f1da0be645bb31da01c774" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "users" (
+                "id" character varying NOT NULL,
+                "username" character varying NOT NULL,
+                "discriminator" character varying NOT NULL,
+                "avatar" character varying,
+                "accent_color" integer,
+                "banner" character varying,
+                "phone" character varying,
+                "desktop" boolean NOT NULL,
+                "mobile" boolean NOT NULL,
+                "premium" boolean NOT NULL,
+                "premium_type" integer NOT NULL,
+                "bot" boolean NOT NULL,
+                "bio" character varying NOT NULL,
+                "system" boolean NOT NULL,
+                "nsfw_allowed" boolean NOT NULL,
+                "mfa_enabled" boolean NOT NULL,
+                "totp_secret" character varying,
+                "totp_last_ticket" character varying,
+                "created_at" TIMESTAMP NOT NULL,
+                "premium_since" TIMESTAMP,
+                "verified" boolean NOT NULL,
+                "disabled" boolean NOT NULL,
+                "deleted" boolean NOT NULL,
+                "email" character varying,
+                "flags" character varying NOT NULL,
+                "public_flags" integer NOT NULL,
+                "rights" bigint NOT NULL,
+                "data" text NOT NULL,
+                "fingerprints" text NOT NULL,
+                "settings" text NOT NULL,
+                "extended_settings" text NOT NULL,
+                "notes" text NOT NULL,
+                CONSTRAINT "PK_a3ffb1c0c8416b9fc6f907b7433" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "backup_codes" (
+                "id" character varying NOT NULL,
+                "code" character varying NOT NULL,
+                "consumed" boolean NOT NULL,
+                "expired" boolean NOT NULL,
+                "user_id" character varying,
+                CONSTRAINT "PK_34ab957382dbc57e8fb53f1638f" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "bans" (
+                "id" character varying NOT NULL,
+                "user_id" character varying,
+                "guild_id" character varying,
+                "executor_id" character varying,
+                "ip" character varying NOT NULL,
+                "reason" character varying,
+                CONSTRAINT "PK_a4d6f261bffa4615c62d756566a" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "recipients" (
+                "id" character varying NOT NULL,
+                "channel_id" character varying NOT NULL,
+                "user_id" character varying NOT NULL,
+                "closed" boolean NOT NULL DEFAULT false,
+                CONSTRAINT "PK_de8fc5a9c364568f294798fe1e9" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "roles" (
+                "id" character varying NOT NULL,
+                "guild_id" character varying,
+                "color" integer NOT NULL,
+                "hoist" boolean NOT NULL,
+                "managed" boolean NOT NULL,
+                "mentionable" boolean NOT NULL,
+                "name" character varying NOT NULL,
+                "permissions" character varying NOT NULL,
+                "position" integer NOT NULL,
+                "icon" character varying,
+                "unicode_emoji" character varying,
+                "tags" text,
+                CONSTRAINT "PK_c1433d71a4838793a49dcad46ab" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "members" (
+                "index" SERIAL NOT NULL,
+                "id" character varying NOT NULL,
+                "guild_id" character varying NOT NULL,
+                "nick" character varying,
+                "joined_at" TIMESTAMP NOT NULL,
+                "premium_since" bigint,
+                "deaf" boolean NOT NULL,
+                "mute" boolean NOT NULL,
+                "pending" boolean NOT NULL,
+                "settings" text NOT NULL,
+                "last_message_id" character varying,
+                "joined_by" character varying,
+                CONSTRAINT "PK_b4a6b8c2478e5df990909c6cf6a" PRIMARY KEY ("index")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE UNIQUE INDEX "IDX_bb2bf9386ac443afbbbf9f12d3" ON "members" ("id", "guild_id")
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "webhooks" (
+                "id" character varying NOT NULL,
+                "type" integer NOT NULL,
+                "name" character varying,
+                "avatar" character varying,
+                "token" character varying,
+                "guild_id" character varying,
+                "channel_id" character varying,
+                "application_id" character varying,
+                "user_id" character varying,
+                "source_guild_id" character varying,
+                CONSTRAINT "PK_9e8795cfc899ab7bdaa831e8527" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "stickers" (
+                "id" character varying NOT NULL,
+                "name" character varying NOT NULL,
+                "description" character varying,
+                "available" boolean,
+                "tags" character varying,
+                "pack_id" character varying,
+                "guild_id" character varying,
+                "user_id" character varying,
+                "type" integer NOT NULL,
+                "format_type" integer NOT NULL,
+                CONSTRAINT "PK_e1dafa4063a5532645cc2810374" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "attachments" (
+                "id" character varying NOT NULL,
+                "filename" character varying NOT NULL,
+                "size" integer NOT NULL,
+                "url" character varying NOT NULL,
+                "proxy_url" character varying NOT NULL,
+                "height" integer,
+                "width" integer,
+                "content_type" character varying,
+                "message_id" character varying,
+                CONSTRAINT "PK_5e1f050bcff31e3084a1d662412" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "messages" (
+                "id" character varying NOT NULL,
+                "channel_id" character varying,
+                "guild_id" character varying,
+                "author_id" character varying,
+                "member_id" character varying,
+                "webhook_id" character varying,
+                "application_id" character varying,
+                "content" character varying,
+                "timestamp" TIMESTAMP NOT NULL DEFAULT now(),
+                "edited_timestamp" TIMESTAMP,
+                "tts" boolean,
+                "mention_everyone" boolean,
+                "embeds" text NOT NULL,
+                "reactions" text NOT NULL,
+                "nonce" text,
+                "pinned" boolean,
+                "type" integer NOT NULL,
+                "activity" text,
+                "flags" character varying,
+                "message_reference" text,
+                "interaction" text,
+                "components" text,
+                "message_reference_id" character varying,
+                CONSTRAINT "PK_18325f38ae6de43878487eff986" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_86b9109b155eb70c0a2ca3b4b6" ON "messages" ("channel_id")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_05535bc695e9f7ee104616459d" ON "messages" ("author_id")
+        `);
+		await queryRunner.query(`
+            CREATE UNIQUE INDEX "IDX_3ed7a60fb7dbe04e1ba9332a8b" ON "messages" ("channel_id", "id")
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "read_states" (
+                "id" character varying NOT NULL,
+                "channel_id" character varying NOT NULL,
+                "user_id" character varying NOT NULL,
+                "last_message_id" character varying,
+                "public_ack" character varying,
+                "notifications_cursor" character varying,
+                "last_pin_timestamp" TIMESTAMP,
+                "mention_count" integer,
+                CONSTRAINT "PK_e6956a804978f01b713b1ed58e2" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE UNIQUE INDEX "IDX_0abf8b443321bd3cf7f81ee17a" ON "read_states" ("channel_id", "user_id")
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "invites" (
+                "code" character varying NOT NULL,
+                "temporary" boolean NOT NULL,
+                "uses" integer NOT NULL,
+                "max_uses" integer NOT NULL,
+                "max_age" integer NOT NULL,
+                "created_at" TIMESTAMP NOT NULL,
+                "expires_at" TIMESTAMP NOT NULL,
+                "guild_id" character varying,
+                "channel_id" character varying,
+                "inviter_id" character varying,
+                "target_user_id" character varying,
+                "target_user_type" integer,
+                "vanity_url" boolean,
+                CONSTRAINT "PK_33fd8a248db1cd832baa8aa25bf" PRIMARY KEY ("code")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "voice_states" (
+                "id" character varying NOT NULL,
+                "guild_id" character varying,
+                "channel_id" character varying,
+                "user_id" character varying,
+                "session_id" character varying NOT NULL,
+                "token" character varying,
+                "deaf" boolean NOT NULL,
+                "mute" boolean NOT NULL,
+                "self_deaf" boolean NOT NULL,
+                "self_mute" boolean NOT NULL,
+                "self_stream" boolean,
+                "self_video" boolean NOT NULL,
+                "suppress" boolean NOT NULL,
+                "request_to_speak_timestamp" TIMESTAMP,
+                CONSTRAINT "PK_ada09a50c134fad1369b510e3ce" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "channels" (
+                "id" character varying NOT NULL,
+                "created_at" TIMESTAMP NOT NULL,
+                "name" character varying,
+                "icon" text,
+                "type" integer NOT NULL,
+                "last_message_id" character varying,
+                "guild_id" character varying,
+                "parent_id" character varying,
+                "owner_id" character varying,
+                "last_pin_timestamp" integer,
+                "default_auto_archive_duration" integer,
+                "position" integer,
+                "permission_overwrites" text,
+                "video_quality_mode" integer,
+                "bitrate" integer,
+                "user_limit" integer,
+                "nsfw" boolean,
+                "rate_limit_per_user" integer,
+                "topic" character varying,
+                "retention_policy_id" character varying,
+                CONSTRAINT "PK_bc603823f3f741359c2339389f9" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "emojis" (
+                "id" character varying NOT NULL,
+                "animated" boolean NOT NULL,
+                "available" boolean NOT NULL,
+                "guild_id" character varying NOT NULL,
+                "user_id" character varying,
+                "managed" boolean NOT NULL,
+                "name" character varying NOT NULL,
+                "require_colons" boolean NOT NULL,
+                "roles" text NOT NULL,
+                "groups" text,
+                CONSTRAINT "PK_9adb96a675f555c6169bad7ba62" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "templates" (
+                "id" character varying NOT NULL,
+                "code" character varying NOT NULL,
+                "name" character varying NOT NULL,
+                "description" character varying,
+                "usage_count" integer,
+                "creator_id" character varying,
+                "created_at" TIMESTAMP NOT NULL,
+                "updated_at" TIMESTAMP NOT NULL,
+                "source_guild_id" character varying,
+                "serialized_source_guild" text NOT NULL,
+                CONSTRAINT "UQ_be38737bf339baf63b1daeffb55" UNIQUE ("code"),
+                CONSTRAINT "PK_515948649ce0bbbe391de702ae5" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "guilds" (
+                "id" character varying NOT NULL,
+                "afk_channel_id" character varying,
+                "afk_timeout" integer,
+                "banner" character varying,
+                "default_message_notifications" integer,
+                "description" character varying,
+                "discovery_splash" character varying,
+                "explicit_content_filter" integer,
+                "features" text NOT NULL,
+                "primary_category_id" integer,
+                "icon" character varying,
+                "large" boolean,
+                "max_members" integer,
+                "max_presences" integer,
+                "max_video_channel_users" integer,
+                "member_count" integer,
+                "presence_count" integer,
+                "template_id" character varying,
+                "mfa_level" integer,
+                "name" character varying NOT NULL,
+                "owner_id" character varying,
+                "preferred_locale" character varying,
+                "premium_subscription_count" integer,
+                "premium_tier" integer,
+                "public_updates_channel_id" character varying,
+                "rules_channel_id" character varying,
+                "region" character varying,
+                "splash" character varying,
+                "system_channel_id" character varying,
+                "system_channel_flags" integer,
+                "unavailable" boolean,
+                "verification_level" integer,
+                "welcome_screen" text NOT NULL,
+                "widget_channel_id" character varying,
+                "widget_enabled" boolean,
+                "nsfw_level" integer,
+                "nsfw" boolean,
+                "parent" character varying,
+                CONSTRAINT "PK_e7e7f2a51bd6d96a9ac2aa560f9" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "team_members" (
+                "id" character varying NOT NULL,
+                "membership_state" integer NOT NULL,
+                "permissions" text NOT NULL,
+                "team_id" character varying,
+                "user_id" character varying,
+                CONSTRAINT "PK_ca3eae89dcf20c9fd95bf7460aa" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "teams" (
+                "id" character varying NOT NULL,
+                "icon" character varying,
+                "name" character varying NOT NULL,
+                "owner_user_id" character varying,
+                CONSTRAINT "PK_7e5523774a38b08a6236d322403" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "applications" (
+                "id" character varying NOT NULL,
+                "name" character varying NOT NULL,
+                "icon" character varying,
+                "description" character varying NOT NULL,
+                "rpc_origins" text,
+                "bot_public" boolean NOT NULL,
+                "bot_require_code_grant" boolean NOT NULL,
+                "terms_of_service_url" character varying,
+                "privacy_policy_url" character varying,
+                "summary" character varying,
+                "verify_key" character varying NOT NULL,
+                "primary_sku_id" character varying,
+                "slug" character varying,
+                "cover_image" character varying,
+                "flags" character varying NOT NULL,
+                "owner_id" character varying,
+                "team_id" character varying,
+                "guild_id" character varying,
+                CONSTRAINT "PK_938c0a27255637bde919591888f" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "audit_logs" (
+                "id" character varying NOT NULL,
+                "user_id" character varying,
+                "action_type" integer NOT NULL,
+                "options" text,
+                "changes" text NOT NULL,
+                "reason" character varying,
+                "target_id" character varying,
+                CONSTRAINT "PK_1bb179d048bbc581caa3b013439" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "categories" (
+                "id" integer NOT NULL,
+                "name" character varying,
+                "localizations" text NOT NULL,
+                "is_primary" boolean,
+                CONSTRAINT "PK_24dbc6126a28ff948da33e97d3b" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "rate_limits" (
+                "id" character varying NOT NULL,
+                "executor_id" character varying NOT NULL,
+                "hits" integer NOT NULL,
+                "blocked" boolean NOT NULL,
+                "expires_at" TIMESTAMP NOT NULL,
+                CONSTRAINT "PK_3b4449f1f5fc167d921ee619f65" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "sessions" (
+                "id" character varying NOT NULL,
+                "user_id" character varying,
+                "session_id" character varying NOT NULL,
+                "activities" text,
+                "client_info" text NOT NULL,
+                "status" character varying NOT NULL,
+                CONSTRAINT "PK_3238ef96f18b355b671619111bc" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "sticker_packs" (
+                "id" character varying NOT NULL,
+                "name" character varying NOT NULL,
+                "description" character varying,
+                "banner_asset_id" character varying,
+                "cover_sticker_id" character varying,
+                "coverStickerId" character varying,
+                CONSTRAINT "PK_a27381efea0f876f5d3233af655" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "client_release" (
+                "id" character varying NOT NULL,
+                "name" character varying NOT NULL,
+                "pub_date" character varying NOT NULL,
+                "url" character varying NOT NULL,
+                "deb_url" character varying NOT NULL,
+                "osx_url" character varying NOT NULL,
+                "win_url" character varying NOT NULL,
+                "notes" character varying,
+                CONSTRAINT "PK_4c4ea258342d2d6ba1be0a71a43" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "notes" (
+                "id" character varying NOT NULL,
+                "content" character varying NOT NULL,
+                "owner_id" character varying,
+                "target_id" character varying,
+                CONSTRAINT "UQ_74e6689b9568cc965b8bfc9150b" UNIQUE ("owner_id", "target_id"),
+                CONSTRAINT "PK_af6206538ea96c4e77e9f400c3d" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "member_roles" (
+                "index" integer NOT NULL,
+                "role_id" character varying NOT NULL,
+                CONSTRAINT "PK_951c1d72a0fd1da8760b4a1fd66" PRIMARY KEY ("index", "role_id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_5d7ddc8a5f9c167f548625e772" ON "member_roles" ("index")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_e9080e7a7997a0170026d5139c" ON "member_roles" ("role_id")
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "message_user_mentions" (
+                "messagesId" character varying NOT NULL,
+                "usersId" character varying NOT NULL,
+                CONSTRAINT "PK_9b9b6e245ad47a48dbd7605d4fb" PRIMARY KEY ("messagesId", "usersId")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_a343387fc560ef378760681c23" ON "message_user_mentions" ("messagesId")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_b831eb18ceebd28976239b1e2f" ON "message_user_mentions" ("usersId")
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "message_role_mentions" (
+                "messagesId" character varying NOT NULL,
+                "rolesId" character varying NOT NULL,
+                CONSTRAINT "PK_74dba92cc300452a6e14b83ed44" PRIMARY KEY ("messagesId", "rolesId")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_a8242cf535337a490b0feaea0b" ON "message_role_mentions" ("messagesId")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_29d63eb1a458200851bc37d074" ON "message_role_mentions" ("rolesId")
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "message_channel_mentions" (
+                "messagesId" character varying NOT NULL,
+                "channelsId" character varying NOT NULL,
+                CONSTRAINT "PK_85cb45351497cd9d06a79ced65e" PRIMARY KEY ("messagesId", "channelsId")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_2a27102ecd1d81b4582a436092" ON "message_channel_mentions" ("messagesId")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_bdb8c09e1464cabf62105bf4b9" ON "message_channel_mentions" ("channelsId")
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "message_stickers" (
+                "messagesId" character varying NOT NULL,
+                "stickersId" character varying NOT NULL,
+                CONSTRAINT "PK_ed820c4093d0b8cd1d2bcf66087" PRIMARY KEY ("messagesId", "stickersId")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_40bb6f23e7cc133292e92829d2" ON "message_stickers" ("messagesId")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_e22a70819d07659c7a71c112a1" ON "message_stickers" ("stickersId")
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "relationships"
+            ADD CONSTRAINT "FK_9af4194bab1250b1c584ae4f1d7" FOREIGN KEY ("from_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "relationships"
+            ADD CONSTRAINT "FK_9c7f6b98a9843b76dce1b0c878b" FOREIGN KEY ("to_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "connected_accounts"
+            ADD CONSTRAINT "FK_f47244225a6a1eac04a3463dd90" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "backup_codes"
+            ADD CONSTRAINT "FK_70066ea80d2f4b871beda32633b" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "bans"
+            ADD CONSTRAINT "FK_5999e8e449f80a236ff72023559" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "bans"
+            ADD CONSTRAINT "FK_9d3ab7dd180ebdd245cdb66ecad" FOREIGN KEY ("guild_id") REFERENCES "guilds"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "bans"
+            ADD CONSTRAINT "FK_07ad88c86d1f290d46748410d58" FOREIGN KEY ("executor_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "recipients"
+            ADD CONSTRAINT "FK_2f18ee1ba667f233ae86c0ea60e" FOREIGN KEY ("channel_id") REFERENCES "channels"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "recipients"
+            ADD CONSTRAINT "FK_6157e8b6ba4e6e3089616481fe2" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "roles"
+            ADD CONSTRAINT "FK_c32c1ab1c4dc7dcb0278c4b1b8b" FOREIGN KEY ("guild_id") REFERENCES "guilds"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "members"
+            ADD CONSTRAINT "FK_28b53062261b996d9c99fa12404" FOREIGN KEY ("id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "members"
+            ADD CONSTRAINT "FK_16aceddd5b89825b8ed6029ad1c" FOREIGN KEY ("guild_id") REFERENCES "guilds"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "webhooks"
+            ADD CONSTRAINT "FK_487a7af59d189f744fe394368fc" FOREIGN KEY ("guild_id") REFERENCES "guilds"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "webhooks"
+            ADD CONSTRAINT "FK_df528cf77e82f8032230e7e37d8" FOREIGN KEY ("channel_id") REFERENCES "channels"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "webhooks"
+            ADD CONSTRAINT "FK_c3e5305461931763b56aa905f1c" FOREIGN KEY ("application_id") REFERENCES "applications"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "webhooks"
+            ADD CONSTRAINT "FK_0d523f6f997c86e052c49b1455f" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "webhooks"
+            ADD CONSTRAINT "FK_3a285f4f49c40e0706d3018bc9f" FOREIGN KEY ("source_guild_id") REFERENCES "guilds"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "stickers"
+            ADD CONSTRAINT "FK_e7cfa5cefa6661b3fb8fda8ce69" FOREIGN KEY ("pack_id") REFERENCES "sticker_packs"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "stickers"
+            ADD CONSTRAINT "FK_193d551d852aca5347ef5c9f205" FOREIGN KEY ("guild_id") REFERENCES "guilds"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "stickers"
+            ADD CONSTRAINT "FK_8f4ee73f2bb2325ff980502e158" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "attachments"
+            ADD CONSTRAINT "FK_623e10eec51ada466c5038979e3" FOREIGN KEY ("message_id") REFERENCES "messages"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "messages"
+            ADD CONSTRAINT "FK_86b9109b155eb70c0a2ca3b4b6d" FOREIGN KEY ("channel_id") REFERENCES "channels"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "messages"
+            ADD CONSTRAINT "FK_b193588441b085352a4c0109423" FOREIGN KEY ("guild_id") REFERENCES "guilds"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "messages"
+            ADD CONSTRAINT "FK_05535bc695e9f7ee104616459d3" FOREIGN KEY ("author_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "messages"
+            ADD CONSTRAINT "FK_b0525304f2262b7014245351c76" FOREIGN KEY ("member_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "messages"
+            ADD CONSTRAINT "FK_f83c04bcf1df4e5c0e7a52ed348" FOREIGN KEY ("webhook_id") REFERENCES "webhooks"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "messages"
+            ADD CONSTRAINT "FK_5d3ec1cb962de6488637fd779d6" FOREIGN KEY ("application_id") REFERENCES "applications"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "messages"
+            ADD CONSTRAINT "FK_61a92bb65b302a76d9c1fcd3174" FOREIGN KEY ("message_reference_id") REFERENCES "messages"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "read_states"
+            ADD CONSTRAINT "FK_40da2fca4e0eaf7a23b5bfc5d34" FOREIGN KEY ("channel_id") REFERENCES "channels"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "read_states"
+            ADD CONSTRAINT "FK_195f92e4dd1254a4e348c043763" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "invites"
+            ADD CONSTRAINT "FK_3f4939aa1461e8af57fea3fb05d" FOREIGN KEY ("guild_id") REFERENCES "guilds"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "invites"
+            ADD CONSTRAINT "FK_6a15b051fe5050aa00a4b9ff0f6" FOREIGN KEY ("channel_id") REFERENCES "channels"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "invites"
+            ADD CONSTRAINT "FK_15c35422032e0b22b4ada95f48f" FOREIGN KEY ("inviter_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "invites"
+            ADD CONSTRAINT "FK_11a0d394f8fc649c19ce5f16b59" FOREIGN KEY ("target_user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "voice_states"
+            ADD CONSTRAINT "FK_03779ef216d4b0358470d9cb748" FOREIGN KEY ("guild_id") REFERENCES "guilds"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "voice_states"
+            ADD CONSTRAINT "FK_9f8d389866b40b6657edd026dd4" FOREIGN KEY ("channel_id") REFERENCES "channels"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "voice_states"
+            ADD CONSTRAINT "FK_5fe1d5f931a67e85039c640001b" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "channels"
+            ADD CONSTRAINT "FK_c253dafe5f3a03ec00cd8fb4581" FOREIGN KEY ("guild_id") REFERENCES "guilds"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "channels"
+            ADD CONSTRAINT "FK_3274522d14af40540b1a883fc80" FOREIGN KEY ("parent_id") REFERENCES "channels"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "channels"
+            ADD CONSTRAINT "FK_3873ed438575cce703ecff4fc7b" FOREIGN KEY ("owner_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "emojis"
+            ADD CONSTRAINT "FK_4b988e0db89d94cebcf07f598cc" FOREIGN KEY ("guild_id") REFERENCES "guilds"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "emojis"
+            ADD CONSTRAINT "FK_fa7ddd5f9a214e28ce596548421" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "templates"
+            ADD CONSTRAINT "FK_d7374b7f8f5fbfdececa4fb62e1" FOREIGN KEY ("creator_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "templates"
+            ADD CONSTRAINT "FK_445d00eaaea0e60a017a5ed0c11" FOREIGN KEY ("source_guild_id") REFERENCES "guilds"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "guilds"
+            ADD CONSTRAINT "FK_f591a66b8019d87b0fe6c12dad6" FOREIGN KEY ("afk_channel_id") REFERENCES "channels"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "guilds"
+            ADD CONSTRAINT "FK_e2a2f873a64a5cf62526de42325" FOREIGN KEY ("template_id") REFERENCES "templates"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "guilds"
+            ADD CONSTRAINT "FK_fc1a451727e3643ca572a3bb394" FOREIGN KEY ("owner_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "guilds"
+            ADD CONSTRAINT "FK_8d450b016dc8bec35f36729e4b0" FOREIGN KEY ("public_updates_channel_id") REFERENCES "channels"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "guilds"
+            ADD CONSTRAINT "FK_95828668aa333460582e0ca6396" FOREIGN KEY ("rules_channel_id") REFERENCES "channels"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "guilds"
+            ADD CONSTRAINT "FK_cfc3d3ad260f8121c95b31a1fce" FOREIGN KEY ("system_channel_id") REFERENCES "channels"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "guilds"
+            ADD CONSTRAINT "FK_9d1d665379eefde7876a17afa99" FOREIGN KEY ("widget_channel_id") REFERENCES "channels"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "team_members"
+            ADD CONSTRAINT "FK_fdad7d5768277e60c40e01cdcea" FOREIGN KEY ("team_id") REFERENCES "teams"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "team_members"
+            ADD CONSTRAINT "FK_c2bf4967c8c2a6b845dadfbf3d4" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "teams"
+            ADD CONSTRAINT "FK_13f00abf7cb6096c43ecaf8c108" FOREIGN KEY ("owner_user_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD CONSTRAINT "FK_e57508958bf92b9d9d25231b5e8" FOREIGN KEY ("owner_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD CONSTRAINT "FK_a36ed02953077f408d0f3ebc424" FOREIGN KEY ("team_id") REFERENCES "teams"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD CONSTRAINT "FK_e5bf78cdbbe9ba91062d74c5aba" FOREIGN KEY ("guild_id") REFERENCES "guilds"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "audit_logs"
+            ADD CONSTRAINT "FK_3cd01cd3ae7aab010310d96ac8e" FOREIGN KEY ("target_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "audit_logs"
+            ADD CONSTRAINT "FK_bd2726fd31b35443f2245b93ba0" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "sessions"
+            ADD CONSTRAINT "FK_085d540d9f418cfbdc7bd55bb19" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "sticker_packs"
+            ADD CONSTRAINT "FK_448fafba4355ee1c837bbc865f1" FOREIGN KEY ("coverStickerId") REFERENCES "stickers"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "notes"
+            ADD CONSTRAINT "FK_f9e103f8ae67cb1787063597925" FOREIGN KEY ("owner_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "notes"
+            ADD CONSTRAINT "FK_23e08e5b4481711d573e1abecdc" FOREIGN KEY ("target_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "member_roles"
+            ADD CONSTRAINT "FK_5d7ddc8a5f9c167f548625e772e" FOREIGN KEY ("index") REFERENCES "members"("index") ON DELETE CASCADE ON UPDATE CASCADE
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "member_roles"
+            ADD CONSTRAINT "FK_e9080e7a7997a0170026d5139c1" FOREIGN KEY ("role_id") REFERENCES "roles"("id") ON DELETE CASCADE ON UPDATE CASCADE
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "message_user_mentions"
+            ADD CONSTRAINT "FK_a343387fc560ef378760681c236" FOREIGN KEY ("messagesId") REFERENCES "messages"("id") ON DELETE CASCADE ON UPDATE CASCADE
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "message_user_mentions"
+            ADD CONSTRAINT "FK_b831eb18ceebd28976239b1e2f8" FOREIGN KEY ("usersId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "message_role_mentions"
+            ADD CONSTRAINT "FK_a8242cf535337a490b0feaea0b4" FOREIGN KEY ("messagesId") REFERENCES "messages"("id") ON DELETE CASCADE ON UPDATE CASCADE
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "message_role_mentions"
+            ADD CONSTRAINT "FK_29d63eb1a458200851bc37d074b" FOREIGN KEY ("rolesId") REFERENCES "roles"("id") ON DELETE CASCADE ON UPDATE CASCADE
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "message_channel_mentions"
+            ADD CONSTRAINT "FK_2a27102ecd1d81b4582a4360921" FOREIGN KEY ("messagesId") REFERENCES "messages"("id") ON DELETE CASCADE ON UPDATE CASCADE
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "message_channel_mentions"
+            ADD CONSTRAINT "FK_bdb8c09e1464cabf62105bf4b9d" FOREIGN KEY ("channelsId") REFERENCES "channels"("id") ON DELETE CASCADE ON UPDATE CASCADE
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "message_stickers"
+            ADD CONSTRAINT "FK_40bb6f23e7cc133292e92829d28" FOREIGN KEY ("messagesId") REFERENCES "messages"("id") ON DELETE CASCADE ON UPDATE CASCADE
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "message_stickers"
+            ADD CONSTRAINT "FK_e22a70819d07659c7a71c112a1f" FOREIGN KEY ("stickersId") REFERENCES "stickers"("id") ON DELETE CASCADE ON UPDATE CASCADE
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "query-result-cache" (
+                "id" SERIAL NOT NULL,
+                "identifier" character varying,
+                "time" bigint NOT NULL,
+                "duration" integer NOT NULL,
+                "query" text NOT NULL,
+                "result" text NOT NULL,
+                CONSTRAINT "PK_6a98f758d8bfd010e7e10ffd3d3" PRIMARY KEY ("id")
+            )
+        `);
+	}
+
+	public async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            DROP TABLE "query-result-cache"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "message_stickers" DROP CONSTRAINT "FK_e22a70819d07659c7a71c112a1f"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "message_stickers" DROP CONSTRAINT "FK_40bb6f23e7cc133292e92829d28"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "message_channel_mentions" DROP CONSTRAINT "FK_bdb8c09e1464cabf62105bf4b9d"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "message_channel_mentions" DROP CONSTRAINT "FK_2a27102ecd1d81b4582a4360921"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "message_role_mentions" DROP CONSTRAINT "FK_29d63eb1a458200851bc37d074b"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "message_role_mentions" DROP CONSTRAINT "FK_a8242cf535337a490b0feaea0b4"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "message_user_mentions" DROP CONSTRAINT "FK_b831eb18ceebd28976239b1e2f8"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "message_user_mentions" DROP CONSTRAINT "FK_a343387fc560ef378760681c236"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "member_roles" DROP CONSTRAINT "FK_e9080e7a7997a0170026d5139c1"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "member_roles" DROP CONSTRAINT "FK_5d7ddc8a5f9c167f548625e772e"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "notes" DROP CONSTRAINT "FK_23e08e5b4481711d573e1abecdc"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "notes" DROP CONSTRAINT "FK_f9e103f8ae67cb1787063597925"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "sticker_packs" DROP CONSTRAINT "FK_448fafba4355ee1c837bbc865f1"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "sessions" DROP CONSTRAINT "FK_085d540d9f418cfbdc7bd55bb19"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "audit_logs" DROP CONSTRAINT "FK_bd2726fd31b35443f2245b93ba0"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "audit_logs" DROP CONSTRAINT "FK_3cd01cd3ae7aab010310d96ac8e"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP CONSTRAINT "FK_e5bf78cdbbe9ba91062d74c5aba"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP CONSTRAINT "FK_a36ed02953077f408d0f3ebc424"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP CONSTRAINT "FK_e57508958bf92b9d9d25231b5e8"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "teams" DROP CONSTRAINT "FK_13f00abf7cb6096c43ecaf8c108"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "team_members" DROP CONSTRAINT "FK_c2bf4967c8c2a6b845dadfbf3d4"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "team_members" DROP CONSTRAINT "FK_fdad7d5768277e60c40e01cdcea"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "guilds" DROP CONSTRAINT "FK_9d1d665379eefde7876a17afa99"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "guilds" DROP CONSTRAINT "FK_cfc3d3ad260f8121c95b31a1fce"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "guilds" DROP CONSTRAINT "FK_95828668aa333460582e0ca6396"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "guilds" DROP CONSTRAINT "FK_8d450b016dc8bec35f36729e4b0"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "guilds" DROP CONSTRAINT "FK_fc1a451727e3643ca572a3bb394"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "guilds" DROP CONSTRAINT "FK_e2a2f873a64a5cf62526de42325"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "guilds" DROP CONSTRAINT "FK_f591a66b8019d87b0fe6c12dad6"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "templates" DROP CONSTRAINT "FK_445d00eaaea0e60a017a5ed0c11"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "templates" DROP CONSTRAINT "FK_d7374b7f8f5fbfdececa4fb62e1"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "emojis" DROP CONSTRAINT "FK_fa7ddd5f9a214e28ce596548421"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "emojis" DROP CONSTRAINT "FK_4b988e0db89d94cebcf07f598cc"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "channels" DROP CONSTRAINT "FK_3873ed438575cce703ecff4fc7b"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "channels" DROP CONSTRAINT "FK_3274522d14af40540b1a883fc80"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "channels" DROP CONSTRAINT "FK_c253dafe5f3a03ec00cd8fb4581"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "voice_states" DROP CONSTRAINT "FK_5fe1d5f931a67e85039c640001b"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "voice_states" DROP CONSTRAINT "FK_9f8d389866b40b6657edd026dd4"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "voice_states" DROP CONSTRAINT "FK_03779ef216d4b0358470d9cb748"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "invites" DROP CONSTRAINT "FK_11a0d394f8fc649c19ce5f16b59"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "invites" DROP CONSTRAINT "FK_15c35422032e0b22b4ada95f48f"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "invites" DROP CONSTRAINT "FK_6a15b051fe5050aa00a4b9ff0f6"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "invites" DROP CONSTRAINT "FK_3f4939aa1461e8af57fea3fb05d"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "read_states" DROP CONSTRAINT "FK_195f92e4dd1254a4e348c043763"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "read_states" DROP CONSTRAINT "FK_40da2fca4e0eaf7a23b5bfc5d34"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "messages" DROP CONSTRAINT "FK_61a92bb65b302a76d9c1fcd3174"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "messages" DROP CONSTRAINT "FK_5d3ec1cb962de6488637fd779d6"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "messages" DROP CONSTRAINT "FK_f83c04bcf1df4e5c0e7a52ed348"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "messages" DROP CONSTRAINT "FK_b0525304f2262b7014245351c76"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "messages" DROP CONSTRAINT "FK_05535bc695e9f7ee104616459d3"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "messages" DROP CONSTRAINT "FK_b193588441b085352a4c0109423"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "messages" DROP CONSTRAINT "FK_86b9109b155eb70c0a2ca3b4b6d"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "attachments" DROP CONSTRAINT "FK_623e10eec51ada466c5038979e3"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "stickers" DROP CONSTRAINT "FK_8f4ee73f2bb2325ff980502e158"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "stickers" DROP CONSTRAINT "FK_193d551d852aca5347ef5c9f205"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "stickers" DROP CONSTRAINT "FK_e7cfa5cefa6661b3fb8fda8ce69"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "webhooks" DROP CONSTRAINT "FK_3a285f4f49c40e0706d3018bc9f"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "webhooks" DROP CONSTRAINT "FK_0d523f6f997c86e052c49b1455f"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "webhooks" DROP CONSTRAINT "FK_c3e5305461931763b56aa905f1c"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "webhooks" DROP CONSTRAINT "FK_df528cf77e82f8032230e7e37d8"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "webhooks" DROP CONSTRAINT "FK_487a7af59d189f744fe394368fc"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "members" DROP CONSTRAINT "FK_16aceddd5b89825b8ed6029ad1c"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "members" DROP CONSTRAINT "FK_28b53062261b996d9c99fa12404"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "roles" DROP CONSTRAINT "FK_c32c1ab1c4dc7dcb0278c4b1b8b"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "recipients" DROP CONSTRAINT "FK_6157e8b6ba4e6e3089616481fe2"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "recipients" DROP CONSTRAINT "FK_2f18ee1ba667f233ae86c0ea60e"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "bans" DROP CONSTRAINT "FK_07ad88c86d1f290d46748410d58"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "bans" DROP CONSTRAINT "FK_9d3ab7dd180ebdd245cdb66ecad"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "bans" DROP CONSTRAINT "FK_5999e8e449f80a236ff72023559"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "backup_codes" DROP CONSTRAINT "FK_70066ea80d2f4b871beda32633b"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "connected_accounts" DROP CONSTRAINT "FK_f47244225a6a1eac04a3463dd90"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "relationships" DROP CONSTRAINT "FK_9c7f6b98a9843b76dce1b0c878b"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "relationships" DROP CONSTRAINT "FK_9af4194bab1250b1c584ae4f1d7"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "public"."IDX_e22a70819d07659c7a71c112a1"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "public"."IDX_40bb6f23e7cc133292e92829d2"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "message_stickers"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "public"."IDX_bdb8c09e1464cabf62105bf4b9"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "public"."IDX_2a27102ecd1d81b4582a436092"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "message_channel_mentions"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "public"."IDX_29d63eb1a458200851bc37d074"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "public"."IDX_a8242cf535337a490b0feaea0b"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "message_role_mentions"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "public"."IDX_b831eb18ceebd28976239b1e2f"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "public"."IDX_a343387fc560ef378760681c23"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "message_user_mentions"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "public"."IDX_e9080e7a7997a0170026d5139c"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "public"."IDX_5d7ddc8a5f9c167f548625e772"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "member_roles"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "notes"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "client_release"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "sticker_packs"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "sessions"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "rate_limits"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "categories"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "audit_logs"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "applications"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "teams"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "team_members"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "guilds"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "templates"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "emojis"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "channels"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "voice_states"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "invites"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "public"."IDX_0abf8b443321bd3cf7f81ee17a"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "read_states"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "public"."IDX_3ed7a60fb7dbe04e1ba9332a8b"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "public"."IDX_05535bc695e9f7ee104616459d"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "public"."IDX_86b9109b155eb70c0a2ca3b4b6"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "messages"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "attachments"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "stickers"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "webhooks"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "public"."IDX_bb2bf9386ac443afbbbf9f12d3"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "members"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "roles"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "recipients"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "bans"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "backup_codes"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "users"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "connected_accounts"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "public"."IDX_a0b2ff0a598df0b0d055934a17"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "relationships"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "config"
+        `);
+	}
+}
diff --git a/src/util/migrations/postgres/1659921826567-premium_since_as_date.ts b/src/util/migrations/postgres/1659921826567-premium_since_as_date.ts
new file mode 100644
index 00000000..7543ce85
--- /dev/null
+++ b/src/util/migrations/postgres/1659921826567-premium_since_as_date.ts
@@ -0,0 +1,25 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class premiumSinceAsDate1659921826567 implements MigrationInterface {
+	name = "premiumSinceAsDate1659921826567";
+
+	public async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE "members" DROP COLUMN "premium_since"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "members"
+            ADD "premium_since" TIMESTAMP
+        `);
+	}
+
+	public async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE "members" DROP COLUMN "premium_since"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "members"
+            ADD "premium_since" bigint
+        `);
+	}
+}
diff --git a/src/util/migrations/postgres/1660130561959-updated-applications.ts b/src/util/migrations/postgres/1660130561959-updated-applications.ts
new file mode 100644
index 00000000..3d47d6d3
--- /dev/null
+++ b/src/util/migrations/postgres/1660130561959-updated-applications.ts
@@ -0,0 +1,181 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class updatedApplications1660130561959 implements MigrationInterface {
+	name = "updatedApplications1660130561959";
+
+	public async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP CONSTRAINT "FK_e5bf78cdbbe9ba91062d74c5aba"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP COLUMN "rpc_origins"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP COLUMN "primary_sku_id"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP COLUMN "slug"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP COLUMN "guild_id"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD "type" text
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD "hook" boolean NOT NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD "redirect_uris" text
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD "rpc_application_state" integer
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD "store_application_state" integer
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD "verification_state" integer
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD "interactions_endpoint_url" character varying
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD "integration_public" boolean
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD "integration_require_code_grant" boolean
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD "discoverability_state" integer
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD "discovery_eligibility_flags" integer
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD "tags" text
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD "install_params" text
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD "bot_user_id" character varying
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD CONSTRAINT "UQ_2ce5a55796fe4c2f77ece57a647" UNIQUE ("bot_user_id")
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ALTER COLUMN "description" DROP NOT NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP COLUMN "flags"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD "flags" integer NOT NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD CONSTRAINT "FK_2ce5a55796fe4c2f77ece57a647" FOREIGN KEY ("bot_user_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+	}
+
+	public async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP CONSTRAINT "FK_2ce5a55796fe4c2f77ece57a647"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP COLUMN "flags"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD "flags" character varying NOT NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ALTER COLUMN "description"
+            SET NOT NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP CONSTRAINT "UQ_2ce5a55796fe4c2f77ece57a647"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP COLUMN "bot_user_id"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP COLUMN "install_params"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP COLUMN "tags"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP COLUMN "discovery_eligibility_flags"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP COLUMN "discoverability_state"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP COLUMN "integration_require_code_grant"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP COLUMN "integration_public"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP COLUMN "interactions_endpoint_url"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP COLUMN "verification_state"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP COLUMN "store_application_state"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP COLUMN "rpc_application_state"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP COLUMN "redirect_uris"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP COLUMN "hook"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications" DROP COLUMN "type"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD "guild_id" character varying
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD "slug" character varying
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD "primary_sku_id" character varying
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD "rpc_origins" text
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+            ADD CONSTRAINT "FK_e5bf78cdbbe9ba91062d74c5aba" FOREIGN KEY ("guild_id") REFERENCES "guilds"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+	}
+}
diff --git a/src/util/migrations/postgres/1660257815436-CodeCleanup2.ts b/src/util/migrations/postgres/1660257815436-CodeCleanup2.ts
new file mode 100644
index 00000000..3e4167e9
--- /dev/null
+++ b/src/util/migrations/postgres/1660257815436-CodeCleanup2.ts
@@ -0,0 +1,58 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class CodeCleanup21660257815436 implements MigrationInterface {
+	name = "CodeCleanup21660257815436";
+
+	public async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            CREATE TABLE "user_settings" (
+                "id" character varying NOT NULL,
+                "afk_timeout" integer,
+                "allow_accessibility_detection" boolean,
+                "animate_emoji" boolean,
+                "animate_stickers" integer,
+                "contact_sync_enabled" boolean,
+                "convert_emoticons" boolean,
+                "custom_status" text,
+                "default_guilds_restricted" boolean,
+                "detect_platform_accounts" boolean,
+                "developer_mode" boolean,
+                "disable_games_tab" boolean,
+                "enable_tts_command" boolean,
+                "explicit_content_filter" integer,
+                "friend_source_flags" text,
+                "gateway_connected" boolean,
+                "gif_auto_play" boolean,
+                "guild_folders" text,
+                "guild_positions" text,
+                "inline_attachment_media" boolean,
+                "inline_embed_media" boolean,
+                "locale" character varying,
+                "message_display_compact" boolean,
+                "native_phone_integration_enabled" boolean,
+                "render_embeds" boolean,
+                "render_reactions" boolean,
+                "restricted_guilds" text,
+                "show_current_game" boolean,
+                "status" character varying,
+                "stream_notifications_enabled" boolean,
+                "theme" character varying,
+                "timezone_offset" integer,
+                CONSTRAINT "PK_00f004f5922a0744d174530d639" PRIMARY KEY ("id")
+            )
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "guilds"
+            ADD "premium_progress_bar_enabled" boolean
+        `);
+	}
+
+	public async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE "guilds" DROP COLUMN "premium_progress_bar_enabled"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "user_settings"
+        `);
+	}
+}
diff --git a/src/util/migrations/postgres/1660258372154-CodeCleanup3.ts b/src/util/migrations/postgres/1660258372154-CodeCleanup3.ts
new file mode 100644
index 00000000..3071b59f
--- /dev/null
+++ b/src/util/migrations/postgres/1660258372154-CodeCleanup3.ts
@@ -0,0 +1,18 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class CodeCleanup31660258372154 implements MigrationInterface {
+	name = "CodeCleanup31660258372154";
+
+	public async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE "users" DROP COLUMN "settings"
+        `);
+	}
+
+	public async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE "users"
+            ADD "settings" text NOT NULL
+        `);
+	}
+}
diff --git a/src/util/migrations/postgres/1660260565996-CodeCleanup4.ts b/src/util/migrations/postgres/1660260565996-CodeCleanup4.ts
new file mode 100644
index 00000000..c2e9aa85
--- /dev/null
+++ b/src/util/migrations/postgres/1660260565996-CodeCleanup4.ts
@@ -0,0 +1,32 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class CodeCleanup41660260565996 implements MigrationInterface {
+	name = "CodeCleanup41660260565996";
+
+	public async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE "users"
+            ADD "settingsId" character varying
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "users"
+            ADD CONSTRAINT "UQ_76ba283779c8441fd5ff819c8cf" UNIQUE ("settingsId")
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "users"
+            ADD CONSTRAINT "FK_76ba283779c8441fd5ff819c8cf" FOREIGN KEY ("settingsId") REFERENCES "user_settings"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+	}
+
+	public async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE "users" DROP CONSTRAINT "FK_76ba283779c8441fd5ff819c8cf"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "users" DROP CONSTRAINT "UQ_76ba283779c8441fd5ff819c8cf"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "users" DROP COLUMN "settingsId"
+        `);
+	}
+}
diff --git a/src/util/migrations/postgres/1660265907544-CodeCleanup5.ts b/src/util/migrations/postgres/1660265907544-CodeCleanup5.ts
new file mode 100644
index 00000000..0f098e1f
--- /dev/null
+++ b/src/util/migrations/postgres/1660265907544-CodeCleanup5.ts
@@ -0,0 +1,25 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class CodeCleanup51660265907544 implements MigrationInterface {
+	name = "CodeCleanup51660265907544";
+
+	public async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE "channels"
+            ADD "flags" integer
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "channels"
+            ADD "default_thread_rate_limit_per_user" integer
+        `);
+	}
+
+	public async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE "channels" DROP COLUMN "default_thread_rate_limit_per_user"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "channels" DROP COLUMN "flags"
+        `);
+	}
+}
diff --git a/src/util/migrations/postgres/1660416055566-InvitersAreDeletable.ts b/src/util/migrations/postgres/1660416055566-InvitersAreDeletable.ts
new file mode 100644
index 00000000..e8321ede
--- /dev/null
+++ b/src/util/migrations/postgres/1660416055566-InvitersAreDeletable.ts
@@ -0,0 +1,25 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class InvitersAreDeletable1660416055566 implements MigrationInterface {
+	name = "InvitersAreDeletable1660416055566";
+
+	public async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE "invites" DROP CONSTRAINT "FK_15c35422032e0b22b4ada95f48f"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "invites"
+            ADD CONSTRAINT "FK_15c35422032e0b22b4ada95f48f" FOREIGN KEY ("inviter_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+        `);
+	}
+
+	public async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE "invites" DROP CONSTRAINT "FK_15c35422032e0b22b4ada95f48f"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "invites"
+            ADD CONSTRAINT "FK_15c35422032e0b22b4ada95f48f" FOREIGN KEY ("inviter_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+        `);
+	}
+}
diff --git a/src/util/migrations/postgres/1660549242936-fix_nullables.ts b/src/util/migrations/postgres/1660549242936-fix_nullables.ts
new file mode 100644
index 00000000..07fd52f7
--- /dev/null
+++ b/src/util/migrations/postgres/1660549242936-fix_nullables.ts
@@ -0,0 +1,29 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class fixNullables1660549242936 implements MigrationInterface {
+	name = "fixNullables1660549242936";
+
+	public async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE "users"
+            ALTER COLUMN "bio" DROP NOT NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "users"
+            ALTER COLUMN "mfa_enabled" DROP NOT NULL
+        `);
+	}
+
+	public async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE "users"
+            ALTER COLUMN "mfa_enabled"
+            SET NOT NULL
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "users"
+            ALTER COLUMN "bio"
+            SET NOT NULL
+        `);
+	}
+}
diff --git a/src/util/migrations/sqlite/1659899662635-initial.ts b/src/util/migrations/sqlite/1659899662635-initial.ts
new file mode 100644
index 00000000..dffaa51d
--- /dev/null
+++ b/src/util/migrations/sqlite/1659899662635-initial.ts
@@ -0,0 +1,3528 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class initial1659899662635 implements MigrationInterface {
+	name = "initial1659899662635";
+
+	public async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            CREATE TABLE "config" ("key" varchar PRIMARY KEY NOT NULL, "value" text)
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "relationships" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "from_id" varchar NOT NULL,
+                "to_id" varchar NOT NULL,
+                "nickname" varchar,
+                "type" integer NOT NULL
+            )
+        `);
+		await queryRunner.query(`
+            CREATE UNIQUE INDEX "IDX_a0b2ff0a598df0b0d055934a17" ON "relationships" ("from_id", "to_id")
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "connected_accounts" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "user_id" varchar,
+                "access_token" varchar NOT NULL,
+                "friend_sync" boolean NOT NULL,
+                "name" varchar NOT NULL,
+                "revoked" boolean NOT NULL,
+                "show_activity" boolean NOT NULL,
+                "type" varchar NOT NULL,
+                "verified" boolean NOT NULL,
+                "visibility" integer NOT NULL
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "users" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "username" varchar NOT NULL,
+                "discriminator" varchar NOT NULL,
+                "avatar" varchar,
+                "accent_color" integer,
+                "banner" varchar,
+                "phone" varchar,
+                "desktop" boolean NOT NULL,
+                "mobile" boolean NOT NULL,
+                "premium" boolean NOT NULL,
+                "premium_type" integer NOT NULL,
+                "bot" boolean NOT NULL,
+                "bio" varchar NOT NULL,
+                "system" boolean NOT NULL,
+                "nsfw_allowed" boolean NOT NULL,
+                "mfa_enabled" boolean NOT NULL,
+                "totp_secret" varchar,
+                "totp_last_ticket" varchar,
+                "created_at" datetime NOT NULL,
+                "premium_since" datetime,
+                "verified" boolean NOT NULL,
+                "disabled" boolean NOT NULL,
+                "deleted" boolean NOT NULL,
+                "email" varchar,
+                "flags" varchar NOT NULL,
+                "public_flags" integer NOT NULL,
+                "rights" bigint NOT NULL,
+                "data" text NOT NULL,
+                "fingerprints" text NOT NULL,
+                "settings" text NOT NULL,
+                "extended_settings" text NOT NULL,
+                "notes" text NOT NULL
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "backup_codes" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "code" varchar NOT NULL,
+                "consumed" boolean NOT NULL,
+                "expired" boolean NOT NULL,
+                "user_id" varchar
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "bans" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "user_id" varchar,
+                "guild_id" varchar,
+                "executor_id" varchar,
+                "ip" varchar NOT NULL,
+                "reason" varchar
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "recipients" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "channel_id" varchar NOT NULL,
+                "user_id" varchar NOT NULL,
+                "closed" boolean NOT NULL DEFAULT (0)
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "roles" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "guild_id" varchar,
+                "color" integer NOT NULL,
+                "hoist" boolean NOT NULL,
+                "managed" boolean NOT NULL,
+                "mentionable" boolean NOT NULL,
+                "name" varchar NOT NULL,
+                "permissions" varchar NOT NULL,
+                "position" integer NOT NULL,
+                "icon" varchar,
+                "unicode_emoji" varchar,
+                "tags" text
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "members" (
+                "index" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
+                "id" varchar NOT NULL,
+                "guild_id" varchar NOT NULL,
+                "nick" varchar,
+                "joined_at" datetime NOT NULL,
+                "premium_since" bigint,
+                "deaf" boolean NOT NULL,
+                "mute" boolean NOT NULL,
+                "pending" boolean NOT NULL,
+                "settings" text NOT NULL,
+                "last_message_id" varchar,
+                "joined_by" varchar
+            )
+        `);
+		await queryRunner.query(`
+            CREATE UNIQUE INDEX "IDX_bb2bf9386ac443afbbbf9f12d3" ON "members" ("id", "guild_id")
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "webhooks" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "type" integer NOT NULL,
+                "name" varchar,
+                "avatar" varchar,
+                "token" varchar,
+                "guild_id" varchar,
+                "channel_id" varchar,
+                "application_id" varchar,
+                "user_id" varchar,
+                "source_guild_id" varchar
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "stickers" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "name" varchar NOT NULL,
+                "description" varchar,
+                "available" boolean,
+                "tags" varchar,
+                "pack_id" varchar,
+                "guild_id" varchar,
+                "user_id" varchar,
+                "type" integer NOT NULL,
+                "format_type" integer NOT NULL
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "attachments" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "filename" varchar NOT NULL,
+                "size" integer NOT NULL,
+                "url" varchar NOT NULL,
+                "proxy_url" varchar NOT NULL,
+                "height" integer,
+                "width" integer,
+                "content_type" varchar,
+                "message_id" varchar
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "messages" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "channel_id" varchar,
+                "guild_id" varchar,
+                "author_id" varchar,
+                "member_id" varchar,
+                "webhook_id" varchar,
+                "application_id" varchar,
+                "content" varchar,
+                "timestamp" datetime NOT NULL DEFAULT (datetime('now')),
+                "edited_timestamp" datetime,
+                "tts" boolean,
+                "mention_everyone" boolean,
+                "embeds" text NOT NULL,
+                "reactions" text NOT NULL,
+                "nonce" text,
+                "pinned" boolean,
+                "type" integer NOT NULL,
+                "activity" text,
+                "flags" varchar,
+                "message_reference" text,
+                "interaction" text,
+                "components" text,
+                "message_reference_id" varchar
+            )
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_86b9109b155eb70c0a2ca3b4b6" ON "messages" ("channel_id")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_05535bc695e9f7ee104616459d" ON "messages" ("author_id")
+        `);
+		await queryRunner.query(`
+            CREATE UNIQUE INDEX "IDX_3ed7a60fb7dbe04e1ba9332a8b" ON "messages" ("channel_id", "id")
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "read_states" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "channel_id" varchar NOT NULL,
+                "user_id" varchar NOT NULL,
+                "last_message_id" varchar,
+                "public_ack" varchar,
+                "notifications_cursor" varchar,
+                "last_pin_timestamp" datetime,
+                "mention_count" integer
+            )
+        `);
+		await queryRunner.query(`
+            CREATE UNIQUE INDEX "IDX_0abf8b443321bd3cf7f81ee17a" ON "read_states" ("channel_id", "user_id")
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "invites" (
+                "code" varchar PRIMARY KEY NOT NULL,
+                "temporary" boolean NOT NULL,
+                "uses" integer NOT NULL,
+                "max_uses" integer NOT NULL,
+                "max_age" integer NOT NULL,
+                "created_at" datetime NOT NULL,
+                "expires_at" datetime NOT NULL,
+                "guild_id" varchar,
+                "channel_id" varchar,
+                "inviter_id" varchar,
+                "target_user_id" varchar,
+                "target_user_type" integer,
+                "vanity_url" boolean
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "voice_states" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "guild_id" varchar,
+                "channel_id" varchar,
+                "user_id" varchar,
+                "session_id" varchar NOT NULL,
+                "token" varchar,
+                "deaf" boolean NOT NULL,
+                "mute" boolean NOT NULL,
+                "self_deaf" boolean NOT NULL,
+                "self_mute" boolean NOT NULL,
+                "self_stream" boolean,
+                "self_video" boolean NOT NULL,
+                "suppress" boolean NOT NULL,
+                "request_to_speak_timestamp" datetime
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "channels" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "created_at" datetime NOT NULL,
+                "name" varchar,
+                "icon" text,
+                "type" integer NOT NULL,
+                "last_message_id" varchar,
+                "guild_id" varchar,
+                "parent_id" varchar,
+                "owner_id" varchar,
+                "last_pin_timestamp" integer,
+                "default_auto_archive_duration" integer,
+                "position" integer,
+                "permission_overwrites" text,
+                "video_quality_mode" integer,
+                "bitrate" integer,
+                "user_limit" integer,
+                "nsfw" boolean,
+                "rate_limit_per_user" integer,
+                "topic" varchar,
+                "retention_policy_id" varchar
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "emojis" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "animated" boolean NOT NULL,
+                "available" boolean NOT NULL,
+                "guild_id" varchar NOT NULL,
+                "user_id" varchar,
+                "managed" boolean NOT NULL,
+                "name" varchar NOT NULL,
+                "require_colons" boolean NOT NULL,
+                "roles" text NOT NULL,
+                "groups" text
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "templates" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "code" varchar NOT NULL,
+                "name" varchar NOT NULL,
+                "description" varchar,
+                "usage_count" integer,
+                "creator_id" varchar,
+                "created_at" datetime NOT NULL,
+                "updated_at" datetime NOT NULL,
+                "source_guild_id" varchar,
+                "serialized_source_guild" text NOT NULL,
+                CONSTRAINT "UQ_be38737bf339baf63b1daeffb55" UNIQUE ("code")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "guilds" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "afk_channel_id" varchar,
+                "afk_timeout" integer,
+                "banner" varchar,
+                "default_message_notifications" integer,
+                "description" varchar,
+                "discovery_splash" varchar,
+                "explicit_content_filter" integer,
+                "features" text NOT NULL,
+                "primary_category_id" integer,
+                "icon" varchar,
+                "large" boolean,
+                "max_members" integer,
+                "max_presences" integer,
+                "max_video_channel_users" integer,
+                "member_count" integer,
+                "presence_count" integer,
+                "template_id" varchar,
+                "mfa_level" integer,
+                "name" varchar NOT NULL,
+                "owner_id" varchar,
+                "preferred_locale" varchar,
+                "premium_subscription_count" integer,
+                "premium_tier" integer,
+                "public_updates_channel_id" varchar,
+                "rules_channel_id" varchar,
+                "region" varchar,
+                "splash" varchar,
+                "system_channel_id" varchar,
+                "system_channel_flags" integer,
+                "unavailable" boolean,
+                "verification_level" integer,
+                "welcome_screen" text NOT NULL,
+                "widget_channel_id" varchar,
+                "widget_enabled" boolean,
+                "nsfw_level" integer,
+                "nsfw" boolean,
+                "parent" varchar
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "team_members" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "membership_state" integer NOT NULL,
+                "permissions" text NOT NULL,
+                "team_id" varchar,
+                "user_id" varchar
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "teams" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "icon" varchar,
+                "name" varchar NOT NULL,
+                "owner_user_id" varchar
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "applications" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "name" varchar NOT NULL,
+                "icon" varchar,
+                "description" varchar NOT NULL,
+                "rpc_origins" text,
+                "bot_public" boolean NOT NULL,
+                "bot_require_code_grant" boolean NOT NULL,
+                "terms_of_service_url" varchar,
+                "privacy_policy_url" varchar,
+                "summary" varchar,
+                "verify_key" varchar NOT NULL,
+                "primary_sku_id" varchar,
+                "slug" varchar,
+                "cover_image" varchar,
+                "flags" varchar NOT NULL,
+                "owner_id" varchar,
+                "team_id" varchar,
+                "guild_id" varchar
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "audit_logs" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "user_id" varchar,
+                "action_type" integer NOT NULL,
+                "options" text,
+                "changes" text NOT NULL,
+                "reason" varchar,
+                "target_id" varchar
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "categories" (
+                "id" integer PRIMARY KEY NOT NULL,
+                "name" varchar,
+                "localizations" text NOT NULL,
+                "is_primary" boolean
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "rate_limits" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "executor_id" varchar NOT NULL,
+                "hits" integer NOT NULL,
+                "blocked" boolean NOT NULL,
+                "expires_at" datetime NOT NULL
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "sessions" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "user_id" varchar,
+                "session_id" varchar NOT NULL,
+                "activities" text,
+                "client_info" text NOT NULL,
+                "status" varchar NOT NULL
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "sticker_packs" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "name" varchar NOT NULL,
+                "description" varchar,
+                "banner_asset_id" varchar,
+                "cover_sticker_id" varchar,
+                "coverStickerId" varchar
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "client_release" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "name" varchar NOT NULL,
+                "pub_date" varchar NOT NULL,
+                "url" varchar NOT NULL,
+                "deb_url" varchar NOT NULL,
+                "osx_url" varchar NOT NULL,
+                "win_url" varchar NOT NULL,
+                "notes" varchar
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "notes" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "content" varchar NOT NULL,
+                "owner_id" varchar,
+                "target_id" varchar,
+                CONSTRAINT "UQ_74e6689b9568cc965b8bfc9150b" UNIQUE ("owner_id", "target_id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "member_roles" (
+                "index" integer NOT NULL,
+                "role_id" varchar NOT NULL,
+                PRIMARY KEY ("index", "role_id")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_5d7ddc8a5f9c167f548625e772" ON "member_roles" ("index")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_e9080e7a7997a0170026d5139c" ON "member_roles" ("role_id")
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "message_user_mentions" (
+                "messagesId" varchar NOT NULL,
+                "usersId" varchar NOT NULL,
+                PRIMARY KEY ("messagesId", "usersId")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_a343387fc560ef378760681c23" ON "message_user_mentions" ("messagesId")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_b831eb18ceebd28976239b1e2f" ON "message_user_mentions" ("usersId")
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "message_role_mentions" (
+                "messagesId" varchar NOT NULL,
+                "rolesId" varchar NOT NULL,
+                PRIMARY KEY ("messagesId", "rolesId")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_a8242cf535337a490b0feaea0b" ON "message_role_mentions" ("messagesId")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_29d63eb1a458200851bc37d074" ON "message_role_mentions" ("rolesId")
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "message_channel_mentions" (
+                "messagesId" varchar NOT NULL,
+                "channelsId" varchar NOT NULL,
+                PRIMARY KEY ("messagesId", "channelsId")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_2a27102ecd1d81b4582a436092" ON "message_channel_mentions" ("messagesId")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_bdb8c09e1464cabf62105bf4b9" ON "message_channel_mentions" ("channelsId")
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "message_stickers" (
+                "messagesId" varchar NOT NULL,
+                "stickersId" varchar NOT NULL,
+                PRIMARY KEY ("messagesId", "stickersId")
+            )
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_40bb6f23e7cc133292e92829d2" ON "message_stickers" ("messagesId")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_e22a70819d07659c7a71c112a1" ON "message_stickers" ("stickersId")
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_a0b2ff0a598df0b0d055934a17"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_relationships" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "from_id" varchar NOT NULL,
+                "to_id" varchar NOT NULL,
+                "nickname" varchar,
+                "type" integer NOT NULL,
+                CONSTRAINT "FK_9af4194bab1250b1c584ae4f1d7" FOREIGN KEY ("from_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_9c7f6b98a9843b76dce1b0c878b" FOREIGN KEY ("to_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_relationships"("id", "from_id", "to_id", "nickname", "type")
+            SELECT "id",
+                "from_id",
+                "to_id",
+                "nickname",
+                "type"
+            FROM "relationships"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "relationships"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_relationships"
+                RENAME TO "relationships"
+        `);
+		await queryRunner.query(`
+            CREATE UNIQUE INDEX "IDX_a0b2ff0a598df0b0d055934a17" ON "relationships" ("from_id", "to_id")
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_connected_accounts" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "user_id" varchar,
+                "access_token" varchar NOT NULL,
+                "friend_sync" boolean NOT NULL,
+                "name" varchar NOT NULL,
+                "revoked" boolean NOT NULL,
+                "show_activity" boolean NOT NULL,
+                "type" varchar NOT NULL,
+                "verified" boolean NOT NULL,
+                "visibility" integer NOT NULL,
+                CONSTRAINT "FK_f47244225a6a1eac04a3463dd90" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_connected_accounts"(
+                    "id",
+                    "user_id",
+                    "access_token",
+                    "friend_sync",
+                    "name",
+                    "revoked",
+                    "show_activity",
+                    "type",
+                    "verified",
+                    "visibility"
+                )
+            SELECT "id",
+                "user_id",
+                "access_token",
+                "friend_sync",
+                "name",
+                "revoked",
+                "show_activity",
+                "type",
+                "verified",
+                "visibility"
+            FROM "connected_accounts"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "connected_accounts"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_connected_accounts"
+                RENAME TO "connected_accounts"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_backup_codes" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "code" varchar NOT NULL,
+                "consumed" boolean NOT NULL,
+                "expired" boolean NOT NULL,
+                "user_id" varchar,
+                CONSTRAINT "FK_70066ea80d2f4b871beda32633b" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_backup_codes"("id", "code", "consumed", "expired", "user_id")
+            SELECT "id",
+                "code",
+                "consumed",
+                "expired",
+                "user_id"
+            FROM "backup_codes"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "backup_codes"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_backup_codes"
+                RENAME TO "backup_codes"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_bans" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "user_id" varchar,
+                "guild_id" varchar,
+                "executor_id" varchar,
+                "ip" varchar NOT NULL,
+                "reason" varchar,
+                CONSTRAINT "FK_5999e8e449f80a236ff72023559" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_9d3ab7dd180ebdd245cdb66ecad" FOREIGN KEY ("guild_id") REFERENCES "guilds" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_07ad88c86d1f290d46748410d58" FOREIGN KEY ("executor_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_bans"(
+                    "id",
+                    "user_id",
+                    "guild_id",
+                    "executor_id",
+                    "ip",
+                    "reason"
+                )
+            SELECT "id",
+                "user_id",
+                "guild_id",
+                "executor_id",
+                "ip",
+                "reason"
+            FROM "bans"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "bans"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_bans"
+                RENAME TO "bans"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_recipients" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "channel_id" varchar NOT NULL,
+                "user_id" varchar NOT NULL,
+                "closed" boolean NOT NULL DEFAULT (0),
+                CONSTRAINT "FK_2f18ee1ba667f233ae86c0ea60e" FOREIGN KEY ("channel_id") REFERENCES "channels" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_6157e8b6ba4e6e3089616481fe2" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_recipients"("id", "channel_id", "user_id", "closed")
+            SELECT "id",
+                "channel_id",
+                "user_id",
+                "closed"
+            FROM "recipients"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "recipients"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_recipients"
+                RENAME TO "recipients"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_roles" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "guild_id" varchar,
+                "color" integer NOT NULL,
+                "hoist" boolean NOT NULL,
+                "managed" boolean NOT NULL,
+                "mentionable" boolean NOT NULL,
+                "name" varchar NOT NULL,
+                "permissions" varchar NOT NULL,
+                "position" integer NOT NULL,
+                "icon" varchar,
+                "unicode_emoji" varchar,
+                "tags" text,
+                CONSTRAINT "FK_c32c1ab1c4dc7dcb0278c4b1b8b" FOREIGN KEY ("guild_id") REFERENCES "guilds" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_roles"(
+                    "id",
+                    "guild_id",
+                    "color",
+                    "hoist",
+                    "managed",
+                    "mentionable",
+                    "name",
+                    "permissions",
+                    "position",
+                    "icon",
+                    "unicode_emoji",
+                    "tags"
+                )
+            SELECT "id",
+                "guild_id",
+                "color",
+                "hoist",
+                "managed",
+                "mentionable",
+                "name",
+                "permissions",
+                "position",
+                "icon",
+                "unicode_emoji",
+                "tags"
+            FROM "roles"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "roles"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_roles"
+                RENAME TO "roles"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_bb2bf9386ac443afbbbf9f12d3"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_members" (
+                "index" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
+                "id" varchar NOT NULL,
+                "guild_id" varchar NOT NULL,
+                "nick" varchar,
+                "joined_at" datetime NOT NULL,
+                "premium_since" bigint,
+                "deaf" boolean NOT NULL,
+                "mute" boolean NOT NULL,
+                "pending" boolean NOT NULL,
+                "settings" text NOT NULL,
+                "last_message_id" varchar,
+                "joined_by" varchar,
+                CONSTRAINT "FK_28b53062261b996d9c99fa12404" FOREIGN KEY ("id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_16aceddd5b89825b8ed6029ad1c" FOREIGN KEY ("guild_id") REFERENCES "guilds" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_members"(
+                    "index",
+                    "id",
+                    "guild_id",
+                    "nick",
+                    "joined_at",
+                    "premium_since",
+                    "deaf",
+                    "mute",
+                    "pending",
+                    "settings",
+                    "last_message_id",
+                    "joined_by"
+                )
+            SELECT "index",
+                "id",
+                "guild_id",
+                "nick",
+                "joined_at",
+                "premium_since",
+                "deaf",
+                "mute",
+                "pending",
+                "settings",
+                "last_message_id",
+                "joined_by"
+            FROM "members"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "members"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_members"
+                RENAME TO "members"
+        `);
+		await queryRunner.query(`
+            CREATE UNIQUE INDEX "IDX_bb2bf9386ac443afbbbf9f12d3" ON "members" ("id", "guild_id")
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_webhooks" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "type" integer NOT NULL,
+                "name" varchar,
+                "avatar" varchar,
+                "token" varchar,
+                "guild_id" varchar,
+                "channel_id" varchar,
+                "application_id" varchar,
+                "user_id" varchar,
+                "source_guild_id" varchar,
+                CONSTRAINT "FK_487a7af59d189f744fe394368fc" FOREIGN KEY ("guild_id") REFERENCES "guilds" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_df528cf77e82f8032230e7e37d8" FOREIGN KEY ("channel_id") REFERENCES "channels" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_c3e5305461931763b56aa905f1c" FOREIGN KEY ("application_id") REFERENCES "applications" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_0d523f6f997c86e052c49b1455f" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_3a285f4f49c40e0706d3018bc9f" FOREIGN KEY ("source_guild_id") REFERENCES "guilds" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_webhooks"(
+                    "id",
+                    "type",
+                    "name",
+                    "avatar",
+                    "token",
+                    "guild_id",
+                    "channel_id",
+                    "application_id",
+                    "user_id",
+                    "source_guild_id"
+                )
+            SELECT "id",
+                "type",
+                "name",
+                "avatar",
+                "token",
+                "guild_id",
+                "channel_id",
+                "application_id",
+                "user_id",
+                "source_guild_id"
+            FROM "webhooks"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "webhooks"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_webhooks"
+                RENAME TO "webhooks"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_stickers" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "name" varchar NOT NULL,
+                "description" varchar,
+                "available" boolean,
+                "tags" varchar,
+                "pack_id" varchar,
+                "guild_id" varchar,
+                "user_id" varchar,
+                "type" integer NOT NULL,
+                "format_type" integer NOT NULL,
+                CONSTRAINT "FK_e7cfa5cefa6661b3fb8fda8ce69" FOREIGN KEY ("pack_id") REFERENCES "sticker_packs" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_193d551d852aca5347ef5c9f205" FOREIGN KEY ("guild_id") REFERENCES "guilds" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_8f4ee73f2bb2325ff980502e158" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_stickers"(
+                    "id",
+                    "name",
+                    "description",
+                    "available",
+                    "tags",
+                    "pack_id",
+                    "guild_id",
+                    "user_id",
+                    "type",
+                    "format_type"
+                )
+            SELECT "id",
+                "name",
+                "description",
+                "available",
+                "tags",
+                "pack_id",
+                "guild_id",
+                "user_id",
+                "type",
+                "format_type"
+            FROM "stickers"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "stickers"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_stickers"
+                RENAME TO "stickers"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_attachments" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "filename" varchar NOT NULL,
+                "size" integer NOT NULL,
+                "url" varchar NOT NULL,
+                "proxy_url" varchar NOT NULL,
+                "height" integer,
+                "width" integer,
+                "content_type" varchar,
+                "message_id" varchar,
+                CONSTRAINT "FK_623e10eec51ada466c5038979e3" FOREIGN KEY ("message_id") REFERENCES "messages" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_attachments"(
+                    "id",
+                    "filename",
+                    "size",
+                    "url",
+                    "proxy_url",
+                    "height",
+                    "width",
+                    "content_type",
+                    "message_id"
+                )
+            SELECT "id",
+                "filename",
+                "size",
+                "url",
+                "proxy_url",
+                "height",
+                "width",
+                "content_type",
+                "message_id"
+            FROM "attachments"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "attachments"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_attachments"
+                RENAME TO "attachments"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_86b9109b155eb70c0a2ca3b4b6"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_05535bc695e9f7ee104616459d"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_3ed7a60fb7dbe04e1ba9332a8b"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_messages" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "channel_id" varchar,
+                "guild_id" varchar,
+                "author_id" varchar,
+                "member_id" varchar,
+                "webhook_id" varchar,
+                "application_id" varchar,
+                "content" varchar,
+                "timestamp" datetime NOT NULL DEFAULT (datetime('now')),
+                "edited_timestamp" datetime,
+                "tts" boolean,
+                "mention_everyone" boolean,
+                "embeds" text NOT NULL,
+                "reactions" text NOT NULL,
+                "nonce" text,
+                "pinned" boolean,
+                "type" integer NOT NULL,
+                "activity" text,
+                "flags" varchar,
+                "message_reference" text,
+                "interaction" text,
+                "components" text,
+                "message_reference_id" varchar,
+                CONSTRAINT "FK_86b9109b155eb70c0a2ca3b4b6d" FOREIGN KEY ("channel_id") REFERENCES "channels" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_b193588441b085352a4c0109423" FOREIGN KEY ("guild_id") REFERENCES "guilds" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_05535bc695e9f7ee104616459d3" FOREIGN KEY ("author_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_b0525304f2262b7014245351c76" FOREIGN KEY ("member_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_f83c04bcf1df4e5c0e7a52ed348" FOREIGN KEY ("webhook_id") REFERENCES "webhooks" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_5d3ec1cb962de6488637fd779d6" FOREIGN KEY ("application_id") REFERENCES "applications" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_61a92bb65b302a76d9c1fcd3174" FOREIGN KEY ("message_reference_id") REFERENCES "messages" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_messages"(
+                    "id",
+                    "channel_id",
+                    "guild_id",
+                    "author_id",
+                    "member_id",
+                    "webhook_id",
+                    "application_id",
+                    "content",
+                    "timestamp",
+                    "edited_timestamp",
+                    "tts",
+                    "mention_everyone",
+                    "embeds",
+                    "reactions",
+                    "nonce",
+                    "pinned",
+                    "type",
+                    "activity",
+                    "flags",
+                    "message_reference",
+                    "interaction",
+                    "components",
+                    "message_reference_id"
+                )
+            SELECT "id",
+                "channel_id",
+                "guild_id",
+                "author_id",
+                "member_id",
+                "webhook_id",
+                "application_id",
+                "content",
+                "timestamp",
+                "edited_timestamp",
+                "tts",
+                "mention_everyone",
+                "embeds",
+                "reactions",
+                "nonce",
+                "pinned",
+                "type",
+                "activity",
+                "flags",
+                "message_reference",
+                "interaction",
+                "components",
+                "message_reference_id"
+            FROM "messages"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "messages"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_messages"
+                RENAME TO "messages"
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_86b9109b155eb70c0a2ca3b4b6" ON "messages" ("channel_id")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_05535bc695e9f7ee104616459d" ON "messages" ("author_id")
+        `);
+		await queryRunner.query(`
+            CREATE UNIQUE INDEX "IDX_3ed7a60fb7dbe04e1ba9332a8b" ON "messages" ("channel_id", "id")
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_0abf8b443321bd3cf7f81ee17a"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_read_states" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "channel_id" varchar NOT NULL,
+                "user_id" varchar NOT NULL,
+                "last_message_id" varchar,
+                "public_ack" varchar,
+                "notifications_cursor" varchar,
+                "last_pin_timestamp" datetime,
+                "mention_count" integer,
+                CONSTRAINT "FK_40da2fca4e0eaf7a23b5bfc5d34" FOREIGN KEY ("channel_id") REFERENCES "channels" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_195f92e4dd1254a4e348c043763" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_read_states"(
+                    "id",
+                    "channel_id",
+                    "user_id",
+                    "last_message_id",
+                    "public_ack",
+                    "notifications_cursor",
+                    "last_pin_timestamp",
+                    "mention_count"
+                )
+            SELECT "id",
+                "channel_id",
+                "user_id",
+                "last_message_id",
+                "public_ack",
+                "notifications_cursor",
+                "last_pin_timestamp",
+                "mention_count"
+            FROM "read_states"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "read_states"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_read_states"
+                RENAME TO "read_states"
+        `);
+		await queryRunner.query(`
+            CREATE UNIQUE INDEX "IDX_0abf8b443321bd3cf7f81ee17a" ON "read_states" ("channel_id", "user_id")
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_invites" (
+                "code" varchar PRIMARY KEY NOT NULL,
+                "temporary" boolean NOT NULL,
+                "uses" integer NOT NULL,
+                "max_uses" integer NOT NULL,
+                "max_age" integer NOT NULL,
+                "created_at" datetime NOT NULL,
+                "expires_at" datetime NOT NULL,
+                "guild_id" varchar,
+                "channel_id" varchar,
+                "inviter_id" varchar,
+                "target_user_id" varchar,
+                "target_user_type" integer,
+                "vanity_url" boolean,
+                CONSTRAINT "FK_3f4939aa1461e8af57fea3fb05d" FOREIGN KEY ("guild_id") REFERENCES "guilds" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_6a15b051fe5050aa00a4b9ff0f6" FOREIGN KEY ("channel_id") REFERENCES "channels" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_15c35422032e0b22b4ada95f48f" FOREIGN KEY ("inviter_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_11a0d394f8fc649c19ce5f16b59" FOREIGN KEY ("target_user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_invites"(
+                    "code",
+                    "temporary",
+                    "uses",
+                    "max_uses",
+                    "max_age",
+                    "created_at",
+                    "expires_at",
+                    "guild_id",
+                    "channel_id",
+                    "inviter_id",
+                    "target_user_id",
+                    "target_user_type",
+                    "vanity_url"
+                )
+            SELECT "code",
+                "temporary",
+                "uses",
+                "max_uses",
+                "max_age",
+                "created_at",
+                "expires_at",
+                "guild_id",
+                "channel_id",
+                "inviter_id",
+                "target_user_id",
+                "target_user_type",
+                "vanity_url"
+            FROM "invites"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "invites"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_invites"
+                RENAME TO "invites"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_voice_states" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "guild_id" varchar,
+                "channel_id" varchar,
+                "user_id" varchar,
+                "session_id" varchar NOT NULL,
+                "token" varchar,
+                "deaf" boolean NOT NULL,
+                "mute" boolean NOT NULL,
+                "self_deaf" boolean NOT NULL,
+                "self_mute" boolean NOT NULL,
+                "self_stream" boolean,
+                "self_video" boolean NOT NULL,
+                "suppress" boolean NOT NULL,
+                "request_to_speak_timestamp" datetime,
+                CONSTRAINT "FK_03779ef216d4b0358470d9cb748" FOREIGN KEY ("guild_id") REFERENCES "guilds" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_9f8d389866b40b6657edd026dd4" FOREIGN KEY ("channel_id") REFERENCES "channels" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_5fe1d5f931a67e85039c640001b" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_voice_states"(
+                    "id",
+                    "guild_id",
+                    "channel_id",
+                    "user_id",
+                    "session_id",
+                    "token",
+                    "deaf",
+                    "mute",
+                    "self_deaf",
+                    "self_mute",
+                    "self_stream",
+                    "self_video",
+                    "suppress",
+                    "request_to_speak_timestamp"
+                )
+            SELECT "id",
+                "guild_id",
+                "channel_id",
+                "user_id",
+                "session_id",
+                "token",
+                "deaf",
+                "mute",
+                "self_deaf",
+                "self_mute",
+                "self_stream",
+                "self_video",
+                "suppress",
+                "request_to_speak_timestamp"
+            FROM "voice_states"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "voice_states"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_voice_states"
+                RENAME TO "voice_states"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_channels" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "created_at" datetime NOT NULL,
+                "name" varchar,
+                "icon" text,
+                "type" integer NOT NULL,
+                "last_message_id" varchar,
+                "guild_id" varchar,
+                "parent_id" varchar,
+                "owner_id" varchar,
+                "last_pin_timestamp" integer,
+                "default_auto_archive_duration" integer,
+                "position" integer,
+                "permission_overwrites" text,
+                "video_quality_mode" integer,
+                "bitrate" integer,
+                "user_limit" integer,
+                "nsfw" boolean,
+                "rate_limit_per_user" integer,
+                "topic" varchar,
+                "retention_policy_id" varchar,
+                CONSTRAINT "FK_c253dafe5f3a03ec00cd8fb4581" FOREIGN KEY ("guild_id") REFERENCES "guilds" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_3274522d14af40540b1a883fc80" FOREIGN KEY ("parent_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_3873ed438575cce703ecff4fc7b" FOREIGN KEY ("owner_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_channels"(
+                    "id",
+                    "created_at",
+                    "name",
+                    "icon",
+                    "type",
+                    "last_message_id",
+                    "guild_id",
+                    "parent_id",
+                    "owner_id",
+                    "last_pin_timestamp",
+                    "default_auto_archive_duration",
+                    "position",
+                    "permission_overwrites",
+                    "video_quality_mode",
+                    "bitrate",
+                    "user_limit",
+                    "nsfw",
+                    "rate_limit_per_user",
+                    "topic",
+                    "retention_policy_id"
+                )
+            SELECT "id",
+                "created_at",
+                "name",
+                "icon",
+                "type",
+                "last_message_id",
+                "guild_id",
+                "parent_id",
+                "owner_id",
+                "last_pin_timestamp",
+                "default_auto_archive_duration",
+                "position",
+                "permission_overwrites",
+                "video_quality_mode",
+                "bitrate",
+                "user_limit",
+                "nsfw",
+                "rate_limit_per_user",
+                "topic",
+                "retention_policy_id"
+            FROM "channels"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "channels"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_channels"
+                RENAME TO "channels"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_emojis" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "animated" boolean NOT NULL,
+                "available" boolean NOT NULL,
+                "guild_id" varchar NOT NULL,
+                "user_id" varchar,
+                "managed" boolean NOT NULL,
+                "name" varchar NOT NULL,
+                "require_colons" boolean NOT NULL,
+                "roles" text NOT NULL,
+                "groups" text,
+                CONSTRAINT "FK_4b988e0db89d94cebcf07f598cc" FOREIGN KEY ("guild_id") REFERENCES "guilds" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_fa7ddd5f9a214e28ce596548421" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_emojis"(
+                    "id",
+                    "animated",
+                    "available",
+                    "guild_id",
+                    "user_id",
+                    "managed",
+                    "name",
+                    "require_colons",
+                    "roles",
+                    "groups"
+                )
+            SELECT "id",
+                "animated",
+                "available",
+                "guild_id",
+                "user_id",
+                "managed",
+                "name",
+                "require_colons",
+                "roles",
+                "groups"
+            FROM "emojis"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "emojis"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_emojis"
+                RENAME TO "emojis"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_templates" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "code" varchar NOT NULL,
+                "name" varchar NOT NULL,
+                "description" varchar,
+                "usage_count" integer,
+                "creator_id" varchar,
+                "created_at" datetime NOT NULL,
+                "updated_at" datetime NOT NULL,
+                "source_guild_id" varchar,
+                "serialized_source_guild" text NOT NULL,
+                CONSTRAINT "UQ_be38737bf339baf63b1daeffb55" UNIQUE ("code"),
+                CONSTRAINT "FK_d7374b7f8f5fbfdececa4fb62e1" FOREIGN KEY ("creator_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_445d00eaaea0e60a017a5ed0c11" FOREIGN KEY ("source_guild_id") REFERENCES "guilds" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_templates"(
+                    "id",
+                    "code",
+                    "name",
+                    "description",
+                    "usage_count",
+                    "creator_id",
+                    "created_at",
+                    "updated_at",
+                    "source_guild_id",
+                    "serialized_source_guild"
+                )
+            SELECT "id",
+                "code",
+                "name",
+                "description",
+                "usage_count",
+                "creator_id",
+                "created_at",
+                "updated_at",
+                "source_guild_id",
+                "serialized_source_guild"
+            FROM "templates"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "templates"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_templates"
+                RENAME TO "templates"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_guilds" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "afk_channel_id" varchar,
+                "afk_timeout" integer,
+                "banner" varchar,
+                "default_message_notifications" integer,
+                "description" varchar,
+                "discovery_splash" varchar,
+                "explicit_content_filter" integer,
+                "features" text NOT NULL,
+                "primary_category_id" integer,
+                "icon" varchar,
+                "large" boolean,
+                "max_members" integer,
+                "max_presences" integer,
+                "max_video_channel_users" integer,
+                "member_count" integer,
+                "presence_count" integer,
+                "template_id" varchar,
+                "mfa_level" integer,
+                "name" varchar NOT NULL,
+                "owner_id" varchar,
+                "preferred_locale" varchar,
+                "premium_subscription_count" integer,
+                "premium_tier" integer,
+                "public_updates_channel_id" varchar,
+                "rules_channel_id" varchar,
+                "region" varchar,
+                "splash" varchar,
+                "system_channel_id" varchar,
+                "system_channel_flags" integer,
+                "unavailable" boolean,
+                "verification_level" integer,
+                "welcome_screen" text NOT NULL,
+                "widget_channel_id" varchar,
+                "widget_enabled" boolean,
+                "nsfw_level" integer,
+                "nsfw" boolean,
+                "parent" varchar,
+                CONSTRAINT "FK_f591a66b8019d87b0fe6c12dad6" FOREIGN KEY ("afk_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_e2a2f873a64a5cf62526de42325" FOREIGN KEY ("template_id") REFERENCES "templates" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_fc1a451727e3643ca572a3bb394" FOREIGN KEY ("owner_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_8d450b016dc8bec35f36729e4b0" FOREIGN KEY ("public_updates_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_95828668aa333460582e0ca6396" FOREIGN KEY ("rules_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_cfc3d3ad260f8121c95b31a1fce" FOREIGN KEY ("system_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_9d1d665379eefde7876a17afa99" FOREIGN KEY ("widget_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_guilds"(
+                    "id",
+                    "afk_channel_id",
+                    "afk_timeout",
+                    "banner",
+                    "default_message_notifications",
+                    "description",
+                    "discovery_splash",
+                    "explicit_content_filter",
+                    "features",
+                    "primary_category_id",
+                    "icon",
+                    "large",
+                    "max_members",
+                    "max_presences",
+                    "max_video_channel_users",
+                    "member_count",
+                    "presence_count",
+                    "template_id",
+                    "mfa_level",
+                    "name",
+                    "owner_id",
+                    "preferred_locale",
+                    "premium_subscription_count",
+                    "premium_tier",
+                    "public_updates_channel_id",
+                    "rules_channel_id",
+                    "region",
+                    "splash",
+                    "system_channel_id",
+                    "system_channel_flags",
+                    "unavailable",
+                    "verification_level",
+                    "welcome_screen",
+                    "widget_channel_id",
+                    "widget_enabled",
+                    "nsfw_level",
+                    "nsfw",
+                    "parent"
+                )
+            SELECT "id",
+                "afk_channel_id",
+                "afk_timeout",
+                "banner",
+                "default_message_notifications",
+                "description",
+                "discovery_splash",
+                "explicit_content_filter",
+                "features",
+                "primary_category_id",
+                "icon",
+                "large",
+                "max_members",
+                "max_presences",
+                "max_video_channel_users",
+                "member_count",
+                "presence_count",
+                "template_id",
+                "mfa_level",
+                "name",
+                "owner_id",
+                "preferred_locale",
+                "premium_subscription_count",
+                "premium_tier",
+                "public_updates_channel_id",
+                "rules_channel_id",
+                "region",
+                "splash",
+                "system_channel_id",
+                "system_channel_flags",
+                "unavailable",
+                "verification_level",
+                "welcome_screen",
+                "widget_channel_id",
+                "widget_enabled",
+                "nsfw_level",
+                "nsfw",
+                "parent"
+            FROM "guilds"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "guilds"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_guilds"
+                RENAME TO "guilds"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_team_members" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "membership_state" integer NOT NULL,
+                "permissions" text NOT NULL,
+                "team_id" varchar,
+                "user_id" varchar,
+                CONSTRAINT "FK_fdad7d5768277e60c40e01cdcea" FOREIGN KEY ("team_id") REFERENCES "teams" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_c2bf4967c8c2a6b845dadfbf3d4" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_team_members"(
+                    "id",
+                    "membership_state",
+                    "permissions",
+                    "team_id",
+                    "user_id"
+                )
+            SELECT "id",
+                "membership_state",
+                "permissions",
+                "team_id",
+                "user_id"
+            FROM "team_members"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "team_members"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_team_members"
+                RENAME TO "team_members"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_teams" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "icon" varchar,
+                "name" varchar NOT NULL,
+                "owner_user_id" varchar,
+                CONSTRAINT "FK_13f00abf7cb6096c43ecaf8c108" FOREIGN KEY ("owner_user_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_teams"("id", "icon", "name", "owner_user_id")
+            SELECT "id",
+                "icon",
+                "name",
+                "owner_user_id"
+            FROM "teams"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "teams"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_teams"
+                RENAME TO "teams"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_applications" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "name" varchar NOT NULL,
+                "icon" varchar,
+                "description" varchar NOT NULL,
+                "rpc_origins" text,
+                "bot_public" boolean NOT NULL,
+                "bot_require_code_grant" boolean NOT NULL,
+                "terms_of_service_url" varchar,
+                "privacy_policy_url" varchar,
+                "summary" varchar,
+                "verify_key" varchar NOT NULL,
+                "primary_sku_id" varchar,
+                "slug" varchar,
+                "cover_image" varchar,
+                "flags" varchar NOT NULL,
+                "owner_id" varchar,
+                "team_id" varchar,
+                "guild_id" varchar,
+                CONSTRAINT "FK_e57508958bf92b9d9d25231b5e8" FOREIGN KEY ("owner_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_a36ed02953077f408d0f3ebc424" FOREIGN KEY ("team_id") REFERENCES "teams" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_e5bf78cdbbe9ba91062d74c5aba" FOREIGN KEY ("guild_id") REFERENCES "guilds" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_applications"(
+                    "id",
+                    "name",
+                    "icon",
+                    "description",
+                    "rpc_origins",
+                    "bot_public",
+                    "bot_require_code_grant",
+                    "terms_of_service_url",
+                    "privacy_policy_url",
+                    "summary",
+                    "verify_key",
+                    "primary_sku_id",
+                    "slug",
+                    "cover_image",
+                    "flags",
+                    "owner_id",
+                    "team_id",
+                    "guild_id"
+                )
+            SELECT "id",
+                "name",
+                "icon",
+                "description",
+                "rpc_origins",
+                "bot_public",
+                "bot_require_code_grant",
+                "terms_of_service_url",
+                "privacy_policy_url",
+                "summary",
+                "verify_key",
+                "primary_sku_id",
+                "slug",
+                "cover_image",
+                "flags",
+                "owner_id",
+                "team_id",
+                "guild_id"
+            FROM "applications"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "applications"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_applications"
+                RENAME TO "applications"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_audit_logs" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "user_id" varchar,
+                "action_type" integer NOT NULL,
+                "options" text,
+                "changes" text NOT NULL,
+                "reason" varchar,
+                "target_id" varchar,
+                CONSTRAINT "FK_3cd01cd3ae7aab010310d96ac8e" FOREIGN KEY ("target_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_bd2726fd31b35443f2245b93ba0" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_audit_logs"(
+                    "id",
+                    "user_id",
+                    "action_type",
+                    "options",
+                    "changes",
+                    "reason",
+                    "target_id"
+                )
+            SELECT "id",
+                "user_id",
+                "action_type",
+                "options",
+                "changes",
+                "reason",
+                "target_id"
+            FROM "audit_logs"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "audit_logs"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_audit_logs"
+                RENAME TO "audit_logs"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_sessions" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "user_id" varchar,
+                "session_id" varchar NOT NULL,
+                "activities" text,
+                "client_info" text NOT NULL,
+                "status" varchar NOT NULL,
+                CONSTRAINT "FK_085d540d9f418cfbdc7bd55bb19" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_sessions"(
+                    "id",
+                    "user_id",
+                    "session_id",
+                    "activities",
+                    "client_info",
+                    "status"
+                )
+            SELECT "id",
+                "user_id",
+                "session_id",
+                "activities",
+                "client_info",
+                "status"
+            FROM "sessions"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "sessions"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_sessions"
+                RENAME TO "sessions"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_sticker_packs" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "name" varchar NOT NULL,
+                "description" varchar,
+                "banner_asset_id" varchar,
+                "cover_sticker_id" varchar,
+                "coverStickerId" varchar,
+                CONSTRAINT "FK_448fafba4355ee1c837bbc865f1" FOREIGN KEY ("coverStickerId") REFERENCES "stickers" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_sticker_packs"(
+                    "id",
+                    "name",
+                    "description",
+                    "banner_asset_id",
+                    "cover_sticker_id",
+                    "coverStickerId"
+                )
+            SELECT "id",
+                "name",
+                "description",
+                "banner_asset_id",
+                "cover_sticker_id",
+                "coverStickerId"
+            FROM "sticker_packs"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "sticker_packs"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_sticker_packs"
+                RENAME TO "sticker_packs"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_notes" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "content" varchar NOT NULL,
+                "owner_id" varchar,
+                "target_id" varchar,
+                CONSTRAINT "UQ_74e6689b9568cc965b8bfc9150b" UNIQUE ("owner_id", "target_id"),
+                CONSTRAINT "FK_f9e103f8ae67cb1787063597925" FOREIGN KEY ("owner_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_23e08e5b4481711d573e1abecdc" FOREIGN KEY ("target_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_notes"("id", "content", "owner_id", "target_id")
+            SELECT "id",
+                "content",
+                "owner_id",
+                "target_id"
+            FROM "notes"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "notes"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_notes"
+                RENAME TO "notes"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_5d7ddc8a5f9c167f548625e772"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_e9080e7a7997a0170026d5139c"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_member_roles" (
+                "index" integer NOT NULL,
+                "role_id" varchar NOT NULL,
+                CONSTRAINT "FK_5d7ddc8a5f9c167f548625e772e" FOREIGN KEY ("index") REFERENCES "members" ("index") ON DELETE CASCADE ON UPDATE CASCADE,
+                CONSTRAINT "FK_e9080e7a7997a0170026d5139c1" FOREIGN KEY ("role_id") REFERENCES "roles" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+                PRIMARY KEY ("index", "role_id")
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_member_roles"("index", "role_id")
+            SELECT "index",
+                "role_id"
+            FROM "member_roles"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "member_roles"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_member_roles"
+                RENAME TO "member_roles"
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_5d7ddc8a5f9c167f548625e772" ON "member_roles" ("index")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_e9080e7a7997a0170026d5139c" ON "member_roles" ("role_id")
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_a343387fc560ef378760681c23"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_b831eb18ceebd28976239b1e2f"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_message_user_mentions" (
+                "messagesId" varchar NOT NULL,
+                "usersId" varchar NOT NULL,
+                CONSTRAINT "FK_a343387fc560ef378760681c236" FOREIGN KEY ("messagesId") REFERENCES "messages" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+                CONSTRAINT "FK_b831eb18ceebd28976239b1e2f8" FOREIGN KEY ("usersId") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+                PRIMARY KEY ("messagesId", "usersId")
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_message_user_mentions"("messagesId", "usersId")
+            SELECT "messagesId",
+                "usersId"
+            FROM "message_user_mentions"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "message_user_mentions"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_message_user_mentions"
+                RENAME TO "message_user_mentions"
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_a343387fc560ef378760681c23" ON "message_user_mentions" ("messagesId")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_b831eb18ceebd28976239b1e2f" ON "message_user_mentions" ("usersId")
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_a8242cf535337a490b0feaea0b"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_29d63eb1a458200851bc37d074"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_message_role_mentions" (
+                "messagesId" varchar NOT NULL,
+                "rolesId" varchar NOT NULL,
+                CONSTRAINT "FK_a8242cf535337a490b0feaea0b4" FOREIGN KEY ("messagesId") REFERENCES "messages" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+                CONSTRAINT "FK_29d63eb1a458200851bc37d074b" FOREIGN KEY ("rolesId") REFERENCES "roles" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+                PRIMARY KEY ("messagesId", "rolesId")
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_message_role_mentions"("messagesId", "rolesId")
+            SELECT "messagesId",
+                "rolesId"
+            FROM "message_role_mentions"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "message_role_mentions"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_message_role_mentions"
+                RENAME TO "message_role_mentions"
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_a8242cf535337a490b0feaea0b" ON "message_role_mentions" ("messagesId")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_29d63eb1a458200851bc37d074" ON "message_role_mentions" ("rolesId")
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_2a27102ecd1d81b4582a436092"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_bdb8c09e1464cabf62105bf4b9"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_message_channel_mentions" (
+                "messagesId" varchar NOT NULL,
+                "channelsId" varchar NOT NULL,
+                CONSTRAINT "FK_2a27102ecd1d81b4582a4360921" FOREIGN KEY ("messagesId") REFERENCES "messages" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+                CONSTRAINT "FK_bdb8c09e1464cabf62105bf4b9d" FOREIGN KEY ("channelsId") REFERENCES "channels" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+                PRIMARY KEY ("messagesId", "channelsId")
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_message_channel_mentions"("messagesId", "channelsId")
+            SELECT "messagesId",
+                "channelsId"
+            FROM "message_channel_mentions"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "message_channel_mentions"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_message_channel_mentions"
+                RENAME TO "message_channel_mentions"
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_2a27102ecd1d81b4582a436092" ON "message_channel_mentions" ("messagesId")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_bdb8c09e1464cabf62105bf4b9" ON "message_channel_mentions" ("channelsId")
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_40bb6f23e7cc133292e92829d2"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_e22a70819d07659c7a71c112a1"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_message_stickers" (
+                "messagesId" varchar NOT NULL,
+                "stickersId" varchar NOT NULL,
+                CONSTRAINT "FK_40bb6f23e7cc133292e92829d28" FOREIGN KEY ("messagesId") REFERENCES "messages" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+                CONSTRAINT "FK_e22a70819d07659c7a71c112a1f" FOREIGN KEY ("stickersId") REFERENCES "stickers" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+                PRIMARY KEY ("messagesId", "stickersId")
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_message_stickers"("messagesId", "stickersId")
+            SELECT "messagesId",
+                "stickersId"
+            FROM "message_stickers"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "message_stickers"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_message_stickers"
+                RENAME TO "message_stickers"
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_40bb6f23e7cc133292e92829d2" ON "message_stickers" ("messagesId")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_e22a70819d07659c7a71c112a1" ON "message_stickers" ("stickersId")
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "query-result-cache" (
+                "id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
+                "identifier" varchar,
+                "time" bigint NOT NULL,
+                "duration" integer NOT NULL,
+                "query" text NOT NULL,
+                "result" text NOT NULL
+            )
+        `);
+	}
+
+	public async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            DROP TABLE "query-result-cache"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_e22a70819d07659c7a71c112a1"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_40bb6f23e7cc133292e92829d2"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "message_stickers"
+                RENAME TO "temporary_message_stickers"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "message_stickers" (
+                "messagesId" varchar NOT NULL,
+                "stickersId" varchar NOT NULL,
+                PRIMARY KEY ("messagesId", "stickersId")
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "message_stickers"("messagesId", "stickersId")
+            SELECT "messagesId",
+                "stickersId"
+            FROM "temporary_message_stickers"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_message_stickers"
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_e22a70819d07659c7a71c112a1" ON "message_stickers" ("stickersId")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_40bb6f23e7cc133292e92829d2" ON "message_stickers" ("messagesId")
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_bdb8c09e1464cabf62105bf4b9"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_2a27102ecd1d81b4582a436092"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "message_channel_mentions"
+                RENAME TO "temporary_message_channel_mentions"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "message_channel_mentions" (
+                "messagesId" varchar NOT NULL,
+                "channelsId" varchar NOT NULL,
+                PRIMARY KEY ("messagesId", "channelsId")
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "message_channel_mentions"("messagesId", "channelsId")
+            SELECT "messagesId",
+                "channelsId"
+            FROM "temporary_message_channel_mentions"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_message_channel_mentions"
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_bdb8c09e1464cabf62105bf4b9" ON "message_channel_mentions" ("channelsId")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_2a27102ecd1d81b4582a436092" ON "message_channel_mentions" ("messagesId")
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_29d63eb1a458200851bc37d074"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_a8242cf535337a490b0feaea0b"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "message_role_mentions"
+                RENAME TO "temporary_message_role_mentions"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "message_role_mentions" (
+                "messagesId" varchar NOT NULL,
+                "rolesId" varchar NOT NULL,
+                PRIMARY KEY ("messagesId", "rolesId")
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "message_role_mentions"("messagesId", "rolesId")
+            SELECT "messagesId",
+                "rolesId"
+            FROM "temporary_message_role_mentions"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_message_role_mentions"
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_29d63eb1a458200851bc37d074" ON "message_role_mentions" ("rolesId")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_a8242cf535337a490b0feaea0b" ON "message_role_mentions" ("messagesId")
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_b831eb18ceebd28976239b1e2f"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_a343387fc560ef378760681c23"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "message_user_mentions"
+                RENAME TO "temporary_message_user_mentions"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "message_user_mentions" (
+                "messagesId" varchar NOT NULL,
+                "usersId" varchar NOT NULL,
+                PRIMARY KEY ("messagesId", "usersId")
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "message_user_mentions"("messagesId", "usersId")
+            SELECT "messagesId",
+                "usersId"
+            FROM "temporary_message_user_mentions"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_message_user_mentions"
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_b831eb18ceebd28976239b1e2f" ON "message_user_mentions" ("usersId")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_a343387fc560ef378760681c23" ON "message_user_mentions" ("messagesId")
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_e9080e7a7997a0170026d5139c"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_5d7ddc8a5f9c167f548625e772"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "member_roles"
+                RENAME TO "temporary_member_roles"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "member_roles" (
+                "index" integer NOT NULL,
+                "role_id" varchar NOT NULL,
+                PRIMARY KEY ("index", "role_id")
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "member_roles"("index", "role_id")
+            SELECT "index",
+                "role_id"
+            FROM "temporary_member_roles"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_member_roles"
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_e9080e7a7997a0170026d5139c" ON "member_roles" ("role_id")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_5d7ddc8a5f9c167f548625e772" ON "member_roles" ("index")
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "notes"
+                RENAME TO "temporary_notes"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "notes" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "content" varchar NOT NULL,
+                "owner_id" varchar,
+                "target_id" varchar,
+                CONSTRAINT "UQ_74e6689b9568cc965b8bfc9150b" UNIQUE ("owner_id", "target_id")
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "notes"("id", "content", "owner_id", "target_id")
+            SELECT "id",
+                "content",
+                "owner_id",
+                "target_id"
+            FROM "temporary_notes"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_notes"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "sticker_packs"
+                RENAME TO "temporary_sticker_packs"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "sticker_packs" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "name" varchar NOT NULL,
+                "description" varchar,
+                "banner_asset_id" varchar,
+                "cover_sticker_id" varchar,
+                "coverStickerId" varchar
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "sticker_packs"(
+                    "id",
+                    "name",
+                    "description",
+                    "banner_asset_id",
+                    "cover_sticker_id",
+                    "coverStickerId"
+                )
+            SELECT "id",
+                "name",
+                "description",
+                "banner_asset_id",
+                "cover_sticker_id",
+                "coverStickerId"
+            FROM "temporary_sticker_packs"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_sticker_packs"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "sessions"
+                RENAME TO "temporary_sessions"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "sessions" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "user_id" varchar,
+                "session_id" varchar NOT NULL,
+                "activities" text,
+                "client_info" text NOT NULL,
+                "status" varchar NOT NULL
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "sessions"(
+                    "id",
+                    "user_id",
+                    "session_id",
+                    "activities",
+                    "client_info",
+                    "status"
+                )
+            SELECT "id",
+                "user_id",
+                "session_id",
+                "activities",
+                "client_info",
+                "status"
+            FROM "temporary_sessions"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_sessions"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "audit_logs"
+                RENAME TO "temporary_audit_logs"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "audit_logs" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "user_id" varchar,
+                "action_type" integer NOT NULL,
+                "options" text,
+                "changes" text NOT NULL,
+                "reason" varchar,
+                "target_id" varchar
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "audit_logs"(
+                    "id",
+                    "user_id",
+                    "action_type",
+                    "options",
+                    "changes",
+                    "reason",
+                    "target_id"
+                )
+            SELECT "id",
+                "user_id",
+                "action_type",
+                "options",
+                "changes",
+                "reason",
+                "target_id"
+            FROM "temporary_audit_logs"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_audit_logs"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+                RENAME TO "temporary_applications"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "applications" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "name" varchar NOT NULL,
+                "icon" varchar,
+                "description" varchar NOT NULL,
+                "rpc_origins" text,
+                "bot_public" boolean NOT NULL,
+                "bot_require_code_grant" boolean NOT NULL,
+                "terms_of_service_url" varchar,
+                "privacy_policy_url" varchar,
+                "summary" varchar,
+                "verify_key" varchar NOT NULL,
+                "primary_sku_id" varchar,
+                "slug" varchar,
+                "cover_image" varchar,
+                "flags" varchar NOT NULL,
+                "owner_id" varchar,
+                "team_id" varchar,
+                "guild_id" varchar
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "applications"(
+                    "id",
+                    "name",
+                    "icon",
+                    "description",
+                    "rpc_origins",
+                    "bot_public",
+                    "bot_require_code_grant",
+                    "terms_of_service_url",
+                    "privacy_policy_url",
+                    "summary",
+                    "verify_key",
+                    "primary_sku_id",
+                    "slug",
+                    "cover_image",
+                    "flags",
+                    "owner_id",
+                    "team_id",
+                    "guild_id"
+                )
+            SELECT "id",
+                "name",
+                "icon",
+                "description",
+                "rpc_origins",
+                "bot_public",
+                "bot_require_code_grant",
+                "terms_of_service_url",
+                "privacy_policy_url",
+                "summary",
+                "verify_key",
+                "primary_sku_id",
+                "slug",
+                "cover_image",
+                "flags",
+                "owner_id",
+                "team_id",
+                "guild_id"
+            FROM "temporary_applications"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_applications"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "teams"
+                RENAME TO "temporary_teams"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "teams" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "icon" varchar,
+                "name" varchar NOT NULL,
+                "owner_user_id" varchar
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "teams"("id", "icon", "name", "owner_user_id")
+            SELECT "id",
+                "icon",
+                "name",
+                "owner_user_id"
+            FROM "temporary_teams"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_teams"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "team_members"
+                RENAME TO "temporary_team_members"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "team_members" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "membership_state" integer NOT NULL,
+                "permissions" text NOT NULL,
+                "team_id" varchar,
+                "user_id" varchar
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "team_members"(
+                    "id",
+                    "membership_state",
+                    "permissions",
+                    "team_id",
+                    "user_id"
+                )
+            SELECT "id",
+                "membership_state",
+                "permissions",
+                "team_id",
+                "user_id"
+            FROM "temporary_team_members"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_team_members"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "guilds"
+                RENAME TO "temporary_guilds"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "guilds" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "afk_channel_id" varchar,
+                "afk_timeout" integer,
+                "banner" varchar,
+                "default_message_notifications" integer,
+                "description" varchar,
+                "discovery_splash" varchar,
+                "explicit_content_filter" integer,
+                "features" text NOT NULL,
+                "primary_category_id" integer,
+                "icon" varchar,
+                "large" boolean,
+                "max_members" integer,
+                "max_presences" integer,
+                "max_video_channel_users" integer,
+                "member_count" integer,
+                "presence_count" integer,
+                "template_id" varchar,
+                "mfa_level" integer,
+                "name" varchar NOT NULL,
+                "owner_id" varchar,
+                "preferred_locale" varchar,
+                "premium_subscription_count" integer,
+                "premium_tier" integer,
+                "public_updates_channel_id" varchar,
+                "rules_channel_id" varchar,
+                "region" varchar,
+                "splash" varchar,
+                "system_channel_id" varchar,
+                "system_channel_flags" integer,
+                "unavailable" boolean,
+                "verification_level" integer,
+                "welcome_screen" text NOT NULL,
+                "widget_channel_id" varchar,
+                "widget_enabled" boolean,
+                "nsfw_level" integer,
+                "nsfw" boolean,
+                "parent" varchar
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "guilds"(
+                    "id",
+                    "afk_channel_id",
+                    "afk_timeout",
+                    "banner",
+                    "default_message_notifications",
+                    "description",
+                    "discovery_splash",
+                    "explicit_content_filter",
+                    "features",
+                    "primary_category_id",
+                    "icon",
+                    "large",
+                    "max_members",
+                    "max_presences",
+                    "max_video_channel_users",
+                    "member_count",
+                    "presence_count",
+                    "template_id",
+                    "mfa_level",
+                    "name",
+                    "owner_id",
+                    "preferred_locale",
+                    "premium_subscription_count",
+                    "premium_tier",
+                    "public_updates_channel_id",
+                    "rules_channel_id",
+                    "region",
+                    "splash",
+                    "system_channel_id",
+                    "system_channel_flags",
+                    "unavailable",
+                    "verification_level",
+                    "welcome_screen",
+                    "widget_channel_id",
+                    "widget_enabled",
+                    "nsfw_level",
+                    "nsfw",
+                    "parent"
+                )
+            SELECT "id",
+                "afk_channel_id",
+                "afk_timeout",
+                "banner",
+                "default_message_notifications",
+                "description",
+                "discovery_splash",
+                "explicit_content_filter",
+                "features",
+                "primary_category_id",
+                "icon",
+                "large",
+                "max_members",
+                "max_presences",
+                "max_video_channel_users",
+                "member_count",
+                "presence_count",
+                "template_id",
+                "mfa_level",
+                "name",
+                "owner_id",
+                "preferred_locale",
+                "premium_subscription_count",
+                "premium_tier",
+                "public_updates_channel_id",
+                "rules_channel_id",
+                "region",
+                "splash",
+                "system_channel_id",
+                "system_channel_flags",
+                "unavailable",
+                "verification_level",
+                "welcome_screen",
+                "widget_channel_id",
+                "widget_enabled",
+                "nsfw_level",
+                "nsfw",
+                "parent"
+            FROM "temporary_guilds"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_guilds"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "templates"
+                RENAME TO "temporary_templates"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "templates" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "code" varchar NOT NULL,
+                "name" varchar NOT NULL,
+                "description" varchar,
+                "usage_count" integer,
+                "creator_id" varchar,
+                "created_at" datetime NOT NULL,
+                "updated_at" datetime NOT NULL,
+                "source_guild_id" varchar,
+                "serialized_source_guild" text NOT NULL,
+                CONSTRAINT "UQ_be38737bf339baf63b1daeffb55" UNIQUE ("code")
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "templates"(
+                    "id",
+                    "code",
+                    "name",
+                    "description",
+                    "usage_count",
+                    "creator_id",
+                    "created_at",
+                    "updated_at",
+                    "source_guild_id",
+                    "serialized_source_guild"
+                )
+            SELECT "id",
+                "code",
+                "name",
+                "description",
+                "usage_count",
+                "creator_id",
+                "created_at",
+                "updated_at",
+                "source_guild_id",
+                "serialized_source_guild"
+            FROM "temporary_templates"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_templates"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "emojis"
+                RENAME TO "temporary_emojis"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "emojis" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "animated" boolean NOT NULL,
+                "available" boolean NOT NULL,
+                "guild_id" varchar NOT NULL,
+                "user_id" varchar,
+                "managed" boolean NOT NULL,
+                "name" varchar NOT NULL,
+                "require_colons" boolean NOT NULL,
+                "roles" text NOT NULL,
+                "groups" text
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "emojis"(
+                    "id",
+                    "animated",
+                    "available",
+                    "guild_id",
+                    "user_id",
+                    "managed",
+                    "name",
+                    "require_colons",
+                    "roles",
+                    "groups"
+                )
+            SELECT "id",
+                "animated",
+                "available",
+                "guild_id",
+                "user_id",
+                "managed",
+                "name",
+                "require_colons",
+                "roles",
+                "groups"
+            FROM "temporary_emojis"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_emojis"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "channels"
+                RENAME TO "temporary_channels"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "channels" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "created_at" datetime NOT NULL,
+                "name" varchar,
+                "icon" text,
+                "type" integer NOT NULL,
+                "last_message_id" varchar,
+                "guild_id" varchar,
+                "parent_id" varchar,
+                "owner_id" varchar,
+                "last_pin_timestamp" integer,
+                "default_auto_archive_duration" integer,
+                "position" integer,
+                "permission_overwrites" text,
+                "video_quality_mode" integer,
+                "bitrate" integer,
+                "user_limit" integer,
+                "nsfw" boolean,
+                "rate_limit_per_user" integer,
+                "topic" varchar,
+                "retention_policy_id" varchar
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "channels"(
+                    "id",
+                    "created_at",
+                    "name",
+                    "icon",
+                    "type",
+                    "last_message_id",
+                    "guild_id",
+                    "parent_id",
+                    "owner_id",
+                    "last_pin_timestamp",
+                    "default_auto_archive_duration",
+                    "position",
+                    "permission_overwrites",
+                    "video_quality_mode",
+                    "bitrate",
+                    "user_limit",
+                    "nsfw",
+                    "rate_limit_per_user",
+                    "topic",
+                    "retention_policy_id"
+                )
+            SELECT "id",
+                "created_at",
+                "name",
+                "icon",
+                "type",
+                "last_message_id",
+                "guild_id",
+                "parent_id",
+                "owner_id",
+                "last_pin_timestamp",
+                "default_auto_archive_duration",
+                "position",
+                "permission_overwrites",
+                "video_quality_mode",
+                "bitrate",
+                "user_limit",
+                "nsfw",
+                "rate_limit_per_user",
+                "topic",
+                "retention_policy_id"
+            FROM "temporary_channels"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_channels"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "voice_states"
+                RENAME TO "temporary_voice_states"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "voice_states" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "guild_id" varchar,
+                "channel_id" varchar,
+                "user_id" varchar,
+                "session_id" varchar NOT NULL,
+                "token" varchar,
+                "deaf" boolean NOT NULL,
+                "mute" boolean NOT NULL,
+                "self_deaf" boolean NOT NULL,
+                "self_mute" boolean NOT NULL,
+                "self_stream" boolean,
+                "self_video" boolean NOT NULL,
+                "suppress" boolean NOT NULL,
+                "request_to_speak_timestamp" datetime
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "voice_states"(
+                    "id",
+                    "guild_id",
+                    "channel_id",
+                    "user_id",
+                    "session_id",
+                    "token",
+                    "deaf",
+                    "mute",
+                    "self_deaf",
+                    "self_mute",
+                    "self_stream",
+                    "self_video",
+                    "suppress",
+                    "request_to_speak_timestamp"
+                )
+            SELECT "id",
+                "guild_id",
+                "channel_id",
+                "user_id",
+                "session_id",
+                "token",
+                "deaf",
+                "mute",
+                "self_deaf",
+                "self_mute",
+                "self_stream",
+                "self_video",
+                "suppress",
+                "request_to_speak_timestamp"
+            FROM "temporary_voice_states"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_voice_states"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "invites"
+                RENAME TO "temporary_invites"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "invites" (
+                "code" varchar PRIMARY KEY NOT NULL,
+                "temporary" boolean NOT NULL,
+                "uses" integer NOT NULL,
+                "max_uses" integer NOT NULL,
+                "max_age" integer NOT NULL,
+                "created_at" datetime NOT NULL,
+                "expires_at" datetime NOT NULL,
+                "guild_id" varchar,
+                "channel_id" varchar,
+                "inviter_id" varchar,
+                "target_user_id" varchar,
+                "target_user_type" integer,
+                "vanity_url" boolean
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "invites"(
+                    "code",
+                    "temporary",
+                    "uses",
+                    "max_uses",
+                    "max_age",
+                    "created_at",
+                    "expires_at",
+                    "guild_id",
+                    "channel_id",
+                    "inviter_id",
+                    "target_user_id",
+                    "target_user_type",
+                    "vanity_url"
+                )
+            SELECT "code",
+                "temporary",
+                "uses",
+                "max_uses",
+                "max_age",
+                "created_at",
+                "expires_at",
+                "guild_id",
+                "channel_id",
+                "inviter_id",
+                "target_user_id",
+                "target_user_type",
+                "vanity_url"
+            FROM "temporary_invites"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_invites"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_0abf8b443321bd3cf7f81ee17a"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "read_states"
+                RENAME TO "temporary_read_states"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "read_states" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "channel_id" varchar NOT NULL,
+                "user_id" varchar NOT NULL,
+                "last_message_id" varchar,
+                "public_ack" varchar,
+                "notifications_cursor" varchar,
+                "last_pin_timestamp" datetime,
+                "mention_count" integer
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "read_states"(
+                    "id",
+                    "channel_id",
+                    "user_id",
+                    "last_message_id",
+                    "public_ack",
+                    "notifications_cursor",
+                    "last_pin_timestamp",
+                    "mention_count"
+                )
+            SELECT "id",
+                "channel_id",
+                "user_id",
+                "last_message_id",
+                "public_ack",
+                "notifications_cursor",
+                "last_pin_timestamp",
+                "mention_count"
+            FROM "temporary_read_states"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_read_states"
+        `);
+		await queryRunner.query(`
+            CREATE UNIQUE INDEX "IDX_0abf8b443321bd3cf7f81ee17a" ON "read_states" ("channel_id", "user_id")
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_3ed7a60fb7dbe04e1ba9332a8b"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_05535bc695e9f7ee104616459d"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_86b9109b155eb70c0a2ca3b4b6"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "messages"
+                RENAME TO "temporary_messages"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "messages" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "channel_id" varchar,
+                "guild_id" varchar,
+                "author_id" varchar,
+                "member_id" varchar,
+                "webhook_id" varchar,
+                "application_id" varchar,
+                "content" varchar,
+                "timestamp" datetime NOT NULL DEFAULT (datetime('now')),
+                "edited_timestamp" datetime,
+                "tts" boolean,
+                "mention_everyone" boolean,
+                "embeds" text NOT NULL,
+                "reactions" text NOT NULL,
+                "nonce" text,
+                "pinned" boolean,
+                "type" integer NOT NULL,
+                "activity" text,
+                "flags" varchar,
+                "message_reference" text,
+                "interaction" text,
+                "components" text,
+                "message_reference_id" varchar
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "messages"(
+                    "id",
+                    "channel_id",
+                    "guild_id",
+                    "author_id",
+                    "member_id",
+                    "webhook_id",
+                    "application_id",
+                    "content",
+                    "timestamp",
+                    "edited_timestamp",
+                    "tts",
+                    "mention_everyone",
+                    "embeds",
+                    "reactions",
+                    "nonce",
+                    "pinned",
+                    "type",
+                    "activity",
+                    "flags",
+                    "message_reference",
+                    "interaction",
+                    "components",
+                    "message_reference_id"
+                )
+            SELECT "id",
+                "channel_id",
+                "guild_id",
+                "author_id",
+                "member_id",
+                "webhook_id",
+                "application_id",
+                "content",
+                "timestamp",
+                "edited_timestamp",
+                "tts",
+                "mention_everyone",
+                "embeds",
+                "reactions",
+                "nonce",
+                "pinned",
+                "type",
+                "activity",
+                "flags",
+                "message_reference",
+                "interaction",
+                "components",
+                "message_reference_id"
+            FROM "temporary_messages"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_messages"
+        `);
+		await queryRunner.query(`
+            CREATE UNIQUE INDEX "IDX_3ed7a60fb7dbe04e1ba9332a8b" ON "messages" ("channel_id", "id")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_05535bc695e9f7ee104616459d" ON "messages" ("author_id")
+        `);
+		await queryRunner.query(`
+            CREATE INDEX "IDX_86b9109b155eb70c0a2ca3b4b6" ON "messages" ("channel_id")
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "attachments"
+                RENAME TO "temporary_attachments"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "attachments" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "filename" varchar NOT NULL,
+                "size" integer NOT NULL,
+                "url" varchar NOT NULL,
+                "proxy_url" varchar NOT NULL,
+                "height" integer,
+                "width" integer,
+                "content_type" varchar,
+                "message_id" varchar
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "attachments"(
+                    "id",
+                    "filename",
+                    "size",
+                    "url",
+                    "proxy_url",
+                    "height",
+                    "width",
+                    "content_type",
+                    "message_id"
+                )
+            SELECT "id",
+                "filename",
+                "size",
+                "url",
+                "proxy_url",
+                "height",
+                "width",
+                "content_type",
+                "message_id"
+            FROM "temporary_attachments"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_attachments"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "stickers"
+                RENAME TO "temporary_stickers"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "stickers" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "name" varchar NOT NULL,
+                "description" varchar,
+                "available" boolean,
+                "tags" varchar,
+                "pack_id" varchar,
+                "guild_id" varchar,
+                "user_id" varchar,
+                "type" integer NOT NULL,
+                "format_type" integer NOT NULL
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "stickers"(
+                    "id",
+                    "name",
+                    "description",
+                    "available",
+                    "tags",
+                    "pack_id",
+                    "guild_id",
+                    "user_id",
+                    "type",
+                    "format_type"
+                )
+            SELECT "id",
+                "name",
+                "description",
+                "available",
+                "tags",
+                "pack_id",
+                "guild_id",
+                "user_id",
+                "type",
+                "format_type"
+            FROM "temporary_stickers"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_stickers"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "webhooks"
+                RENAME TO "temporary_webhooks"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "webhooks" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "type" integer NOT NULL,
+                "name" varchar,
+                "avatar" varchar,
+                "token" varchar,
+                "guild_id" varchar,
+                "channel_id" varchar,
+                "application_id" varchar,
+                "user_id" varchar,
+                "source_guild_id" varchar
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "webhooks"(
+                    "id",
+                    "type",
+                    "name",
+                    "avatar",
+                    "token",
+                    "guild_id",
+                    "channel_id",
+                    "application_id",
+                    "user_id",
+                    "source_guild_id"
+                )
+            SELECT "id",
+                "type",
+                "name",
+                "avatar",
+                "token",
+                "guild_id",
+                "channel_id",
+                "application_id",
+                "user_id",
+                "source_guild_id"
+            FROM "temporary_webhooks"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_webhooks"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_bb2bf9386ac443afbbbf9f12d3"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "members"
+                RENAME TO "temporary_members"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "members" (
+                "index" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
+                "id" varchar NOT NULL,
+                "guild_id" varchar NOT NULL,
+                "nick" varchar,
+                "joined_at" datetime NOT NULL,
+                "premium_since" bigint,
+                "deaf" boolean NOT NULL,
+                "mute" boolean NOT NULL,
+                "pending" boolean NOT NULL,
+                "settings" text NOT NULL,
+                "last_message_id" varchar,
+                "joined_by" varchar
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "members"(
+                    "index",
+                    "id",
+                    "guild_id",
+                    "nick",
+                    "joined_at",
+                    "premium_since",
+                    "deaf",
+                    "mute",
+                    "pending",
+                    "settings",
+                    "last_message_id",
+                    "joined_by"
+                )
+            SELECT "index",
+                "id",
+                "guild_id",
+                "nick",
+                "joined_at",
+                "premium_since",
+                "deaf",
+                "mute",
+                "pending",
+                "settings",
+                "last_message_id",
+                "joined_by"
+            FROM "temporary_members"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_members"
+        `);
+		await queryRunner.query(`
+            CREATE UNIQUE INDEX "IDX_bb2bf9386ac443afbbbf9f12d3" ON "members" ("id", "guild_id")
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "roles"
+                RENAME TO "temporary_roles"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "roles" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "guild_id" varchar,
+                "color" integer NOT NULL,
+                "hoist" boolean NOT NULL,
+                "managed" boolean NOT NULL,
+                "mentionable" boolean NOT NULL,
+                "name" varchar NOT NULL,
+                "permissions" varchar NOT NULL,
+                "position" integer NOT NULL,
+                "icon" varchar,
+                "unicode_emoji" varchar,
+                "tags" text
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "roles"(
+                    "id",
+                    "guild_id",
+                    "color",
+                    "hoist",
+                    "managed",
+                    "mentionable",
+                    "name",
+                    "permissions",
+                    "position",
+                    "icon",
+                    "unicode_emoji",
+                    "tags"
+                )
+            SELECT "id",
+                "guild_id",
+                "color",
+                "hoist",
+                "managed",
+                "mentionable",
+                "name",
+                "permissions",
+                "position",
+                "icon",
+                "unicode_emoji",
+                "tags"
+            FROM "temporary_roles"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_roles"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "recipients"
+                RENAME TO "temporary_recipients"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "recipients" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "channel_id" varchar NOT NULL,
+                "user_id" varchar NOT NULL,
+                "closed" boolean NOT NULL DEFAULT (0)
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "recipients"("id", "channel_id", "user_id", "closed")
+            SELECT "id",
+                "channel_id",
+                "user_id",
+                "closed"
+            FROM "temporary_recipients"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_recipients"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "bans"
+                RENAME TO "temporary_bans"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "bans" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "user_id" varchar,
+                "guild_id" varchar,
+                "executor_id" varchar,
+                "ip" varchar NOT NULL,
+                "reason" varchar
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "bans"(
+                    "id",
+                    "user_id",
+                    "guild_id",
+                    "executor_id",
+                    "ip",
+                    "reason"
+                )
+            SELECT "id",
+                "user_id",
+                "guild_id",
+                "executor_id",
+                "ip",
+                "reason"
+            FROM "temporary_bans"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_bans"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "backup_codes"
+                RENAME TO "temporary_backup_codes"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "backup_codes" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "code" varchar NOT NULL,
+                "consumed" boolean NOT NULL,
+                "expired" boolean NOT NULL,
+                "user_id" varchar
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "backup_codes"("id", "code", "consumed", "expired", "user_id")
+            SELECT "id",
+                "code",
+                "consumed",
+                "expired",
+                "user_id"
+            FROM "temporary_backup_codes"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_backup_codes"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "connected_accounts"
+                RENAME TO "temporary_connected_accounts"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "connected_accounts" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "user_id" varchar,
+                "access_token" varchar NOT NULL,
+                "friend_sync" boolean NOT NULL,
+                "name" varchar NOT NULL,
+                "revoked" boolean NOT NULL,
+                "show_activity" boolean NOT NULL,
+                "type" varchar NOT NULL,
+                "verified" boolean NOT NULL,
+                "visibility" integer NOT NULL
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "connected_accounts"(
+                    "id",
+                    "user_id",
+                    "access_token",
+                    "friend_sync",
+                    "name",
+                    "revoked",
+                    "show_activity",
+                    "type",
+                    "verified",
+                    "visibility"
+                )
+            SELECT "id",
+                "user_id",
+                "access_token",
+                "friend_sync",
+                "name",
+                "revoked",
+                "show_activity",
+                "type",
+                "verified",
+                "visibility"
+            FROM "temporary_connected_accounts"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_connected_accounts"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_a0b2ff0a598df0b0d055934a17"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "relationships"
+                RENAME TO "temporary_relationships"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "relationships" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "from_id" varchar NOT NULL,
+                "to_id" varchar NOT NULL,
+                "nickname" varchar,
+                "type" integer NOT NULL
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "relationships"("id", "from_id", "to_id", "nickname", "type")
+            SELECT "id",
+                "from_id",
+                "to_id",
+                "nickname",
+                "type"
+            FROM "temporary_relationships"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_relationships"
+        `);
+		await queryRunner.query(`
+            CREATE UNIQUE INDEX "IDX_a0b2ff0a598df0b0d055934a17" ON "relationships" ("from_id", "to_id")
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_e22a70819d07659c7a71c112a1"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_40bb6f23e7cc133292e92829d2"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "message_stickers"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_bdb8c09e1464cabf62105bf4b9"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_2a27102ecd1d81b4582a436092"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "message_channel_mentions"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_29d63eb1a458200851bc37d074"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_a8242cf535337a490b0feaea0b"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "message_role_mentions"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_b831eb18ceebd28976239b1e2f"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_a343387fc560ef378760681c23"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "message_user_mentions"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_e9080e7a7997a0170026d5139c"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_5d7ddc8a5f9c167f548625e772"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "member_roles"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "notes"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "client_release"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "sticker_packs"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "sessions"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "rate_limits"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "categories"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "audit_logs"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "applications"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "teams"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "team_members"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "guilds"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "templates"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "emojis"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "channels"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "voice_states"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "invites"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_0abf8b443321bd3cf7f81ee17a"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "read_states"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_3ed7a60fb7dbe04e1ba9332a8b"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_05535bc695e9f7ee104616459d"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_86b9109b155eb70c0a2ca3b4b6"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "messages"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "attachments"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "stickers"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "webhooks"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_bb2bf9386ac443afbbbf9f12d3"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "members"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "roles"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "recipients"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "bans"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "backup_codes"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "users"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "connected_accounts"
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_a0b2ff0a598df0b0d055934a17"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "relationships"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "config"
+        `);
+	}
+}
diff --git a/src/util/migrations/sqlite/1659921722863-premium_since_as_date.ts b/src/util/migrations/sqlite/1659921722863-premium_since_as_date.ts
new file mode 100644
index 00000000..b6307ee9
--- /dev/null
+++ b/src/util/migrations/sqlite/1659921722863-premium_since_as_date.ts
@@ -0,0 +1,251 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class premiumSinceAsDate1659921722863 implements MigrationInterface {
+	name = "premiumSinceAsDate1659921722863";
+
+	public async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            DROP INDEX "IDX_bb2bf9386ac443afbbbf9f12d3"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_members" (
+                "index" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
+                "id" varchar NOT NULL,
+                "guild_id" varchar NOT NULL,
+                "nick" varchar,
+                "joined_at" datetime NOT NULL,
+                "premium_since" bigint,
+                "deaf" boolean NOT NULL,
+                "mute" boolean NOT NULL,
+                "pending" boolean NOT NULL,
+                "settings" text NOT NULL,
+                "last_message_id" varchar,
+                "joined_by" varchar,
+                CONSTRAINT "FK_16aceddd5b89825b8ed6029ad1c" FOREIGN KEY ("guild_id") REFERENCES "guilds" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_28b53062261b996d9c99fa12404" FOREIGN KEY ("id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_members"(
+                    "index",
+                    "id",
+                    "guild_id",
+                    "nick",
+                    "joined_at",
+                    "premium_since",
+                    "deaf",
+                    "mute",
+                    "pending",
+                    "settings",
+                    "last_message_id",
+                    "joined_by"
+                )
+            SELECT "index",
+                "id",
+                "guild_id",
+                "nick",
+                "joined_at",
+                "premium_since",
+                "deaf",
+                "mute",
+                "pending",
+                "settings",
+                "last_message_id",
+                "joined_by"
+            FROM "members"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "members"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_members"
+                RENAME TO "members"
+        `);
+		await queryRunner.query(`
+            CREATE UNIQUE INDEX "IDX_bb2bf9386ac443afbbbf9f12d3" ON "members" ("id", "guild_id")
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_bb2bf9386ac443afbbbf9f12d3"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_members" (
+                "index" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
+                "id" varchar NOT NULL,
+                "guild_id" varchar NOT NULL,
+                "nick" varchar,
+                "joined_at" datetime NOT NULL,
+                "premium_since" datetime,
+                "deaf" boolean NOT NULL,
+                "mute" boolean NOT NULL,
+                "pending" boolean NOT NULL,
+                "settings" text NOT NULL,
+                "last_message_id" varchar,
+                "joined_by" varchar,
+                CONSTRAINT "FK_16aceddd5b89825b8ed6029ad1c" FOREIGN KEY ("guild_id") REFERENCES "guilds" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_28b53062261b996d9c99fa12404" FOREIGN KEY ("id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_members"(
+                    "index",
+                    "id",
+                    "guild_id",
+                    "nick",
+                    "joined_at",
+                    "premium_since",
+                    "deaf",
+                    "mute",
+                    "pending",
+                    "settings",
+                    "last_message_id",
+                    "joined_by"
+                )
+            SELECT "index",
+                "id",
+                "guild_id",
+                "nick",
+                "joined_at",
+                "premium_since",
+                "deaf",
+                "mute",
+                "pending",
+                "settings",
+                "last_message_id",
+                "joined_by"
+            FROM "members"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "members"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_members"
+                RENAME TO "members"
+        `);
+		await queryRunner.query(`
+            CREATE UNIQUE INDEX "IDX_bb2bf9386ac443afbbbf9f12d3" ON "members" ("id", "guild_id")
+        `);
+	}
+
+	public async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            DROP INDEX "IDX_bb2bf9386ac443afbbbf9f12d3"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "members"
+                RENAME TO "temporary_members"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "members" (
+                "index" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
+                "id" varchar NOT NULL,
+                "guild_id" varchar NOT NULL,
+                "nick" varchar,
+                "joined_at" datetime NOT NULL,
+                "premium_since" bigint,
+                "deaf" boolean NOT NULL,
+                "mute" boolean NOT NULL,
+                "pending" boolean NOT NULL,
+                "settings" text NOT NULL,
+                "last_message_id" varchar,
+                "joined_by" varchar,
+                CONSTRAINT "FK_16aceddd5b89825b8ed6029ad1c" FOREIGN KEY ("guild_id") REFERENCES "guilds" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_28b53062261b996d9c99fa12404" FOREIGN KEY ("id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "members"(
+                    "index",
+                    "id",
+                    "guild_id",
+                    "nick",
+                    "joined_at",
+                    "premium_since",
+                    "deaf",
+                    "mute",
+                    "pending",
+                    "settings",
+                    "last_message_id",
+                    "joined_by"
+                )
+            SELECT "index",
+                "id",
+                "guild_id",
+                "nick",
+                "joined_at",
+                "premium_since",
+                "deaf",
+                "mute",
+                "pending",
+                "settings",
+                "last_message_id",
+                "joined_by"
+            FROM "temporary_members"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_members"
+        `);
+		await queryRunner.query(`
+            CREATE UNIQUE INDEX "IDX_bb2bf9386ac443afbbbf9f12d3" ON "members" ("id", "guild_id")
+        `);
+		await queryRunner.query(`
+            DROP INDEX "IDX_bb2bf9386ac443afbbbf9f12d3"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "members"
+                RENAME TO "temporary_members"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "members" (
+                "index" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
+                "id" varchar NOT NULL,
+                "guild_id" varchar NOT NULL,
+                "nick" varchar,
+                "joined_at" datetime NOT NULL,
+                "premium_since" bigint,
+                "deaf" boolean NOT NULL,
+                "mute" boolean NOT NULL,
+                "pending" boolean NOT NULL,
+                "settings" text NOT NULL,
+                "last_message_id" varchar,
+                "joined_by" varchar,
+                CONSTRAINT "FK_16aceddd5b89825b8ed6029ad1c" FOREIGN KEY ("guild_id") REFERENCES "guilds" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_28b53062261b996d9c99fa12404" FOREIGN KEY ("id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "members"(
+                    "index",
+                    "id",
+                    "guild_id",
+                    "nick",
+                    "joined_at",
+                    "premium_since",
+                    "deaf",
+                    "mute",
+                    "pending",
+                    "settings",
+                    "last_message_id",
+                    "joined_by"
+                )
+            SELECT "index",
+                "id",
+                "guild_id",
+                "nick",
+                "joined_at",
+                "premium_since",
+                "deaf",
+                "mute",
+                "pending",
+                "settings",
+                "last_message_id",
+                "joined_by"
+            FROM "temporary_members"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_members"
+        `);
+		await queryRunner.query(`
+            CREATE UNIQUE INDEX "IDX_bb2bf9386ac443afbbbf9f12d3" ON "members" ("id", "guild_id")
+        `);
+	}
+}
diff --git a/src/util/migrations/sqlite/1660130536131-updated-applications.ts b/src/util/migrations/sqlite/1660130536131-updated-applications.ts
new file mode 100644
index 00000000..bcb1c929
--- /dev/null
+++ b/src/util/migrations/sqlite/1660130536131-updated-applications.ts
@@ -0,0 +1,828 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class updatedApplications1660130536131 implements MigrationInterface {
+	name = "updatedApplications1660130536131";
+
+	public async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            CREATE TABLE "temporary_applications" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "name" varchar NOT NULL,
+                "icon" varchar,
+                "description" varchar NOT NULL,
+                "rpc_origins" text,
+                "bot_public" boolean NOT NULL,
+                "bot_require_code_grant" boolean NOT NULL,
+                "terms_of_service_url" varchar,
+                "privacy_policy_url" varchar,
+                "summary" varchar,
+                "verify_key" varchar NOT NULL,
+                "primary_sku_id" varchar,
+                "slug" varchar,
+                "cover_image" varchar,
+                "flags" varchar NOT NULL,
+                "owner_id" varchar,
+                "team_id" varchar,
+                "guild_id" varchar,
+                CONSTRAINT "FK_a36ed02953077f408d0f3ebc424" FOREIGN KEY ("team_id") REFERENCES "teams" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_e57508958bf92b9d9d25231b5e8" FOREIGN KEY ("owner_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_applications"(
+                    "id",
+                    "name",
+                    "icon",
+                    "description",
+                    "rpc_origins",
+                    "bot_public",
+                    "bot_require_code_grant",
+                    "terms_of_service_url",
+                    "privacy_policy_url",
+                    "summary",
+                    "verify_key",
+                    "primary_sku_id",
+                    "slug",
+                    "cover_image",
+                    "flags",
+                    "owner_id",
+                    "team_id",
+                    "guild_id"
+                )
+            SELECT "id",
+                "name",
+                "icon",
+                "description",
+                "rpc_origins",
+                "bot_public",
+                "bot_require_code_grant",
+                "terms_of_service_url",
+                "privacy_policy_url",
+                "summary",
+                "verify_key",
+                "primary_sku_id",
+                "slug",
+                "cover_image",
+                "flags",
+                "owner_id",
+                "team_id",
+                "guild_id"
+            FROM "applications"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "applications"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_applications"
+                RENAME TO "applications"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_applications" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "name" varchar NOT NULL,
+                "icon" varchar,
+                "description" varchar NOT NULL,
+                "bot_public" boolean NOT NULL,
+                "bot_require_code_grant" boolean NOT NULL,
+                "terms_of_service_url" varchar,
+                "privacy_policy_url" varchar,
+                "summary" varchar,
+                "verify_key" varchar NOT NULL,
+                "cover_image" varchar,
+                "flags" varchar NOT NULL,
+                "owner_id" varchar,
+                "team_id" varchar,
+                CONSTRAINT "FK_a36ed02953077f408d0f3ebc424" FOREIGN KEY ("team_id") REFERENCES "teams" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_e57508958bf92b9d9d25231b5e8" FOREIGN KEY ("owner_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_applications"(
+                    "id",
+                    "name",
+                    "icon",
+                    "description",
+                    "bot_public",
+                    "bot_require_code_grant",
+                    "terms_of_service_url",
+                    "privacy_policy_url",
+                    "summary",
+                    "verify_key",
+                    "cover_image",
+                    "flags",
+                    "owner_id",
+                    "team_id"
+                )
+            SELECT "id",
+                "name",
+                "icon",
+                "description",
+                "bot_public",
+                "bot_require_code_grant",
+                "terms_of_service_url",
+                "privacy_policy_url",
+                "summary",
+                "verify_key",
+                "cover_image",
+                "flags",
+                "owner_id",
+                "team_id"
+            FROM "applications"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "applications"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_applications"
+                RENAME TO "applications"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_applications" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "name" varchar NOT NULL,
+                "icon" varchar,
+                "description" varchar NOT NULL,
+                "bot_public" boolean NOT NULL,
+                "bot_require_code_grant" boolean NOT NULL,
+                "terms_of_service_url" varchar,
+                "privacy_policy_url" varchar,
+                "summary" varchar,
+                "verify_key" varchar NOT NULL,
+                "cover_image" varchar,
+                "flags" varchar NOT NULL,
+                "owner_id" varchar,
+                "team_id" varchar,
+                "type" text,
+                "hook" boolean NOT NULL,
+                "redirect_uris" text,
+                "rpc_application_state" integer,
+                "store_application_state" integer,
+                "verification_state" integer,
+                "interactions_endpoint_url" varchar,
+                "integration_public" boolean,
+                "integration_require_code_grant" boolean,
+                "discoverability_state" integer,
+                "discovery_eligibility_flags" integer,
+                "tags" text,
+                "install_params" text,
+                "bot_user_id" varchar,
+                CONSTRAINT "UQ_b7f6e13565e920916d902e1f431" UNIQUE ("bot_user_id"),
+                CONSTRAINT "FK_a36ed02953077f408d0f3ebc424" FOREIGN KEY ("team_id") REFERENCES "teams" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_e57508958bf92b9d9d25231b5e8" FOREIGN KEY ("owner_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_applications"(
+                    "id",
+                    "name",
+                    "icon",
+                    "description",
+                    "bot_public",
+                    "bot_require_code_grant",
+                    "terms_of_service_url",
+                    "privacy_policy_url",
+                    "summary",
+                    "verify_key",
+                    "cover_image",
+                    "flags",
+                    "owner_id",
+                    "team_id"
+                )
+            SELECT "id",
+                "name",
+                "icon",
+                "description",
+                "bot_public",
+                "bot_require_code_grant",
+                "terms_of_service_url",
+                "privacy_policy_url",
+                "summary",
+                "verify_key",
+                "cover_image",
+                "flags",
+                "owner_id",
+                "team_id"
+            FROM "applications"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "applications"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_applications"
+                RENAME TO "applications"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_applications" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "name" varchar NOT NULL,
+                "icon" varchar,
+                "description" varchar,
+                "bot_public" boolean NOT NULL,
+                "bot_require_code_grant" boolean NOT NULL,
+                "terms_of_service_url" varchar,
+                "privacy_policy_url" varchar,
+                "summary" varchar,
+                "verify_key" varchar NOT NULL,
+                "cover_image" varchar,
+                "flags" integer NOT NULL,
+                "owner_id" varchar,
+                "team_id" varchar,
+                "type" text,
+                "hook" boolean NOT NULL,
+                "redirect_uris" text,
+                "rpc_application_state" integer,
+                "store_application_state" integer,
+                "verification_state" integer,
+                "interactions_endpoint_url" varchar,
+                "integration_public" boolean,
+                "integration_require_code_grant" boolean,
+                "discoverability_state" integer,
+                "discovery_eligibility_flags" integer,
+                "tags" text,
+                "install_params" text,
+                "bot_user_id" varchar,
+                CONSTRAINT "UQ_b7f6e13565e920916d902e1f431" UNIQUE ("bot_user_id"),
+                CONSTRAINT "FK_a36ed02953077f408d0f3ebc424" FOREIGN KEY ("team_id") REFERENCES "teams" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_e57508958bf92b9d9d25231b5e8" FOREIGN KEY ("owner_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_applications"(
+                    "id",
+                    "name",
+                    "icon",
+                    "description",
+                    "bot_public",
+                    "bot_require_code_grant",
+                    "terms_of_service_url",
+                    "privacy_policy_url",
+                    "summary",
+                    "verify_key",
+                    "cover_image",
+                    "flags",
+                    "owner_id",
+                    "team_id",
+                    "type",
+                    "hook",
+                    "redirect_uris",
+                    "rpc_application_state",
+                    "store_application_state",
+                    "verification_state",
+                    "interactions_endpoint_url",
+                    "integration_public",
+                    "integration_require_code_grant",
+                    "discoverability_state",
+                    "discovery_eligibility_flags",
+                    "tags",
+                    "install_params",
+                    "bot_user_id"
+                )
+            SELECT "id",
+                "name",
+                "icon",
+                "description",
+                "bot_public",
+                "bot_require_code_grant",
+                "terms_of_service_url",
+                "privacy_policy_url",
+                "summary",
+                "verify_key",
+                "cover_image",
+                "flags",
+                "owner_id",
+                "team_id",
+                "type",
+                "hook",
+                "redirect_uris",
+                "rpc_application_state",
+                "store_application_state",
+                "verification_state",
+                "interactions_endpoint_url",
+                "integration_public",
+                "integration_require_code_grant",
+                "discoverability_state",
+                "discovery_eligibility_flags",
+                "tags",
+                "install_params",
+                "bot_user_id"
+            FROM "applications"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "applications"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_applications"
+                RENAME TO "applications"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_applications" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "name" varchar NOT NULL,
+                "icon" varchar,
+                "description" varchar,
+                "bot_public" boolean NOT NULL,
+                "bot_require_code_grant" boolean NOT NULL,
+                "terms_of_service_url" varchar,
+                "privacy_policy_url" varchar,
+                "summary" varchar,
+                "verify_key" varchar NOT NULL,
+                "cover_image" varchar,
+                "flags" integer NOT NULL,
+                "owner_id" varchar,
+                "team_id" varchar,
+                "type" text,
+                "hook" boolean NOT NULL,
+                "redirect_uris" text,
+                "rpc_application_state" integer,
+                "store_application_state" integer,
+                "verification_state" integer,
+                "interactions_endpoint_url" varchar,
+                "integration_public" boolean,
+                "integration_require_code_grant" boolean,
+                "discoverability_state" integer,
+                "discovery_eligibility_flags" integer,
+                "tags" text,
+                "install_params" text,
+                "bot_user_id" varchar,
+                CONSTRAINT "UQ_b7f6e13565e920916d902e1f431" UNIQUE ("bot_user_id"),
+                CONSTRAINT "FK_a36ed02953077f408d0f3ebc424" FOREIGN KEY ("team_id") REFERENCES "teams" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_e57508958bf92b9d9d25231b5e8" FOREIGN KEY ("owner_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_2ce5a55796fe4c2f77ece57a647" FOREIGN KEY ("bot_user_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_applications"(
+                    "id",
+                    "name",
+                    "icon",
+                    "description",
+                    "bot_public",
+                    "bot_require_code_grant",
+                    "terms_of_service_url",
+                    "privacy_policy_url",
+                    "summary",
+                    "verify_key",
+                    "cover_image",
+                    "flags",
+                    "owner_id",
+                    "team_id",
+                    "type",
+                    "hook",
+                    "redirect_uris",
+                    "rpc_application_state",
+                    "store_application_state",
+                    "verification_state",
+                    "interactions_endpoint_url",
+                    "integration_public",
+                    "integration_require_code_grant",
+                    "discoverability_state",
+                    "discovery_eligibility_flags",
+                    "tags",
+                    "install_params",
+                    "bot_user_id"
+                )
+            SELECT "id",
+                "name",
+                "icon",
+                "description",
+                "bot_public",
+                "bot_require_code_grant",
+                "terms_of_service_url",
+                "privacy_policy_url",
+                "summary",
+                "verify_key",
+                "cover_image",
+                "flags",
+                "owner_id",
+                "team_id",
+                "type",
+                "hook",
+                "redirect_uris",
+                "rpc_application_state",
+                "store_application_state",
+                "verification_state",
+                "interactions_endpoint_url",
+                "integration_public",
+                "integration_require_code_grant",
+                "discoverability_state",
+                "discovery_eligibility_flags",
+                "tags",
+                "install_params",
+                "bot_user_id"
+            FROM "applications"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "applications"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_applications"
+                RENAME TO "applications"
+        `);
+	}
+
+	public async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+                RENAME TO "temporary_applications"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "applications" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "name" varchar NOT NULL,
+                "icon" varchar,
+                "description" varchar,
+                "bot_public" boolean NOT NULL,
+                "bot_require_code_grant" boolean NOT NULL,
+                "terms_of_service_url" varchar,
+                "privacy_policy_url" varchar,
+                "summary" varchar,
+                "verify_key" varchar NOT NULL,
+                "cover_image" varchar,
+                "flags" integer NOT NULL,
+                "owner_id" varchar,
+                "team_id" varchar,
+                "type" text,
+                "hook" boolean NOT NULL,
+                "redirect_uris" text,
+                "rpc_application_state" integer,
+                "store_application_state" integer,
+                "verification_state" integer,
+                "interactions_endpoint_url" varchar,
+                "integration_public" boolean,
+                "integration_require_code_grant" boolean,
+                "discoverability_state" integer,
+                "discovery_eligibility_flags" integer,
+                "tags" text,
+                "install_params" text,
+                "bot_user_id" varchar,
+                CONSTRAINT "UQ_b7f6e13565e920916d902e1f431" UNIQUE ("bot_user_id"),
+                CONSTRAINT "FK_a36ed02953077f408d0f3ebc424" FOREIGN KEY ("team_id") REFERENCES "teams" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_e57508958bf92b9d9d25231b5e8" FOREIGN KEY ("owner_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "applications"(
+                    "id",
+                    "name",
+                    "icon",
+                    "description",
+                    "bot_public",
+                    "bot_require_code_grant",
+                    "terms_of_service_url",
+                    "privacy_policy_url",
+                    "summary",
+                    "verify_key",
+                    "cover_image",
+                    "flags",
+                    "owner_id",
+                    "team_id",
+                    "type",
+                    "hook",
+                    "redirect_uris",
+                    "rpc_application_state",
+                    "store_application_state",
+                    "verification_state",
+                    "interactions_endpoint_url",
+                    "integration_public",
+                    "integration_require_code_grant",
+                    "discoverability_state",
+                    "discovery_eligibility_flags",
+                    "tags",
+                    "install_params",
+                    "bot_user_id"
+                )
+            SELECT "id",
+                "name",
+                "icon",
+                "description",
+                "bot_public",
+                "bot_require_code_grant",
+                "terms_of_service_url",
+                "privacy_policy_url",
+                "summary",
+                "verify_key",
+                "cover_image",
+                "flags",
+                "owner_id",
+                "team_id",
+                "type",
+                "hook",
+                "redirect_uris",
+                "rpc_application_state",
+                "store_application_state",
+                "verification_state",
+                "interactions_endpoint_url",
+                "integration_public",
+                "integration_require_code_grant",
+                "discoverability_state",
+                "discovery_eligibility_flags",
+                "tags",
+                "install_params",
+                "bot_user_id"
+            FROM "temporary_applications"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_applications"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+                RENAME TO "temporary_applications"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "applications" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "name" varchar NOT NULL,
+                "icon" varchar,
+                "description" varchar NOT NULL,
+                "bot_public" boolean NOT NULL,
+                "bot_require_code_grant" boolean NOT NULL,
+                "terms_of_service_url" varchar,
+                "privacy_policy_url" varchar,
+                "summary" varchar,
+                "verify_key" varchar NOT NULL,
+                "cover_image" varchar,
+                "flags" varchar NOT NULL,
+                "owner_id" varchar,
+                "team_id" varchar,
+                "type" text,
+                "hook" boolean NOT NULL,
+                "redirect_uris" text,
+                "rpc_application_state" integer,
+                "store_application_state" integer,
+                "verification_state" integer,
+                "interactions_endpoint_url" varchar,
+                "integration_public" boolean,
+                "integration_require_code_grant" boolean,
+                "discoverability_state" integer,
+                "discovery_eligibility_flags" integer,
+                "tags" text,
+                "install_params" text,
+                "bot_user_id" varchar,
+                CONSTRAINT "UQ_b7f6e13565e920916d902e1f431" UNIQUE ("bot_user_id"),
+                CONSTRAINT "FK_a36ed02953077f408d0f3ebc424" FOREIGN KEY ("team_id") REFERENCES "teams" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_e57508958bf92b9d9d25231b5e8" FOREIGN KEY ("owner_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "applications"(
+                    "id",
+                    "name",
+                    "icon",
+                    "description",
+                    "bot_public",
+                    "bot_require_code_grant",
+                    "terms_of_service_url",
+                    "privacy_policy_url",
+                    "summary",
+                    "verify_key",
+                    "cover_image",
+                    "flags",
+                    "owner_id",
+                    "team_id",
+                    "type",
+                    "hook",
+                    "redirect_uris",
+                    "rpc_application_state",
+                    "store_application_state",
+                    "verification_state",
+                    "interactions_endpoint_url",
+                    "integration_public",
+                    "integration_require_code_grant",
+                    "discoverability_state",
+                    "discovery_eligibility_flags",
+                    "tags",
+                    "install_params",
+                    "bot_user_id"
+                )
+            SELECT "id",
+                "name",
+                "icon",
+                "description",
+                "bot_public",
+                "bot_require_code_grant",
+                "terms_of_service_url",
+                "privacy_policy_url",
+                "summary",
+                "verify_key",
+                "cover_image",
+                "flags",
+                "owner_id",
+                "team_id",
+                "type",
+                "hook",
+                "redirect_uris",
+                "rpc_application_state",
+                "store_application_state",
+                "verification_state",
+                "interactions_endpoint_url",
+                "integration_public",
+                "integration_require_code_grant",
+                "discoverability_state",
+                "discovery_eligibility_flags",
+                "tags",
+                "install_params",
+                "bot_user_id"
+            FROM "temporary_applications"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_applications"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+                RENAME TO "temporary_applications"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "applications" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "name" varchar NOT NULL,
+                "icon" varchar,
+                "description" varchar NOT NULL,
+                "bot_public" boolean NOT NULL,
+                "bot_require_code_grant" boolean NOT NULL,
+                "terms_of_service_url" varchar,
+                "privacy_policy_url" varchar,
+                "summary" varchar,
+                "verify_key" varchar NOT NULL,
+                "cover_image" varchar,
+                "flags" varchar NOT NULL,
+                "owner_id" varchar,
+                "team_id" varchar,
+                CONSTRAINT "FK_a36ed02953077f408d0f3ebc424" FOREIGN KEY ("team_id") REFERENCES "teams" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_e57508958bf92b9d9d25231b5e8" FOREIGN KEY ("owner_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "applications"(
+                    "id",
+                    "name",
+                    "icon",
+                    "description",
+                    "bot_public",
+                    "bot_require_code_grant",
+                    "terms_of_service_url",
+                    "privacy_policy_url",
+                    "summary",
+                    "verify_key",
+                    "cover_image",
+                    "flags",
+                    "owner_id",
+                    "team_id"
+                )
+            SELECT "id",
+                "name",
+                "icon",
+                "description",
+                "bot_public",
+                "bot_require_code_grant",
+                "terms_of_service_url",
+                "privacy_policy_url",
+                "summary",
+                "verify_key",
+                "cover_image",
+                "flags",
+                "owner_id",
+                "team_id"
+            FROM "temporary_applications"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_applications"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+                RENAME TO "temporary_applications"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "applications" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "name" varchar NOT NULL,
+                "icon" varchar,
+                "description" varchar NOT NULL,
+                "rpc_origins" text,
+                "bot_public" boolean NOT NULL,
+                "bot_require_code_grant" boolean NOT NULL,
+                "terms_of_service_url" varchar,
+                "privacy_policy_url" varchar,
+                "summary" varchar,
+                "verify_key" varchar NOT NULL,
+                "primary_sku_id" varchar,
+                "slug" varchar,
+                "cover_image" varchar,
+                "flags" varchar NOT NULL,
+                "owner_id" varchar,
+                "team_id" varchar,
+                "guild_id" varchar,
+                CONSTRAINT "FK_a36ed02953077f408d0f3ebc424" FOREIGN KEY ("team_id") REFERENCES "teams" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_e57508958bf92b9d9d25231b5e8" FOREIGN KEY ("owner_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "applications"(
+                    "id",
+                    "name",
+                    "icon",
+                    "description",
+                    "bot_public",
+                    "bot_require_code_grant",
+                    "terms_of_service_url",
+                    "privacy_policy_url",
+                    "summary",
+                    "verify_key",
+                    "cover_image",
+                    "flags",
+                    "owner_id",
+                    "team_id"
+                )
+            SELECT "id",
+                "name",
+                "icon",
+                "description",
+                "bot_public",
+                "bot_require_code_grant",
+                "terms_of_service_url",
+                "privacy_policy_url",
+                "summary",
+                "verify_key",
+                "cover_image",
+                "flags",
+                "owner_id",
+                "team_id"
+            FROM "temporary_applications"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_applications"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "applications"
+                RENAME TO "temporary_applications"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "applications" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "name" varchar NOT NULL,
+                "icon" varchar,
+                "description" varchar NOT NULL,
+                "rpc_origins" text,
+                "bot_public" boolean NOT NULL,
+                "bot_require_code_grant" boolean NOT NULL,
+                "terms_of_service_url" varchar,
+                "privacy_policy_url" varchar,
+                "summary" varchar,
+                "verify_key" varchar NOT NULL,
+                "primary_sku_id" varchar,
+                "slug" varchar,
+                "cover_image" varchar,
+                "flags" varchar NOT NULL,
+                "owner_id" varchar,
+                "team_id" varchar,
+                "guild_id" varchar,
+                CONSTRAINT "FK_e5bf78cdbbe9ba91062d74c5aba" FOREIGN KEY ("guild_id") REFERENCES "guilds" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_a36ed02953077f408d0f3ebc424" FOREIGN KEY ("team_id") REFERENCES "teams" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_e57508958bf92b9d9d25231b5e8" FOREIGN KEY ("owner_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "applications"(
+                    "id",
+                    "name",
+                    "icon",
+                    "description",
+                    "rpc_origins",
+                    "bot_public",
+                    "bot_require_code_grant",
+                    "terms_of_service_url",
+                    "privacy_policy_url",
+                    "summary",
+                    "verify_key",
+                    "primary_sku_id",
+                    "slug",
+                    "cover_image",
+                    "flags",
+                    "owner_id",
+                    "team_id",
+                    "guild_id"
+                )
+            SELECT "id",
+                "name",
+                "icon",
+                "description",
+                "rpc_origins",
+                "bot_public",
+                "bot_require_code_grant",
+                "terms_of_service_url",
+                "privacy_policy_url",
+                "summary",
+                "verify_key",
+                "primary_sku_id",
+                "slug",
+                "cover_image",
+                "flags",
+                "owner_id",
+                "team_id",
+                "guild_id"
+            FROM "temporary_applications"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_applications"
+        `);
+	}
+}
diff --git a/src/util/migrations/sqlite/1660257576211-CodeCleanup1.ts b/src/util/migrations/sqlite/1660257576211-CodeCleanup1.ts
new file mode 100644
index 00000000..95410544
--- /dev/null
+++ b/src/util/migrations/sqlite/1660257576211-CodeCleanup1.ts
@@ -0,0 +1,325 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class CodeCleanup11660257576211 implements MigrationInterface {
+	name = "CodeCleanup11660257576211";
+
+	public async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            CREATE TABLE "user_settings" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "afk_timeout" integer,
+                "allow_accessibility_detection" boolean,
+                "animate_emoji" boolean,
+                "animate_stickers" integer,
+                "contact_sync_enabled" boolean,
+                "convert_emoticons" boolean,
+                "custom_status" text,
+                "default_guilds_restricted" boolean,
+                "detect_platform_accounts" boolean,
+                "developer_mode" boolean,
+                "disable_games_tab" boolean,
+                "enable_tts_command" boolean,
+                "explicit_content_filter" integer,
+                "friend_source_flags" text,
+                "gateway_connected" boolean,
+                "gif_auto_play" boolean,
+                "guild_folders" text,
+                "guild_positions" text,
+                "inline_attachment_media" boolean,
+                "inline_embed_media" boolean,
+                "locale" varchar,
+                "message_display_compact" boolean,
+                "native_phone_integration_enabled" boolean,
+                "render_embeds" boolean,
+                "render_reactions" boolean,
+                "restricted_guilds" text,
+                "show_current_game" boolean,
+                "status" varchar,
+                "stream_notifications_enabled" boolean,
+                "theme" varchar,
+                "timezone_offset" integer
+            )
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_guilds" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "afk_channel_id" varchar,
+                "afk_timeout" integer,
+                "banner" varchar,
+                "default_message_notifications" integer,
+                "description" varchar,
+                "discovery_splash" varchar,
+                "explicit_content_filter" integer,
+                "features" text NOT NULL,
+                "primary_category_id" integer,
+                "icon" varchar,
+                "large" boolean,
+                "max_members" integer,
+                "max_presences" integer,
+                "max_video_channel_users" integer,
+                "member_count" integer,
+                "presence_count" integer,
+                "template_id" varchar,
+                "mfa_level" integer,
+                "name" varchar NOT NULL,
+                "owner_id" varchar,
+                "preferred_locale" varchar,
+                "premium_subscription_count" integer,
+                "premium_tier" integer,
+                "public_updates_channel_id" varchar,
+                "rules_channel_id" varchar,
+                "region" varchar,
+                "splash" varchar,
+                "system_channel_id" varchar,
+                "system_channel_flags" integer,
+                "unavailable" boolean,
+                "verification_level" integer,
+                "welcome_screen" text NOT NULL,
+                "widget_channel_id" varchar,
+                "widget_enabled" boolean,
+                "nsfw_level" integer,
+                "nsfw" boolean,
+                "parent" varchar,
+                "premium_progress_bar_enabled" boolean NOT NULL,
+                CONSTRAINT "FK_9d1d665379eefde7876a17afa99" FOREIGN KEY ("widget_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_cfc3d3ad260f8121c95b31a1fce" FOREIGN KEY ("system_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_95828668aa333460582e0ca6396" FOREIGN KEY ("rules_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_8d450b016dc8bec35f36729e4b0" FOREIGN KEY ("public_updates_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_fc1a451727e3643ca572a3bb394" FOREIGN KEY ("owner_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_e2a2f873a64a5cf62526de42325" FOREIGN KEY ("template_id") REFERENCES "templates" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_f591a66b8019d87b0fe6c12dad6" FOREIGN KEY ("afk_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_guilds"(
+                    "id",
+                    "afk_channel_id",
+                    "afk_timeout",
+                    "banner",
+                    "default_message_notifications",
+                    "description",
+                    "discovery_splash",
+                    "explicit_content_filter",
+                    "features",
+                    "primary_category_id",
+                    "icon",
+                    "large",
+                    "max_members",
+                    "max_presences",
+                    "max_video_channel_users",
+                    "member_count",
+                    "presence_count",
+                    "template_id",
+                    "mfa_level",
+                    "name",
+                    "owner_id",
+                    "preferred_locale",
+                    "premium_subscription_count",
+                    "premium_tier",
+                    "public_updates_channel_id",
+                    "rules_channel_id",
+                    "region",
+                    "splash",
+                    "system_channel_id",
+                    "system_channel_flags",
+                    "unavailable",
+                    "verification_level",
+                    "welcome_screen",
+                    "widget_channel_id",
+                    "widget_enabled",
+                    "nsfw_level",
+                    "nsfw",
+                    "parent"
+                )
+            SELECT "id",
+                "afk_channel_id",
+                "afk_timeout",
+                "banner",
+                "default_message_notifications",
+                "description",
+                "discovery_splash",
+                "explicit_content_filter",
+                "features",
+                "primary_category_id",
+                "icon",
+                "large",
+                "max_members",
+                "max_presences",
+                "max_video_channel_users",
+                "member_count",
+                "presence_count",
+                "template_id",
+                "mfa_level",
+                "name",
+                "owner_id",
+                "preferred_locale",
+                "premium_subscription_count",
+                "premium_tier",
+                "public_updates_channel_id",
+                "rules_channel_id",
+                "region",
+                "splash",
+                "system_channel_id",
+                "system_channel_flags",
+                "unavailable",
+                "verification_level",
+                "welcome_screen",
+                "widget_channel_id",
+                "widget_enabled",
+                "nsfw_level",
+                "nsfw",
+                "parent"
+            FROM "guilds"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "guilds"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_guilds"
+                RENAME TO "guilds"
+        `);
+	}
+
+	public async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE "guilds"
+                RENAME TO "temporary_guilds"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "guilds" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "afk_channel_id" varchar,
+                "afk_timeout" integer,
+                "banner" varchar,
+                "default_message_notifications" integer,
+                "description" varchar,
+                "discovery_splash" varchar,
+                "explicit_content_filter" integer,
+                "features" text NOT NULL,
+                "primary_category_id" integer,
+                "icon" varchar,
+                "large" boolean,
+                "max_members" integer,
+                "max_presences" integer,
+                "max_video_channel_users" integer,
+                "member_count" integer,
+                "presence_count" integer,
+                "template_id" varchar,
+                "mfa_level" integer,
+                "name" varchar NOT NULL,
+                "owner_id" varchar,
+                "preferred_locale" varchar,
+                "premium_subscription_count" integer,
+                "premium_tier" integer,
+                "public_updates_channel_id" varchar,
+                "rules_channel_id" varchar,
+                "region" varchar,
+                "splash" varchar,
+                "system_channel_id" varchar,
+                "system_channel_flags" integer,
+                "unavailable" boolean,
+                "verification_level" integer,
+                "welcome_screen" text NOT NULL,
+                "widget_channel_id" varchar,
+                "widget_enabled" boolean,
+                "nsfw_level" integer,
+                "nsfw" boolean,
+                "parent" varchar,
+                CONSTRAINT "FK_9d1d665379eefde7876a17afa99" FOREIGN KEY ("widget_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_cfc3d3ad260f8121c95b31a1fce" FOREIGN KEY ("system_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_95828668aa333460582e0ca6396" FOREIGN KEY ("rules_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_8d450b016dc8bec35f36729e4b0" FOREIGN KEY ("public_updates_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_fc1a451727e3643ca572a3bb394" FOREIGN KEY ("owner_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_e2a2f873a64a5cf62526de42325" FOREIGN KEY ("template_id") REFERENCES "templates" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_f591a66b8019d87b0fe6c12dad6" FOREIGN KEY ("afk_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "guilds"(
+                    "id",
+                    "afk_channel_id",
+                    "afk_timeout",
+                    "banner",
+                    "default_message_notifications",
+                    "description",
+                    "discovery_splash",
+                    "explicit_content_filter",
+                    "features",
+                    "primary_category_id",
+                    "icon",
+                    "large",
+                    "max_members",
+                    "max_presences",
+                    "max_video_channel_users",
+                    "member_count",
+                    "presence_count",
+                    "template_id",
+                    "mfa_level",
+                    "name",
+                    "owner_id",
+                    "preferred_locale",
+                    "premium_subscription_count",
+                    "premium_tier",
+                    "public_updates_channel_id",
+                    "rules_channel_id",
+                    "region",
+                    "splash",
+                    "system_channel_id",
+                    "system_channel_flags",
+                    "unavailable",
+                    "verification_level",
+                    "welcome_screen",
+                    "widget_channel_id",
+                    "widget_enabled",
+                    "nsfw_level",
+                    "nsfw",
+                    "parent"
+                )
+            SELECT "id",
+                "afk_channel_id",
+                "afk_timeout",
+                "banner",
+                "default_message_notifications",
+                "description",
+                "discovery_splash",
+                "explicit_content_filter",
+                "features",
+                "primary_category_id",
+                "icon",
+                "large",
+                "max_members",
+                "max_presences",
+                "max_video_channel_users",
+                "member_count",
+                "presence_count",
+                "template_id",
+                "mfa_level",
+                "name",
+                "owner_id",
+                "preferred_locale",
+                "premium_subscription_count",
+                "premium_tier",
+                "public_updates_channel_id",
+                "rules_channel_id",
+                "region",
+                "splash",
+                "system_channel_id",
+                "system_channel_flags",
+                "unavailable",
+                "verification_level",
+                "welcome_screen",
+                "widget_channel_id",
+                "widget_enabled",
+                "nsfw_level",
+                "nsfw",
+                "parent"
+            FROM "temporary_guilds"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_guilds"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "user_settings"
+        `);
+	}
+}
diff --git a/src/util/migrations/sqlite/1660257795259-CodeCleanup2.ts b/src/util/migrations/sqlite/1660257795259-CodeCleanup2.ts
new file mode 100644
index 00000000..b21e190c
--- /dev/null
+++ b/src/util/migrations/sqlite/1660257795259-CodeCleanup2.ts
@@ -0,0 +1,571 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class CodeCleanup21660257795259 implements MigrationInterface {
+	name = "CodeCleanup21660257795259";
+
+	public async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            CREATE TABLE "temporary_guilds" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "afk_channel_id" varchar,
+                "afk_timeout" integer,
+                "banner" varchar,
+                "default_message_notifications" integer,
+                "description" varchar,
+                "discovery_splash" varchar,
+                "explicit_content_filter" integer,
+                "features" text NOT NULL,
+                "primary_category_id" integer,
+                "icon" varchar,
+                "large" boolean,
+                "max_members" integer,
+                "max_presences" integer,
+                "max_video_channel_users" integer,
+                "member_count" integer,
+                "presence_count" integer,
+                "template_id" varchar,
+                "mfa_level" integer,
+                "name" varchar NOT NULL,
+                "owner_id" varchar,
+                "preferred_locale" varchar,
+                "premium_subscription_count" integer,
+                "premium_tier" integer,
+                "public_updates_channel_id" varchar,
+                "rules_channel_id" varchar,
+                "region" varchar,
+                "splash" varchar,
+                "system_channel_id" varchar,
+                "system_channel_flags" integer,
+                "unavailable" boolean,
+                "verification_level" integer,
+                "welcome_screen" text NOT NULL,
+                "widget_channel_id" varchar,
+                "widget_enabled" boolean,
+                "nsfw_level" integer,
+                "nsfw" boolean,
+                "parent" varchar,
+                "premium_progress_bar_enabled" boolean NOT NULL,
+                CONSTRAINT "FK_f591a66b8019d87b0fe6c12dad6" FOREIGN KEY ("afk_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_e2a2f873a64a5cf62526de42325" FOREIGN KEY ("template_id") REFERENCES "templates" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_fc1a451727e3643ca572a3bb394" FOREIGN KEY ("owner_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_8d450b016dc8bec35f36729e4b0" FOREIGN KEY ("public_updates_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_95828668aa333460582e0ca6396" FOREIGN KEY ("rules_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_cfc3d3ad260f8121c95b31a1fce" FOREIGN KEY ("system_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_9d1d665379eefde7876a17afa99" FOREIGN KEY ("widget_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_guilds"(
+                    "id",
+                    "afk_channel_id",
+                    "afk_timeout",
+                    "banner",
+                    "default_message_notifications",
+                    "description",
+                    "discovery_splash",
+                    "explicit_content_filter",
+                    "features",
+                    "primary_category_id",
+                    "icon",
+                    "large",
+                    "max_members",
+                    "max_presences",
+                    "max_video_channel_users",
+                    "member_count",
+                    "presence_count",
+                    "template_id",
+                    "mfa_level",
+                    "name",
+                    "owner_id",
+                    "preferred_locale",
+                    "premium_subscription_count",
+                    "premium_tier",
+                    "public_updates_channel_id",
+                    "rules_channel_id",
+                    "region",
+                    "splash",
+                    "system_channel_id",
+                    "system_channel_flags",
+                    "unavailable",
+                    "verification_level",
+                    "welcome_screen",
+                    "widget_channel_id",
+                    "widget_enabled",
+                    "nsfw_level",
+                    "nsfw",
+                    "parent",
+                    "premium_progress_bar_enabled"
+                )
+            SELECT "id",
+                "afk_channel_id",
+                "afk_timeout",
+                "banner",
+                "default_message_notifications",
+                "description",
+                "discovery_splash",
+                "explicit_content_filter",
+                "features",
+                "primary_category_id",
+                "icon",
+                "large",
+                "max_members",
+                "max_presences",
+                "max_video_channel_users",
+                "member_count",
+                "presence_count",
+                "template_id",
+                "mfa_level",
+                "name",
+                "owner_id",
+                "preferred_locale",
+                "premium_subscription_count",
+                "premium_tier",
+                "public_updates_channel_id",
+                "rules_channel_id",
+                "region",
+                "splash",
+                "system_channel_id",
+                "system_channel_flags",
+                "unavailable",
+                "verification_level",
+                "welcome_screen",
+                "widget_channel_id",
+                "widget_enabled",
+                "nsfw_level",
+                "nsfw",
+                "parent",
+                "premium_progress_bar_enabled"
+            FROM "guilds"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "guilds"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_guilds"
+                RENAME TO "guilds"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_guilds" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "afk_channel_id" varchar,
+                "afk_timeout" integer,
+                "banner" varchar,
+                "default_message_notifications" integer,
+                "description" varchar,
+                "discovery_splash" varchar,
+                "explicit_content_filter" integer,
+                "features" text NOT NULL,
+                "primary_category_id" integer,
+                "icon" varchar,
+                "large" boolean,
+                "max_members" integer,
+                "max_presences" integer,
+                "max_video_channel_users" integer,
+                "member_count" integer,
+                "presence_count" integer,
+                "template_id" varchar,
+                "mfa_level" integer,
+                "name" varchar NOT NULL,
+                "owner_id" varchar,
+                "preferred_locale" varchar,
+                "premium_subscription_count" integer,
+                "premium_tier" integer,
+                "public_updates_channel_id" varchar,
+                "rules_channel_id" varchar,
+                "region" varchar,
+                "splash" varchar,
+                "system_channel_id" varchar,
+                "system_channel_flags" integer,
+                "unavailable" boolean,
+                "verification_level" integer,
+                "welcome_screen" text NOT NULL,
+                "widget_channel_id" varchar,
+                "widget_enabled" boolean,
+                "nsfw_level" integer,
+                "nsfw" boolean,
+                "parent" varchar,
+                "premium_progress_bar_enabled" boolean,
+                CONSTRAINT "FK_f591a66b8019d87b0fe6c12dad6" FOREIGN KEY ("afk_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_e2a2f873a64a5cf62526de42325" FOREIGN KEY ("template_id") REFERENCES "templates" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_fc1a451727e3643ca572a3bb394" FOREIGN KEY ("owner_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_8d450b016dc8bec35f36729e4b0" FOREIGN KEY ("public_updates_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_95828668aa333460582e0ca6396" FOREIGN KEY ("rules_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_cfc3d3ad260f8121c95b31a1fce" FOREIGN KEY ("system_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_9d1d665379eefde7876a17afa99" FOREIGN KEY ("widget_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_guilds"(
+                    "id",
+                    "afk_channel_id",
+                    "afk_timeout",
+                    "banner",
+                    "default_message_notifications",
+                    "description",
+                    "discovery_splash",
+                    "explicit_content_filter",
+                    "features",
+                    "primary_category_id",
+                    "icon",
+                    "large",
+                    "max_members",
+                    "max_presences",
+                    "max_video_channel_users",
+                    "member_count",
+                    "presence_count",
+                    "template_id",
+                    "mfa_level",
+                    "name",
+                    "owner_id",
+                    "preferred_locale",
+                    "premium_subscription_count",
+                    "premium_tier",
+                    "public_updates_channel_id",
+                    "rules_channel_id",
+                    "region",
+                    "splash",
+                    "system_channel_id",
+                    "system_channel_flags",
+                    "unavailable",
+                    "verification_level",
+                    "welcome_screen",
+                    "widget_channel_id",
+                    "widget_enabled",
+                    "nsfw_level",
+                    "nsfw",
+                    "parent",
+                    "premium_progress_bar_enabled"
+                )
+            SELECT "id",
+                "afk_channel_id",
+                "afk_timeout",
+                "banner",
+                "default_message_notifications",
+                "description",
+                "discovery_splash",
+                "explicit_content_filter",
+                "features",
+                "primary_category_id",
+                "icon",
+                "large",
+                "max_members",
+                "max_presences",
+                "max_video_channel_users",
+                "member_count",
+                "presence_count",
+                "template_id",
+                "mfa_level",
+                "name",
+                "owner_id",
+                "preferred_locale",
+                "premium_subscription_count",
+                "premium_tier",
+                "public_updates_channel_id",
+                "rules_channel_id",
+                "region",
+                "splash",
+                "system_channel_id",
+                "system_channel_flags",
+                "unavailable",
+                "verification_level",
+                "welcome_screen",
+                "widget_channel_id",
+                "widget_enabled",
+                "nsfw_level",
+                "nsfw",
+                "parent",
+                "premium_progress_bar_enabled"
+            FROM "guilds"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "guilds"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_guilds"
+                RENAME TO "guilds"
+        `);
+	}
+
+	public async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE "guilds"
+                RENAME TO "temporary_guilds"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "guilds" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "afk_channel_id" varchar,
+                "afk_timeout" integer,
+                "banner" varchar,
+                "default_message_notifications" integer,
+                "description" varchar,
+                "discovery_splash" varchar,
+                "explicit_content_filter" integer,
+                "features" text NOT NULL,
+                "primary_category_id" integer,
+                "icon" varchar,
+                "large" boolean,
+                "max_members" integer,
+                "max_presences" integer,
+                "max_video_channel_users" integer,
+                "member_count" integer,
+                "presence_count" integer,
+                "template_id" varchar,
+                "mfa_level" integer,
+                "name" varchar NOT NULL,
+                "owner_id" varchar,
+                "preferred_locale" varchar,
+                "premium_subscription_count" integer,
+                "premium_tier" integer,
+                "public_updates_channel_id" varchar,
+                "rules_channel_id" varchar,
+                "region" varchar,
+                "splash" varchar,
+                "system_channel_id" varchar,
+                "system_channel_flags" integer,
+                "unavailable" boolean,
+                "verification_level" integer,
+                "welcome_screen" text NOT NULL,
+                "widget_channel_id" varchar,
+                "widget_enabled" boolean,
+                "nsfw_level" integer,
+                "nsfw" boolean,
+                "parent" varchar,
+                "premium_progress_bar_enabled" boolean NOT NULL,
+                CONSTRAINT "FK_f591a66b8019d87b0fe6c12dad6" FOREIGN KEY ("afk_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_e2a2f873a64a5cf62526de42325" FOREIGN KEY ("template_id") REFERENCES "templates" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_fc1a451727e3643ca572a3bb394" FOREIGN KEY ("owner_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_8d450b016dc8bec35f36729e4b0" FOREIGN KEY ("public_updates_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_95828668aa333460582e0ca6396" FOREIGN KEY ("rules_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_cfc3d3ad260f8121c95b31a1fce" FOREIGN KEY ("system_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_9d1d665379eefde7876a17afa99" FOREIGN KEY ("widget_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "guilds"(
+                    "id",
+                    "afk_channel_id",
+                    "afk_timeout",
+                    "banner",
+                    "default_message_notifications",
+                    "description",
+                    "discovery_splash",
+                    "explicit_content_filter",
+                    "features",
+                    "primary_category_id",
+                    "icon",
+                    "large",
+                    "max_members",
+                    "max_presences",
+                    "max_video_channel_users",
+                    "member_count",
+                    "presence_count",
+                    "template_id",
+                    "mfa_level",
+                    "name",
+                    "owner_id",
+                    "preferred_locale",
+                    "premium_subscription_count",
+                    "premium_tier",
+                    "public_updates_channel_id",
+                    "rules_channel_id",
+                    "region",
+                    "splash",
+                    "system_channel_id",
+                    "system_channel_flags",
+                    "unavailable",
+                    "verification_level",
+                    "welcome_screen",
+                    "widget_channel_id",
+                    "widget_enabled",
+                    "nsfw_level",
+                    "nsfw",
+                    "parent",
+                    "premium_progress_bar_enabled"
+                )
+            SELECT "id",
+                "afk_channel_id",
+                "afk_timeout",
+                "banner",
+                "default_message_notifications",
+                "description",
+                "discovery_splash",
+                "explicit_content_filter",
+                "features",
+                "primary_category_id",
+                "icon",
+                "large",
+                "max_members",
+                "max_presences",
+                "max_video_channel_users",
+                "member_count",
+                "presence_count",
+                "template_id",
+                "mfa_level",
+                "name",
+                "owner_id",
+                "preferred_locale",
+                "premium_subscription_count",
+                "premium_tier",
+                "public_updates_channel_id",
+                "rules_channel_id",
+                "region",
+                "splash",
+                "system_channel_id",
+                "system_channel_flags",
+                "unavailable",
+                "verification_level",
+                "welcome_screen",
+                "widget_channel_id",
+                "widget_enabled",
+                "nsfw_level",
+                "nsfw",
+                "parent",
+                "premium_progress_bar_enabled"
+            FROM "temporary_guilds"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_guilds"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "guilds"
+                RENAME TO "temporary_guilds"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "guilds" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "afk_channel_id" varchar,
+                "afk_timeout" integer,
+                "banner" varchar,
+                "default_message_notifications" integer,
+                "description" varchar,
+                "discovery_splash" varchar,
+                "explicit_content_filter" integer,
+                "features" text NOT NULL,
+                "primary_category_id" integer,
+                "icon" varchar,
+                "large" boolean,
+                "max_members" integer,
+                "max_presences" integer,
+                "max_video_channel_users" integer,
+                "member_count" integer,
+                "presence_count" integer,
+                "template_id" varchar,
+                "mfa_level" integer,
+                "name" varchar NOT NULL,
+                "owner_id" varchar,
+                "preferred_locale" varchar,
+                "premium_subscription_count" integer,
+                "premium_tier" integer,
+                "public_updates_channel_id" varchar,
+                "rules_channel_id" varchar,
+                "region" varchar,
+                "splash" varchar,
+                "system_channel_id" varchar,
+                "system_channel_flags" integer,
+                "unavailable" boolean,
+                "verification_level" integer,
+                "welcome_screen" text NOT NULL,
+                "widget_channel_id" varchar,
+                "widget_enabled" boolean,
+                "nsfw_level" integer,
+                "nsfw" boolean,
+                "parent" varchar,
+                "premium_progress_bar_enabled" boolean NOT NULL,
+                CONSTRAINT "FK_f591a66b8019d87b0fe6c12dad6" FOREIGN KEY ("afk_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_e2a2f873a64a5cf62526de42325" FOREIGN KEY ("template_id") REFERENCES "templates" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_fc1a451727e3643ca572a3bb394" FOREIGN KEY ("owner_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_8d450b016dc8bec35f36729e4b0" FOREIGN KEY ("public_updates_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_95828668aa333460582e0ca6396" FOREIGN KEY ("rules_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_cfc3d3ad260f8121c95b31a1fce" FOREIGN KEY ("system_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_9d1d665379eefde7876a17afa99" FOREIGN KEY ("widget_channel_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "guilds"(
+                    "id",
+                    "afk_channel_id",
+                    "afk_timeout",
+                    "banner",
+                    "default_message_notifications",
+                    "description",
+                    "discovery_splash",
+                    "explicit_content_filter",
+                    "features",
+                    "primary_category_id",
+                    "icon",
+                    "large",
+                    "max_members",
+                    "max_presences",
+                    "max_video_channel_users",
+                    "member_count",
+                    "presence_count",
+                    "template_id",
+                    "mfa_level",
+                    "name",
+                    "owner_id",
+                    "preferred_locale",
+                    "premium_subscription_count",
+                    "premium_tier",
+                    "public_updates_channel_id",
+                    "rules_channel_id",
+                    "region",
+                    "splash",
+                    "system_channel_id",
+                    "system_channel_flags",
+                    "unavailable",
+                    "verification_level",
+                    "welcome_screen",
+                    "widget_channel_id",
+                    "widget_enabled",
+                    "nsfw_level",
+                    "nsfw",
+                    "parent",
+                    "premium_progress_bar_enabled"
+                )
+            SELECT "id",
+                "afk_channel_id",
+                "afk_timeout",
+                "banner",
+                "default_message_notifications",
+                "description",
+                "discovery_splash",
+                "explicit_content_filter",
+                "features",
+                "primary_category_id",
+                "icon",
+                "large",
+                "max_members",
+                "max_presences",
+                "max_video_channel_users",
+                "member_count",
+                "presence_count",
+                "template_id",
+                "mfa_level",
+                "name",
+                "owner_id",
+                "preferred_locale",
+                "premium_subscription_count",
+                "premium_tier",
+                "public_updates_channel_id",
+                "rules_channel_id",
+                "region",
+                "splash",
+                "system_channel_id",
+                "system_channel_flags",
+                "unavailable",
+                "verification_level",
+                "welcome_screen",
+                "widget_channel_id",
+                "widget_enabled",
+                "nsfw_level",
+                "nsfw",
+                "parent",
+                "premium_progress_bar_enabled"
+            FROM "temporary_guilds"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_guilds"
+        `);
+	}
+}
diff --git a/src/util/migrations/sqlite/1660258351379-CodeCleanup3.ts b/src/util/migrations/sqlite/1660258351379-CodeCleanup3.ts
new file mode 100644
index 00000000..b19864fa
--- /dev/null
+++ b/src/util/migrations/sqlite/1660258351379-CodeCleanup3.ts
@@ -0,0 +1,230 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class CodeCleanup31660258351379 implements MigrationInterface {
+	name = "CodeCleanup31660258351379";
+
+	public async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            CREATE TABLE "temporary_users" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "username" varchar NOT NULL,
+                "discriminator" varchar NOT NULL,
+                "avatar" varchar,
+                "accent_color" integer,
+                "banner" varchar,
+                "phone" varchar,
+                "desktop" boolean NOT NULL,
+                "mobile" boolean NOT NULL,
+                "premium" boolean NOT NULL,
+                "premium_type" integer NOT NULL,
+                "bot" boolean NOT NULL,
+                "bio" varchar NOT NULL,
+                "system" boolean NOT NULL,
+                "nsfw_allowed" boolean NOT NULL,
+                "mfa_enabled" boolean NOT NULL,
+                "totp_secret" varchar,
+                "totp_last_ticket" varchar,
+                "created_at" datetime NOT NULL,
+                "premium_since" datetime,
+                "verified" boolean NOT NULL,
+                "disabled" boolean NOT NULL,
+                "deleted" boolean NOT NULL,
+                "email" varchar,
+                "flags" varchar NOT NULL,
+                "public_flags" integer NOT NULL,
+                "rights" bigint NOT NULL,
+                "data" text NOT NULL,
+                "fingerprints" text NOT NULL,
+                "extended_settings" text NOT NULL,
+                "notes" text NOT NULL
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_users"(
+                    "id",
+                    "username",
+                    "discriminator",
+                    "avatar",
+                    "accent_color",
+                    "banner",
+                    "phone",
+                    "desktop",
+                    "mobile",
+                    "premium",
+                    "premium_type",
+                    "bot",
+                    "bio",
+                    "system",
+                    "nsfw_allowed",
+                    "mfa_enabled",
+                    "totp_secret",
+                    "totp_last_ticket",
+                    "created_at",
+                    "premium_since",
+                    "verified",
+                    "disabled",
+                    "deleted",
+                    "email",
+                    "flags",
+                    "public_flags",
+                    "rights",
+                    "data",
+                    "fingerprints",
+                    "extended_settings",
+                    "notes"
+                )
+            SELECT "id",
+                "username",
+                "discriminator",
+                "avatar",
+                "accent_color",
+                "banner",
+                "phone",
+                "desktop",
+                "mobile",
+                "premium",
+                "premium_type",
+                "bot",
+                "bio",
+                "system",
+                "nsfw_allowed",
+                "mfa_enabled",
+                "totp_secret",
+                "totp_last_ticket",
+                "created_at",
+                "premium_since",
+                "verified",
+                "disabled",
+                "deleted",
+                "email",
+                "flags",
+                "public_flags",
+                "rights",
+                "data",
+                "fingerprints",
+                "extended_settings",
+                "notes"
+            FROM "users"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "users"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_users"
+                RENAME TO "users"
+        `);
+	}
+
+	public async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE "users"
+                RENAME TO "temporary_users"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "users" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "username" varchar NOT NULL,
+                "discriminator" varchar NOT NULL,
+                "avatar" varchar,
+                "accent_color" integer,
+                "banner" varchar,
+                "phone" varchar,
+                "desktop" boolean NOT NULL,
+                "mobile" boolean NOT NULL,
+                "premium" boolean NOT NULL,
+                "premium_type" integer NOT NULL,
+                "bot" boolean NOT NULL,
+                "bio" varchar NOT NULL,
+                "system" boolean NOT NULL,
+                "nsfw_allowed" boolean NOT NULL,
+                "mfa_enabled" boolean NOT NULL,
+                "totp_secret" varchar,
+                "totp_last_ticket" varchar,
+                "created_at" datetime NOT NULL,
+                "premium_since" datetime,
+                "verified" boolean NOT NULL,
+                "disabled" boolean NOT NULL,
+                "deleted" boolean NOT NULL,
+                "email" varchar,
+                "flags" varchar NOT NULL,
+                "public_flags" integer NOT NULL,
+                "rights" bigint NOT NULL,
+                "data" text NOT NULL,
+                "fingerprints" text NOT NULL,
+                "settings" text NOT NULL,
+                "extended_settings" text NOT NULL,
+                "notes" text NOT NULL
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "users"(
+                    "id",
+                    "username",
+                    "discriminator",
+                    "avatar",
+                    "accent_color",
+                    "banner",
+                    "phone",
+                    "desktop",
+                    "mobile",
+                    "premium",
+                    "premium_type",
+                    "bot",
+                    "bio",
+                    "system",
+                    "nsfw_allowed",
+                    "mfa_enabled",
+                    "totp_secret",
+                    "totp_last_ticket",
+                    "created_at",
+                    "premium_since",
+                    "verified",
+                    "disabled",
+                    "deleted",
+                    "email",
+                    "flags",
+                    "public_flags",
+                    "rights",
+                    "data",
+                    "fingerprints",
+                    "extended_settings",
+                    "notes"
+                )
+            SELECT "id",
+                "username",
+                "discriminator",
+                "avatar",
+                "accent_color",
+                "banner",
+                "phone",
+                "desktop",
+                "mobile",
+                "premium",
+                "premium_type",
+                "bot",
+                "bio",
+                "system",
+                "nsfw_allowed",
+                "mfa_enabled",
+                "totp_secret",
+                "totp_last_ticket",
+                "created_at",
+                "premium_since",
+                "verified",
+                "disabled",
+                "deleted",
+                "email",
+                "flags",
+                "public_flags",
+                "rights",
+                "data",
+                "fingerprints",
+                "extended_settings",
+                "notes"
+            FROM "temporary_users"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_users"
+        `);
+	}
+}
diff --git a/src/util/migrations/sqlite/1660260672914-CodeCleanup4.ts b/src/util/migrations/sqlite/1660260672914-CodeCleanup4.ts
new file mode 100644
index 00000000..ed284bc8
--- /dev/null
+++ b/src/util/migrations/sqlite/1660260672914-CodeCleanup4.ts
@@ -0,0 +1,458 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class CodeCleanup41660260672914 implements MigrationInterface {
+	name = "CodeCleanup41660260672914";
+
+	public async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            CREATE TABLE "temporary_users" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "username" varchar NOT NULL,
+                "discriminator" varchar NOT NULL,
+                "avatar" varchar,
+                "accent_color" integer,
+                "banner" varchar,
+                "phone" varchar,
+                "desktop" boolean NOT NULL,
+                "mobile" boolean NOT NULL,
+                "premium" boolean NOT NULL,
+                "premium_type" integer NOT NULL,
+                "bot" boolean NOT NULL,
+                "bio" varchar NOT NULL,
+                "system" boolean NOT NULL,
+                "nsfw_allowed" boolean NOT NULL,
+                "mfa_enabled" boolean NOT NULL,
+                "totp_secret" varchar,
+                "totp_last_ticket" varchar,
+                "created_at" datetime NOT NULL,
+                "premium_since" datetime,
+                "verified" boolean NOT NULL,
+                "disabled" boolean NOT NULL,
+                "deleted" boolean NOT NULL,
+                "email" varchar,
+                "flags" varchar NOT NULL,
+                "public_flags" integer NOT NULL,
+                "rights" bigint NOT NULL,
+                "data" text NOT NULL,
+                "fingerprints" text NOT NULL,
+                "extended_settings" text NOT NULL,
+                "notes" text NOT NULL,
+                "settingsId" varchar,
+                CONSTRAINT "UQ_b1dd13b6ed980004a795ca184a6" UNIQUE ("settingsId")
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_users"(
+                    "id",
+                    "username",
+                    "discriminator",
+                    "avatar",
+                    "accent_color",
+                    "banner",
+                    "phone",
+                    "desktop",
+                    "mobile",
+                    "premium",
+                    "premium_type",
+                    "bot",
+                    "bio",
+                    "system",
+                    "nsfw_allowed",
+                    "mfa_enabled",
+                    "totp_secret",
+                    "totp_last_ticket",
+                    "created_at",
+                    "premium_since",
+                    "verified",
+                    "disabled",
+                    "deleted",
+                    "email",
+                    "flags",
+                    "public_flags",
+                    "rights",
+                    "data",
+                    "fingerprints",
+                    "extended_settings",
+                    "notes"
+                )
+            SELECT "id",
+                "username",
+                "discriminator",
+                "avatar",
+                "accent_color",
+                "banner",
+                "phone",
+                "desktop",
+                "mobile",
+                "premium",
+                "premium_type",
+                "bot",
+                "bio",
+                "system",
+                "nsfw_allowed",
+                "mfa_enabled",
+                "totp_secret",
+                "totp_last_ticket",
+                "created_at",
+                "premium_since",
+                "verified",
+                "disabled",
+                "deleted",
+                "email",
+                "flags",
+                "public_flags",
+                "rights",
+                "data",
+                "fingerprints",
+                "extended_settings",
+                "notes"
+            FROM "users"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "users"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_users"
+                RENAME TO "users"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_users" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "username" varchar NOT NULL,
+                "discriminator" varchar NOT NULL,
+                "avatar" varchar,
+                "accent_color" integer,
+                "banner" varchar,
+                "phone" varchar,
+                "desktop" boolean NOT NULL,
+                "mobile" boolean NOT NULL,
+                "premium" boolean NOT NULL,
+                "premium_type" integer NOT NULL,
+                "bot" boolean NOT NULL,
+                "bio" varchar NOT NULL,
+                "system" boolean NOT NULL,
+                "nsfw_allowed" boolean NOT NULL,
+                "mfa_enabled" boolean NOT NULL,
+                "totp_secret" varchar,
+                "totp_last_ticket" varchar,
+                "created_at" datetime NOT NULL,
+                "premium_since" datetime,
+                "verified" boolean NOT NULL,
+                "disabled" boolean NOT NULL,
+                "deleted" boolean NOT NULL,
+                "email" varchar,
+                "flags" varchar NOT NULL,
+                "public_flags" integer NOT NULL,
+                "rights" bigint NOT NULL,
+                "data" text NOT NULL,
+                "fingerprints" text NOT NULL,
+                "extended_settings" text NOT NULL,
+                "notes" text NOT NULL,
+                "settingsId" varchar,
+                CONSTRAINT "UQ_b1dd13b6ed980004a795ca184a6" UNIQUE ("settingsId"),
+                CONSTRAINT "FK_76ba283779c8441fd5ff819c8cf" FOREIGN KEY ("settingsId") REFERENCES "user_settings" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_users"(
+                    "id",
+                    "username",
+                    "discriminator",
+                    "avatar",
+                    "accent_color",
+                    "banner",
+                    "phone",
+                    "desktop",
+                    "mobile",
+                    "premium",
+                    "premium_type",
+                    "bot",
+                    "bio",
+                    "system",
+                    "nsfw_allowed",
+                    "mfa_enabled",
+                    "totp_secret",
+                    "totp_last_ticket",
+                    "created_at",
+                    "premium_since",
+                    "verified",
+                    "disabled",
+                    "deleted",
+                    "email",
+                    "flags",
+                    "public_flags",
+                    "rights",
+                    "data",
+                    "fingerprints",
+                    "extended_settings",
+                    "notes",
+                    "settingsId"
+                )
+            SELECT "id",
+                "username",
+                "discriminator",
+                "avatar",
+                "accent_color",
+                "banner",
+                "phone",
+                "desktop",
+                "mobile",
+                "premium",
+                "premium_type",
+                "bot",
+                "bio",
+                "system",
+                "nsfw_allowed",
+                "mfa_enabled",
+                "totp_secret",
+                "totp_last_ticket",
+                "created_at",
+                "premium_since",
+                "verified",
+                "disabled",
+                "deleted",
+                "email",
+                "flags",
+                "public_flags",
+                "rights",
+                "data",
+                "fingerprints",
+                "extended_settings",
+                "notes",
+                "settingsId"
+            FROM "users"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "users"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_users"
+                RENAME TO "users"
+        `);
+	}
+
+	public async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE "users"
+                RENAME TO "temporary_users"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "users" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "username" varchar NOT NULL,
+                "discriminator" varchar NOT NULL,
+                "avatar" varchar,
+                "accent_color" integer,
+                "banner" varchar,
+                "phone" varchar,
+                "desktop" boolean NOT NULL,
+                "mobile" boolean NOT NULL,
+                "premium" boolean NOT NULL,
+                "premium_type" integer NOT NULL,
+                "bot" boolean NOT NULL,
+                "bio" varchar NOT NULL,
+                "system" boolean NOT NULL,
+                "nsfw_allowed" boolean NOT NULL,
+                "mfa_enabled" boolean NOT NULL,
+                "totp_secret" varchar,
+                "totp_last_ticket" varchar,
+                "created_at" datetime NOT NULL,
+                "premium_since" datetime,
+                "verified" boolean NOT NULL,
+                "disabled" boolean NOT NULL,
+                "deleted" boolean NOT NULL,
+                "email" varchar,
+                "flags" varchar NOT NULL,
+                "public_flags" integer NOT NULL,
+                "rights" bigint NOT NULL,
+                "data" text NOT NULL,
+                "fingerprints" text NOT NULL,
+                "extended_settings" text NOT NULL,
+                "notes" text NOT NULL,
+                "settingsId" varchar,
+                CONSTRAINT "UQ_b1dd13b6ed980004a795ca184a6" UNIQUE ("settingsId")
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "users"(
+                    "id",
+                    "username",
+                    "discriminator",
+                    "avatar",
+                    "accent_color",
+                    "banner",
+                    "phone",
+                    "desktop",
+                    "mobile",
+                    "premium",
+                    "premium_type",
+                    "bot",
+                    "bio",
+                    "system",
+                    "nsfw_allowed",
+                    "mfa_enabled",
+                    "totp_secret",
+                    "totp_last_ticket",
+                    "created_at",
+                    "premium_since",
+                    "verified",
+                    "disabled",
+                    "deleted",
+                    "email",
+                    "flags",
+                    "public_flags",
+                    "rights",
+                    "data",
+                    "fingerprints",
+                    "extended_settings",
+                    "notes",
+                    "settingsId"
+                )
+            SELECT "id",
+                "username",
+                "discriminator",
+                "avatar",
+                "accent_color",
+                "banner",
+                "phone",
+                "desktop",
+                "mobile",
+                "premium",
+                "premium_type",
+                "bot",
+                "bio",
+                "system",
+                "nsfw_allowed",
+                "mfa_enabled",
+                "totp_secret",
+                "totp_last_ticket",
+                "created_at",
+                "premium_since",
+                "verified",
+                "disabled",
+                "deleted",
+                "email",
+                "flags",
+                "public_flags",
+                "rights",
+                "data",
+                "fingerprints",
+                "extended_settings",
+                "notes",
+                "settingsId"
+            FROM "temporary_users"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_users"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "users"
+                RENAME TO "temporary_users"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "users" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "username" varchar NOT NULL,
+                "discriminator" varchar NOT NULL,
+                "avatar" varchar,
+                "accent_color" integer,
+                "banner" varchar,
+                "phone" varchar,
+                "desktop" boolean NOT NULL,
+                "mobile" boolean NOT NULL,
+                "premium" boolean NOT NULL,
+                "premium_type" integer NOT NULL,
+                "bot" boolean NOT NULL,
+                "bio" varchar NOT NULL,
+                "system" boolean NOT NULL,
+                "nsfw_allowed" boolean NOT NULL,
+                "mfa_enabled" boolean NOT NULL,
+                "totp_secret" varchar,
+                "totp_last_ticket" varchar,
+                "created_at" datetime NOT NULL,
+                "premium_since" datetime,
+                "verified" boolean NOT NULL,
+                "disabled" boolean NOT NULL,
+                "deleted" boolean NOT NULL,
+                "email" varchar,
+                "flags" varchar NOT NULL,
+                "public_flags" integer NOT NULL,
+                "rights" bigint NOT NULL,
+                "data" text NOT NULL,
+                "fingerprints" text NOT NULL,
+                "extended_settings" text NOT NULL,
+                "notes" text NOT NULL
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "users"(
+                    "id",
+                    "username",
+                    "discriminator",
+                    "avatar",
+                    "accent_color",
+                    "banner",
+                    "phone",
+                    "desktop",
+                    "mobile",
+                    "premium",
+                    "premium_type",
+                    "bot",
+                    "bio",
+                    "system",
+                    "nsfw_allowed",
+                    "mfa_enabled",
+                    "totp_secret",
+                    "totp_last_ticket",
+                    "created_at",
+                    "premium_since",
+                    "verified",
+                    "disabled",
+                    "deleted",
+                    "email",
+                    "flags",
+                    "public_flags",
+                    "rights",
+                    "data",
+                    "fingerprints",
+                    "extended_settings",
+                    "notes"
+                )
+            SELECT "id",
+                "username",
+                "discriminator",
+                "avatar",
+                "accent_color",
+                "banner",
+                "phone",
+                "desktop",
+                "mobile",
+                "premium",
+                "premium_type",
+                "bot",
+                "bio",
+                "system",
+                "nsfw_allowed",
+                "mfa_enabled",
+                "totp_secret",
+                "totp_last_ticket",
+                "created_at",
+                "premium_since",
+                "verified",
+                "disabled",
+                "deleted",
+                "email",
+                "flags",
+                "public_flags",
+                "rights",
+                "data",
+                "fingerprints",
+                "extended_settings",
+                "notes"
+            FROM "temporary_users"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_users"
+        `);
+	}
+}
diff --git a/src/util/migrations/sqlite/1660416010862-InvitersAreDeletable.ts b/src/util/migrations/sqlite/1660416010862-InvitersAreDeletable.ts
new file mode 100644
index 00000000..a05082c6
--- /dev/null
+++ b/src/util/migrations/sqlite/1660416010862-InvitersAreDeletable.ts
@@ -0,0 +1,245 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class InvitersAreDeletable1660416010862 implements MigrationInterface {
+	name = "InvitersAreDeletable1660416010862";
+
+	public async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            CREATE TABLE "temporary_invites" (
+                "code" varchar PRIMARY KEY NOT NULL,
+                "temporary" boolean NOT NULL,
+                "uses" integer NOT NULL,
+                "max_uses" integer NOT NULL,
+                "max_age" integer NOT NULL,
+                "created_at" datetime NOT NULL,
+                "expires_at" datetime NOT NULL,
+                "guild_id" varchar,
+                "channel_id" varchar,
+                "inviter_id" varchar,
+                "target_user_id" varchar,
+                "target_user_type" integer,
+                "vanity_url" boolean,
+                CONSTRAINT "FK_11a0d394f8fc649c19ce5f16b59" FOREIGN KEY ("target_user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_6a15b051fe5050aa00a4b9ff0f6" FOREIGN KEY ("channel_id") REFERENCES "channels" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_3f4939aa1461e8af57fea3fb05d" FOREIGN KEY ("guild_id") REFERENCES "guilds" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_invites"(
+                    "code",
+                    "temporary",
+                    "uses",
+                    "max_uses",
+                    "max_age",
+                    "created_at",
+                    "expires_at",
+                    "guild_id",
+                    "channel_id",
+                    "inviter_id",
+                    "target_user_id",
+                    "target_user_type",
+                    "vanity_url"
+                )
+            SELECT "code",
+                "temporary",
+                "uses",
+                "max_uses",
+                "max_age",
+                "created_at",
+                "expires_at",
+                "guild_id",
+                "channel_id",
+                "inviter_id",
+                "target_user_id",
+                "target_user_type",
+                "vanity_url"
+            FROM "invites"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "invites"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_invites"
+                RENAME TO "invites"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "temporary_invites" (
+                "code" varchar PRIMARY KEY NOT NULL,
+                "temporary" boolean NOT NULL,
+                "uses" integer NOT NULL,
+                "max_uses" integer NOT NULL,
+                "max_age" integer NOT NULL,
+                "created_at" datetime NOT NULL,
+                "expires_at" datetime NOT NULL,
+                "guild_id" varchar,
+                "channel_id" varchar,
+                "inviter_id" varchar,
+                "target_user_id" varchar,
+                "target_user_type" integer,
+                "vanity_url" boolean,
+                CONSTRAINT "FK_11a0d394f8fc649c19ce5f16b59" FOREIGN KEY ("target_user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_6a15b051fe5050aa00a4b9ff0f6" FOREIGN KEY ("channel_id") REFERENCES "channels" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_3f4939aa1461e8af57fea3fb05d" FOREIGN KEY ("guild_id") REFERENCES "guilds" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_15c35422032e0b22b4ada95f48f" FOREIGN KEY ("inviter_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_invites"(
+                    "code",
+                    "temporary",
+                    "uses",
+                    "max_uses",
+                    "max_age",
+                    "created_at",
+                    "expires_at",
+                    "guild_id",
+                    "channel_id",
+                    "inviter_id",
+                    "target_user_id",
+                    "target_user_type",
+                    "vanity_url"
+                )
+            SELECT "code",
+                "temporary",
+                "uses",
+                "max_uses",
+                "max_age",
+                "created_at",
+                "expires_at",
+                "guild_id",
+                "channel_id",
+                "inviter_id",
+                "target_user_id",
+                "target_user_type",
+                "vanity_url"
+            FROM "invites"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "invites"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_invites"
+                RENAME TO "invites"
+        `);
+	}
+
+	public async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE "invites"
+                RENAME TO "temporary_invites"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "invites" (
+                "code" varchar PRIMARY KEY NOT NULL,
+                "temporary" boolean NOT NULL,
+                "uses" integer NOT NULL,
+                "max_uses" integer NOT NULL,
+                "max_age" integer NOT NULL,
+                "created_at" datetime NOT NULL,
+                "expires_at" datetime NOT NULL,
+                "guild_id" varchar,
+                "channel_id" varchar,
+                "inviter_id" varchar,
+                "target_user_id" varchar,
+                "target_user_type" integer,
+                "vanity_url" boolean,
+                CONSTRAINT "FK_11a0d394f8fc649c19ce5f16b59" FOREIGN KEY ("target_user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_6a15b051fe5050aa00a4b9ff0f6" FOREIGN KEY ("channel_id") REFERENCES "channels" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_3f4939aa1461e8af57fea3fb05d" FOREIGN KEY ("guild_id") REFERENCES "guilds" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "invites"(
+                    "code",
+                    "temporary",
+                    "uses",
+                    "max_uses",
+                    "max_age",
+                    "created_at",
+                    "expires_at",
+                    "guild_id",
+                    "channel_id",
+                    "inviter_id",
+                    "target_user_id",
+                    "target_user_type",
+                    "vanity_url"
+                )
+            SELECT "code",
+                "temporary",
+                "uses",
+                "max_uses",
+                "max_age",
+                "created_at",
+                "expires_at",
+                "guild_id",
+                "channel_id",
+                "inviter_id",
+                "target_user_id",
+                "target_user_type",
+                "vanity_url"
+            FROM "temporary_invites"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_invites"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "invites"
+                RENAME TO "temporary_invites"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "invites" (
+                "code" varchar PRIMARY KEY NOT NULL,
+                "temporary" boolean NOT NULL,
+                "uses" integer NOT NULL,
+                "max_uses" integer NOT NULL,
+                "max_age" integer NOT NULL,
+                "created_at" datetime NOT NULL,
+                "expires_at" datetime NOT NULL,
+                "guild_id" varchar,
+                "channel_id" varchar,
+                "inviter_id" varchar,
+                "target_user_id" varchar,
+                "target_user_type" integer,
+                "vanity_url" boolean,
+                CONSTRAINT "FK_11a0d394f8fc649c19ce5f16b59" FOREIGN KEY ("target_user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_15c35422032e0b22b4ada95f48f" FOREIGN KEY ("inviter_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_6a15b051fe5050aa00a4b9ff0f6" FOREIGN KEY ("channel_id") REFERENCES "channels" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+                CONSTRAINT "FK_3f4939aa1461e8af57fea3fb05d" FOREIGN KEY ("guild_id") REFERENCES "guilds" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "invites"(
+                    "code",
+                    "temporary",
+                    "uses",
+                    "max_uses",
+                    "max_age",
+                    "created_at",
+                    "expires_at",
+                    "guild_id",
+                    "channel_id",
+                    "inviter_id",
+                    "target_user_id",
+                    "target_user_type",
+                    "vanity_url"
+                )
+            SELECT "code",
+                "temporary",
+                "uses",
+                "max_uses",
+                "max_age",
+                "created_at",
+                "expires_at",
+                "guild_id",
+                "channel_id",
+                "inviter_id",
+                "target_user_id",
+                "target_user_type",
+                "vanity_url"
+            FROM "temporary_invites"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_invites"
+        `);
+	}
+}
diff --git a/src/util/migrations/sqlite/1660538628956-sync_migrations.ts b/src/util/migrations/sqlite/1660538628956-sync_migrations.ts
new file mode 100644
index 00000000..95c59d28
--- /dev/null
+++ b/src/util/migrations/sqlite/1660538628956-sync_migrations.ts
@@ -0,0 +1,171 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class syncMigrations1660538628956 implements MigrationInterface {
+	name = "syncMigrations1660538628956";
+
+	public async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            CREATE TABLE "temporary_channels" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "created_at" datetime NOT NULL,
+                "name" varchar,
+                "icon" text,
+                "type" integer NOT NULL,
+                "last_message_id" varchar,
+                "guild_id" varchar,
+                "parent_id" varchar,
+                "owner_id" varchar,
+                "last_pin_timestamp" integer,
+                "default_auto_archive_duration" integer,
+                "position" integer,
+                "permission_overwrites" text,
+                "video_quality_mode" integer,
+                "bitrate" integer,
+                "user_limit" integer,
+                "nsfw" boolean,
+                "rate_limit_per_user" integer,
+                "topic" varchar,
+                "retention_policy_id" varchar,
+                "flags" integer,
+                "default_thread_rate_limit_per_user" integer,
+                CONSTRAINT "FK_3873ed438575cce703ecff4fc7b" FOREIGN KEY ("owner_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_3274522d14af40540b1a883fc80" FOREIGN KEY ("parent_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_c253dafe5f3a03ec00cd8fb4581" FOREIGN KEY ("guild_id") REFERENCES "guilds" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_channels"(
+                    "id",
+                    "created_at",
+                    "name",
+                    "icon",
+                    "type",
+                    "last_message_id",
+                    "guild_id",
+                    "parent_id",
+                    "owner_id",
+                    "last_pin_timestamp",
+                    "default_auto_archive_duration",
+                    "position",
+                    "permission_overwrites",
+                    "video_quality_mode",
+                    "bitrate",
+                    "user_limit",
+                    "nsfw",
+                    "rate_limit_per_user",
+                    "topic",
+                    "retention_policy_id"
+                )
+            SELECT "id",
+                "created_at",
+                "name",
+                "icon",
+                "type",
+                "last_message_id",
+                "guild_id",
+                "parent_id",
+                "owner_id",
+                "last_pin_timestamp",
+                "default_auto_archive_duration",
+                "position",
+                "permission_overwrites",
+                "video_quality_mode",
+                "bitrate",
+                "user_limit",
+                "nsfw",
+                "rate_limit_per_user",
+                "topic",
+                "retention_policy_id"
+            FROM "channels"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "channels"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_channels"
+                RENAME TO "channels"
+        `);
+	}
+
+	public async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE "channels"
+                RENAME TO "temporary_channels"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "channels" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "created_at" datetime NOT NULL,
+                "name" varchar,
+                "icon" text,
+                "type" integer NOT NULL,
+                "last_message_id" varchar,
+                "guild_id" varchar,
+                "parent_id" varchar,
+                "owner_id" varchar,
+                "last_pin_timestamp" integer,
+                "default_auto_archive_duration" integer,
+                "position" integer,
+                "permission_overwrites" text,
+                "video_quality_mode" integer,
+                "bitrate" integer,
+                "user_limit" integer,
+                "nsfw" boolean,
+                "rate_limit_per_user" integer,
+                "topic" varchar,
+                "retention_policy_id" varchar,
+                CONSTRAINT "FK_3873ed438575cce703ecff4fc7b" FOREIGN KEY ("owner_id") REFERENCES "users" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_3274522d14af40540b1a883fc80" FOREIGN KEY ("parent_id") REFERENCES "channels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION,
+                CONSTRAINT "FK_c253dafe5f3a03ec00cd8fb4581" FOREIGN KEY ("guild_id") REFERENCES "guilds" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "channels"(
+                    "id",
+                    "created_at",
+                    "name",
+                    "icon",
+                    "type",
+                    "last_message_id",
+                    "guild_id",
+                    "parent_id",
+                    "owner_id",
+                    "last_pin_timestamp",
+                    "default_auto_archive_duration",
+                    "position",
+                    "permission_overwrites",
+                    "video_quality_mode",
+                    "bitrate",
+                    "user_limit",
+                    "nsfw",
+                    "rate_limit_per_user",
+                    "topic",
+                    "retention_policy_id"
+                )
+            SELECT "id",
+                "created_at",
+                "name",
+                "icon",
+                "type",
+                "last_message_id",
+                "guild_id",
+                "parent_id",
+                "owner_id",
+                "last_pin_timestamp",
+                "default_auto_archive_duration",
+                "position",
+                "permission_overwrites",
+                "video_quality_mode",
+                "bitrate",
+                "user_limit",
+                "nsfw",
+                "rate_limit_per_user",
+                "topic",
+                "retention_policy_id"
+            FROM "temporary_channels"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_channels"
+        `);
+	}
+}
diff --git a/src/util/migrations/sqlite/1660549233583-fix_nullables.ts b/src/util/migrations/sqlite/1660549233583-fix_nullables.ts
new file mode 100644
index 00000000..fa60bdc1
--- /dev/null
+++ b/src/util/migrations/sqlite/1660549233583-fix_nullables.ts
@@ -0,0 +1,239 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class fixNullables1660549233583 implements MigrationInterface {
+	name = "fixNullables1660549233583";
+
+	public async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            CREATE TABLE "temporary_users" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "username" varchar NOT NULL,
+                "discriminator" varchar NOT NULL,
+                "avatar" varchar,
+                "accent_color" integer,
+                "banner" varchar,
+                "phone" varchar,
+                "desktop" boolean NOT NULL,
+                "mobile" boolean NOT NULL,
+                "premium" boolean NOT NULL,
+                "premium_type" integer NOT NULL,
+                "bot" boolean NOT NULL,
+                "bio" varchar,
+                "system" boolean NOT NULL,
+                "nsfw_allowed" boolean NOT NULL,
+                "mfa_enabled" boolean,
+                "totp_secret" varchar,
+                "totp_last_ticket" varchar,
+                "created_at" datetime NOT NULL,
+                "premium_since" datetime,
+                "verified" boolean NOT NULL,
+                "disabled" boolean NOT NULL,
+                "deleted" boolean NOT NULL,
+                "email" varchar,
+                "flags" varchar NOT NULL,
+                "public_flags" integer NOT NULL,
+                "rights" bigint NOT NULL,
+                "data" text NOT NULL,
+                "fingerprints" text NOT NULL,
+                "extended_settings" text NOT NULL,
+                "notes" text NOT NULL,
+                "settingsId" varchar,
+                CONSTRAINT "UQ_b1dd13b6ed980004a795ca184a6" UNIQUE ("settingsId"),
+                CONSTRAINT "FK_76ba283779c8441fd5ff819c8cf" FOREIGN KEY ("settingsId") REFERENCES "user_settings" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "temporary_users"(
+                    "id",
+                    "username",
+                    "discriminator",
+                    "avatar",
+                    "accent_color",
+                    "banner",
+                    "phone",
+                    "desktop",
+                    "mobile",
+                    "premium",
+                    "premium_type",
+                    "bot",
+                    "bio",
+                    "system",
+                    "nsfw_allowed",
+                    "mfa_enabled",
+                    "totp_secret",
+                    "totp_last_ticket",
+                    "created_at",
+                    "premium_since",
+                    "verified",
+                    "disabled",
+                    "deleted",
+                    "email",
+                    "flags",
+                    "public_flags",
+                    "rights",
+                    "data",
+                    "fingerprints",
+                    "extended_settings",
+                    "notes",
+                    "settingsId"
+                )
+            SELECT "id",
+                "username",
+                "discriminator",
+                "avatar",
+                "accent_color",
+                "banner",
+                "phone",
+                "desktop",
+                "mobile",
+                "premium",
+                "premium_type",
+                "bot",
+                "bio",
+                "system",
+                "nsfw_allowed",
+                "mfa_enabled",
+                "totp_secret",
+                "totp_last_ticket",
+                "created_at",
+                "premium_since",
+                "verified",
+                "disabled",
+                "deleted",
+                "email",
+                "flags",
+                "public_flags",
+                "rights",
+                "data",
+                "fingerprints",
+                "extended_settings",
+                "notes",
+                "settingsId"
+            FROM "users"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "users"
+        `);
+		await queryRunner.query(`
+            ALTER TABLE "temporary_users"
+                RENAME TO "users"
+        `);
+	}
+
+	public async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`
+            ALTER TABLE "users"
+                RENAME TO "temporary_users"
+        `);
+		await queryRunner.query(`
+            CREATE TABLE "users" (
+                "id" varchar PRIMARY KEY NOT NULL,
+                "username" varchar NOT NULL,
+                "discriminator" varchar NOT NULL,
+                "avatar" varchar,
+                "accent_color" integer,
+                "banner" varchar,
+                "phone" varchar,
+                "desktop" boolean NOT NULL,
+                "mobile" boolean NOT NULL,
+                "premium" boolean NOT NULL,
+                "premium_type" integer NOT NULL,
+                "bot" boolean NOT NULL,
+                "bio" varchar NOT NULL,
+                "system" boolean NOT NULL,
+                "nsfw_allowed" boolean NOT NULL,
+                "mfa_enabled" boolean NOT NULL,
+                "totp_secret" varchar,
+                "totp_last_ticket" varchar,
+                "created_at" datetime NOT NULL,
+                "premium_since" datetime,
+                "verified" boolean NOT NULL,
+                "disabled" boolean NOT NULL,
+                "deleted" boolean NOT NULL,
+                "email" varchar,
+                "flags" varchar NOT NULL,
+                "public_flags" integer NOT NULL,
+                "rights" bigint NOT NULL,
+                "data" text NOT NULL,
+                "fingerprints" text NOT NULL,
+                "extended_settings" text NOT NULL,
+                "notes" text NOT NULL,
+                "settingsId" varchar,
+                CONSTRAINT "UQ_b1dd13b6ed980004a795ca184a6" UNIQUE ("settingsId"),
+                CONSTRAINT "FK_76ba283779c8441fd5ff819c8cf" FOREIGN KEY ("settingsId") REFERENCES "user_settings" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
+            )
+        `);
+		await queryRunner.query(`
+            INSERT INTO "users"(
+                    "id",
+                    "username",
+                    "discriminator",
+                    "avatar",
+                    "accent_color",
+                    "banner",
+                    "phone",
+                    "desktop",
+                    "mobile",
+                    "premium",
+                    "premium_type",
+                    "bot",
+                    "bio",
+                    "system",
+                    "nsfw_allowed",
+                    "mfa_enabled",
+                    "totp_secret",
+                    "totp_last_ticket",
+                    "created_at",
+                    "premium_since",
+                    "verified",
+                    "disabled",
+                    "deleted",
+                    "email",
+                    "flags",
+                    "public_flags",
+                    "rights",
+                    "data",
+                    "fingerprints",
+                    "extended_settings",
+                    "notes",
+                    "settingsId"
+                )
+            SELECT "id",
+                "username",
+                "discriminator",
+                "avatar",
+                "accent_color",
+                "banner",
+                "phone",
+                "desktop",
+                "mobile",
+                "premium",
+                "premium_type",
+                "bot",
+                "bio",
+                "system",
+                "nsfw_allowed",
+                "mfa_enabled",
+                "totp_secret",
+                "totp_last_ticket",
+                "created_at",
+                "premium_since",
+                "verified",
+                "disabled",
+                "deleted",
+                "email",
+                "flags",
+                "public_flags",
+                "rights",
+                "data",
+                "fingerprints",
+                "extended_settings",
+                "notes",
+                "settingsId"
+            FROM "temporary_users"
+        `);
+		await queryRunner.query(`
+            DROP TABLE "temporary_users"
+        `);
+	}
+}
diff --git a/src/util/schemas/ActivitySchema.ts b/src/util/schemas/ActivitySchema.ts
new file mode 100644
index 00000000..d94557ea
--- /dev/null
+++ b/src/util/schemas/ActivitySchema.ts
@@ -0,0 +1,51 @@
+import { Activity, Status } from "@fosscord/util";
+
+export const ActivitySchema = {
+	afk: Boolean,
+	status: String,
+	$activities: [
+		{
+			name: String,
+			type: Number,
+			$url: String,
+			$created_at: Date,
+			$timestamps: {
+				$start: Number,
+				$end: Number
+			},
+			$application_id: String,
+			$details: String,
+			$state: String,
+			$emoji: {
+				$name: String,
+				$id: String,
+				$animated: Boolean
+			},
+			$party: {
+				$id: String,
+				$size: [Number, Number]
+			},
+			$assets: {
+				$large_image: String,
+				$large_text: String,
+				$small_image: String,
+				$small_text: String
+			},
+			$secrets: {
+				$join: String,
+				$spectate: String,
+				$match: String
+			},
+			$instance: Boolean,
+			$flags: String
+		}
+	],
+	$since: Number // unix time (in milliseconds) of when the client went idle, or null if the client is not idle
+};
+
+export interface ActivitySchema {
+	afk: boolean;
+	status: Status;
+	activities?: Activity[];
+	since?: number; // unix time (in milliseconds) of when the client went idle, or null if the client is not idle
+}
diff --git a/src/util/schemas/BanCreateSchema.ts b/src/util/schemas/BanCreateSchema.ts
new file mode 100644
index 00000000..834577dc
--- /dev/null
+++ b/src/util/schemas/BanCreateSchema.ts
@@ -0,0 +1,4 @@
+export interface BanCreateSchema {
+	delete_message_days?: string;
+	reason?: string;
+}
diff --git a/src/util/schemas/BanModeratorSchema.ts b/src/util/schemas/BanModeratorSchema.ts
new file mode 100644
index 00000000..afb76433
--- /dev/null
+++ b/src/util/schemas/BanModeratorSchema.ts
@@ -0,0 +1,7 @@
+export interface BanModeratorSchema {
+	id: string;
+	user_id: string;
+	guild_id: string;
+	executor_id: string;
+	reason?: string | undefined;
+}
diff --git a/src/util/schemas/BanRegistrySchema.ts b/src/util/schemas/BanRegistrySchema.ts
new file mode 100644
index 00000000..501f94dc
--- /dev/null
+++ b/src/util/schemas/BanRegistrySchema.ts
@@ -0,0 +1,8 @@
+export interface BanRegistrySchema {
+	id: string;
+	user_id: string;
+	guild_id: string;
+	executor_id: string;
+	ip?: string;
+	reason?: string | undefined;
+}
diff --git a/src/util/schemas/BulkDeleteSchema.ts b/src/util/schemas/BulkDeleteSchema.ts
new file mode 100644
index 00000000..bfc4df65
--- /dev/null
+++ b/src/util/schemas/BulkDeleteSchema.ts
@@ -0,0 +1,3 @@
+export interface BulkDeleteSchema {
+	messages: string[];
+}
diff --git a/src/util/schemas/ChannelModifySchema.ts b/src/util/schemas/ChannelModifySchema.ts
new file mode 100644
index 00000000..f5babef0
--- /dev/null
+++ b/src/util/schemas/ChannelModifySchema.ts
@@ -0,0 +1,28 @@
+import { ChannelPermissionOverwriteType, ChannelType } from "..";
+
+export interface ChannelModifySchema {
+	/**
+	 * @maxLength 100
+	 */
+	name?: string;
+	type?: ChannelType;
+	topic?: string;
+	icon?: string | null;
+	bitrate?: number;
+	user_limit?: number;
+	rate_limit_per_user?: number;
+	position?: number;
+	permission_overwrites?: {
+		id: string;
+		type: ChannelPermissionOverwriteType;
+		allow: string;
+		deny: string;
+	}[];
+	parent_id?: string;
+	id?: string; // is not used (only for guild create)
+	nsfw?: boolean;
+	rtc_region?: string;
+	default_auto_archive_duration?: number;
+	flags?: number;
+	default_thread_rate_limit_per_user?: number;
+}
diff --git a/src/util/schemas/ChannelPermissionOverwriteSchema.ts b/src/util/schemas/ChannelPermissionOverwriteSchema.ts
new file mode 100644
index 00000000..e8bc13bb
--- /dev/null
+++ b/src/util/schemas/ChannelPermissionOverwriteSchema.ts
@@ -0,0 +1,5 @@
+import { ChannelPermissionOverwrite } from "@fosscord/util";
+
+// 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 {}
diff --git a/src/util/schemas/ChannelReorderSchema.ts b/src/util/schemas/ChannelReorderSchema.ts
new file mode 100644
index 00000000..95c2eba9
--- /dev/null
+++ b/src/util/schemas/ChannelReorderSchema.ts
@@ -0,0 +1 @@
+export type ChannelReorderSchema = { id: string; position?: number; lock_permissions?: boolean; parent_id?: string }[];
diff --git a/src/util/schemas/DmChannelCreateSchema.ts b/src/util/schemas/DmChannelCreateSchema.ts
new file mode 100644
index 00000000..1b0fe86d
--- /dev/null
+++ b/src/util/schemas/DmChannelCreateSchema.ts
@@ -0,0 +1,4 @@
+export interface DmChannelCreateSchema {
+	name?: string;
+	recipients: string[];
+}
diff --git a/src/util/schemas/EmojiCreateSchema.ts b/src/util/schemas/EmojiCreateSchema.ts
new file mode 100644
index 00000000..34084713
--- /dev/null
+++ b/src/util/schemas/EmojiCreateSchema.ts
@@ -0,0 +1,6 @@
+export interface EmojiCreateSchema {
+	name?: string;
+	image: string;
+	require_colons?: boolean | null;
+	roles?: string[];
+}
diff --git a/src/util/schemas/EmojiModifySchema.ts b/src/util/schemas/EmojiModifySchema.ts
new file mode 100644
index 00000000..05d2d395
--- /dev/null
+++ b/src/util/schemas/EmojiModifySchema.ts
@@ -0,0 +1,4 @@
+export interface EmojiModifySchema {
+	name?: string;
+	roles?: string[];
+}
diff --git a/src/util/schemas/GuildCreateSchema.ts b/src/util/schemas/GuildCreateSchema.ts
new file mode 100644
index 00000000..e4855119
--- /dev/null
+++ b/src/util/schemas/GuildCreateSchema.ts
@@ -0,0 +1,14 @@
+import { ChannelModifySchema } from ".";
+
+export interface GuildCreateSchema {
+	/**
+	 * @maxLength 100
+	 */
+	name: string;
+	region?: string;
+	icon?: string | null;
+	channels?: ChannelModifySchema[];
+	guild_template_code?: string;
+	system_channel_id?: string;
+	rules_channel_id?: string;
+}
diff --git a/src/util/schemas/GuildTemplateCreateSchema.ts b/src/util/schemas/GuildTemplateCreateSchema.ts
new file mode 100644
index 00000000..59db8428
--- /dev/null
+++ b/src/util/schemas/GuildTemplateCreateSchema.ts
@@ -0,0 +1,4 @@
+export interface GuildTemplateCreateSchema {
+	name: string;
+	avatar?: string | null;
+}
diff --git a/src/util/schemas/GuildUpdateSchema.ts b/src/util/schemas/GuildUpdateSchema.ts
new file mode 100644
index 00000000..86527cf1
--- /dev/null
+++ b/src/util/schemas/GuildUpdateSchema.ts
@@ -0,0 +1,18 @@
+import { GuildCreateSchema } from ".";
+
+export interface GuildUpdateSchema extends Omit<GuildCreateSchema, "channels" | "name"> {
+	name?: string;
+	banner?: string | null;
+	splash?: string | null;
+	description?: string;
+	features?: string[];
+	verification_level?: number;
+	default_message_notifications?: number;
+	system_channel_flags?: number;
+	explicit_content_filter?: number;
+	public_updates_channel_id?: string;
+	afk_timeout?: number;
+	afk_channel_id?: string;
+	preferred_locale?: string;
+	premium_progress_bar_enabled?: boolean;
+}
diff --git a/src/util/schemas/GuildUpdateWelcomeScreenSchema.ts b/src/util/schemas/GuildUpdateWelcomeScreenSchema.ts
new file mode 100644
index 00000000..c8b8ba4e
--- /dev/null
+++ b/src/util/schemas/GuildUpdateWelcomeScreenSchema.ts
@@ -0,0 +1,10 @@
+export interface GuildUpdateWelcomeScreenSchema {
+	welcome_channels?: {
+		channel_id: string;
+		description: string;
+		emoji_id?: string;
+		emoji_name: string;
+	}[];
+	enabled?: boolean;
+	description?: string;
+}
diff --git a/src/util/schemas/IdentifySchema.ts b/src/util/schemas/IdentifySchema.ts
new file mode 100644
index 00000000..bb5ae0c8
--- /dev/null
+++ b/src/util/schemas/IdentifySchema.ts
@@ -0,0 +1,89 @@
+import { ActivitySchema } from "./ActivitySchema";
+
+export const IdentifySchema = {
+	token: String,
+	$intents: String, // discord uses a Integer for bitfields we use bigints tho. | instanceOf will automatically convert the Number to a BigInt
+	$properties: Object,
+	// {
+	// 	// discord uses $ in the property key for bots, so we need to double prefix it, because instanceOf treats $ (prefix) as a optional key
+	// 	$os: String,
+	// 	$os_arch: String,
+	// 	$browser: String,
+	// 	$device: String,
+	// 	$$os: String,
+	// 	$$browser: String,
+	// 	$$device: String,
+	// 	$browser_user_agent: String,
+	// 	$browser_version: String,
+	// 	$os_version: String,
+	// 	$referrer: String,
+	// 	$$referrer: String,
+	// 	$referring_domain: String,
+	// 	$$referring_domain: String,
+	// 	$referrer_current: String,
+	// 	$referring_domain_current: String,
+	// 	$release_channel: String,
+	// 	$client_build_number: Number,
+	// 	$client_event_source: String,
+	// 	$client_version: String,
+	// 	$system_locale: String,
+	// 	$window_manager: String,
+	// 	$distro: String,
+	// },
+	$presence: ActivitySchema,
+	$compress: Boolean,
+	$large_threshold: Number,
+	$shard: [Number, Number],
+	$guild_subscriptions: Boolean,
+	$capabilities: Number,
+	$client_state: {
+		$guild_hashes: Object,
+		$highest_last_message_id: String,
+		$read_state_version: Number,
+		$user_guild_settings_version: Number,
+		$user_settings_version: undefined
+	},
+	$v: Number,
+	$version: Number
+};
+
+export interface IdentifySchema {
+	token: string;
+	properties: {
+		// bruh discord really uses $ in the property key, so we need to double prefix it, because instanceOf treats $ (prefix) as a optional key
+		os?: string;
+		os_atch?: string;
+		browser?: string;
+		device?: string;
+		$os?: string;
+		$browser?: string;
+		$device?: string;
+		browser_user_agent?: string;
+		browser_version?: string;
+		os_version?: string;
+		referrer?: string;
+		referring_domain?: string;
+		referrer_current?: string;
+		referring_domain_current?: string;
+		release_channel?: "stable" | "dev" | "ptb" | "canary";
+		client_build_number?: number;
+		client_event_source?: any;
+		client_version?: string;
+		system_locale?: string;
+	};
+	intents?: string; // discord uses a Integer for bitfields we use bigints tho. | instanceOf will automatically convert the Number to a BigInt
+	presence?: ActivitySchema;
+	compress?: boolean;
+	large_threshold?: number;
+	shard?: [number, number];
+	guild_subscriptions?: boolean;
+	capabilities?: number;
+	client_state?: {
+		guild_hashes?: any;
+		highest_last_message_id?: string;
+		read_state_version?: number;
+		user_guild_settings_version?: number;
+		user_settings_version?: number;
+	};
+	v?: number;
+}
diff --git a/src/util/schemas/InviteCreateSchema.ts b/src/util/schemas/InviteCreateSchema.ts
new file mode 100644
index 00000000..cac11147
--- /dev/null
+++ b/src/util/schemas/InviteCreateSchema.ts
@@ -0,0 +1,11 @@
+export interface InviteCreateSchema {
+	target_user_id?: string;
+	target_type?: string;
+	validate?: string; // ? what is this
+	max_age?: number;
+	max_uses?: number;
+	temporary?: boolean;
+	unique?: boolean;
+	target_user?: string;
+	target_user_type?: number;
+}
diff --git a/src/util/schemas/LazyRequestSchema.ts b/src/util/schemas/LazyRequestSchema.ts
new file mode 100644
index 00000000..fbed5c5b
--- /dev/null
+++ b/src/util/schemas/LazyRequestSchema.ts
@@ -0,0 +1,19 @@
+export interface LazyRequest {
+	guild_id: string;
+	channels?: Record<string, [number, number][]>;
+	activities?: boolean;
+	threads?: boolean;
+	typing?: true;
+	members?: any[];
+	thread_member_lists?: any[];
+}
+
+export const LazyRequest = {
+	guild_id: String,
+	$activities: Boolean,
+	$channels: Object,
+	$typing: Boolean,
+	$threads: Boolean,
+	$members: [] as any[],
+	$thread_member_lists: [] as any[]
+};
diff --git a/src/util/schemas/LoginSchema.ts b/src/util/schemas/LoginSchema.ts
new file mode 100644
index 00000000..dc889d94
--- /dev/null
+++ b/src/util/schemas/LoginSchema.ts
@@ -0,0 +1,8 @@
+export interface LoginSchema {
+	login: string;
+	password: string;
+	undelete?: boolean;
+	captcha_key?: string;
+	login_source?: string;
+	gift_code_sku_id?: string;
+}
diff --git a/src/util/schemas/MemberChangeSchema.ts b/src/util/schemas/MemberChangeSchema.ts
new file mode 100644
index 00000000..db434538
--- /dev/null
+++ b/src/util/schemas/MemberChangeSchema.ts
@@ -0,0 +1,3 @@
+export interface MemberChangeSchema {
+	roles?: string[];
+}
diff --git a/src/util/schemas/MemberNickChangeSchema.ts b/src/util/schemas/MemberNickChangeSchema.ts
new file mode 100644
index 00000000..d863038c
--- /dev/null
+++ b/src/util/schemas/MemberNickChangeSchema.ts
@@ -0,0 +1,3 @@
+export interface MemberNickChangeSchema {
+	nick: string;
+}
diff --git a/src/util/schemas/MessageAcknowledgeSchema.ts b/src/util/schemas/MessageAcknowledgeSchema.ts
new file mode 100644
index 00000000..3f4eb2b6
--- /dev/null
+++ b/src/util/schemas/MessageAcknowledgeSchema.ts
@@ -0,0 +1,8 @@
+// TODO: public read receipts & privacy scoping
+// TODO: send read state event to all channel members
+// TODO: advance-only notification cursor
+
+export interface MessageAcknowledgeSchema {
+	manual?: boolean;
+	mention_count?: number;
+}
diff --git a/src/util/schemas/MessageCreateSchema.ts b/src/util/schemas/MessageCreateSchema.ts
new file mode 100644
index 00000000..bf3470bb
--- /dev/null
+++ b/src/util/schemas/MessageCreateSchema.ts
@@ -0,0 +1,33 @@
+import { Embed } from "@fosscord/util";
+
+export interface MessageCreateSchema {
+	type?: number;
+	content?: string;
+	nonce?: string;
+	channel_id?: string;
+	tts?: boolean;
+	flags?: string;
+	embeds?: Embed[];
+	embed?: Embed;
+	// TODO: ^ embed is deprecated in favor of embeds (https://discord.com/developers/docs/resources/channel#message-object)
+	allowed_mentions?: {
+		parse?: string[];
+		roles?: string[];
+		users?: string[];
+		replied_user?: boolean;
+	};
+	message_reference?: {
+		message_id: string;
+		channel_id: string;
+		guild_id?: string;
+		fail_if_not_exists?: boolean;
+	};
+	payload_json?: string;
+	file?: any;
+	/**
+	TODO: we should create an interface for attachments
+	TODO: OpenWAAO<-->attachment-style metadata conversion
+	**/
+	attachments?: any[];
+	sticker_ids?: string[];
+}
diff --git a/src/util/schemas/MfaCodesSchema.ts b/src/util/schemas/MfaCodesSchema.ts
new file mode 100644
index 00000000..ac05b9a4
--- /dev/null
+++ b/src/util/schemas/MfaCodesSchema.ts
@@ -0,0 +1,4 @@
+export interface MfaCodesSchema {
+	password: string;
+	regenerate?: boolean;
+}
diff --git a/src/util/schemas/ModifyGuildStickerSchema.ts b/src/util/schemas/ModifyGuildStickerSchema.ts
new file mode 100644
index 00000000..159cc44f
--- /dev/null
+++ b/src/util/schemas/ModifyGuildStickerSchema.ts
@@ -0,0 +1,15 @@
+export interface ModifyGuildStickerSchema {
+	/**
+	 * @minLength 2
+	 * @maxLength 30
+	 */
+	name: string;
+	/**
+	 * @maxLength 100
+	 */
+	description?: string;
+	/**
+	 * @maxLength 200
+	 */
+	tags: string;
+}
diff --git a/src/util/schemas/PruneSchema.ts b/src/util/schemas/PruneSchema.ts
new file mode 100644
index 00000000..bea5e2b4
--- /dev/null
+++ b/src/util/schemas/PruneSchema.ts
@@ -0,0 +1,6 @@
+export interface PruneSchema {
+	/**
+	 * @min 0
+	 */
+	days: number;
+}
diff --git a/src/util/schemas/PurgeSchema.ts b/src/util/schemas/PurgeSchema.ts
new file mode 100644
index 00000000..f5ab0a20
--- /dev/null
+++ b/src/util/schemas/PurgeSchema.ts
@@ -0,0 +1,4 @@
+export interface PurgeSchema {
+	before: string;
+	after: string;
+}
diff --git a/src/util/schemas/RegisterSchema.ts b/src/util/schemas/RegisterSchema.ts
new file mode 100644
index 00000000..9bbd9db5
--- /dev/null
+++ b/src/util/schemas/RegisterSchema.ts
@@ -0,0 +1,26 @@
+export interface RegisterSchema {
+	/**
+	 * @minLength 2
+	 * @maxLength 32
+	 */
+	username: string;
+	/**
+	 * @minLength 1
+	 * @maxLength 72
+	 */
+	password?: string;
+	consent: boolean;
+	/**
+	 * @TJS-format email
+	 */
+	email?: string;
+	fingerprint?: string;
+	invite?: string;
+	/**
+	 * @TJS-type string
+	 */
+	date_of_birth?: Date; // "2000-04-03"
+	gift_code_sku_id?: string;
+	captcha_key?: string;
+	promotional_email_opt_in?: boolean;
+}
diff --git a/src/util/schemas/RelationshipPostSchema.ts b/src/util/schemas/RelationshipPostSchema.ts
new file mode 100644
index 00000000..774c67f6
--- /dev/null
+++ b/src/util/schemas/RelationshipPostSchema.ts
@@ -0,0 +1,4 @@
+export interface RelationshipPostSchema {
+	discriminator: string;
+	username: string;
+}
diff --git a/src/util/schemas/RelationshipPutSchema.ts b/src/util/schemas/RelationshipPutSchema.ts
new file mode 100644
index 00000000..0a7f9720
--- /dev/null
+++ b/src/util/schemas/RelationshipPutSchema.ts
@@ -0,0 +1,5 @@
+import { RelationshipType } from "@fosscord/util";
+
+export interface RelationshipPutSchema {
+	type?: RelationshipType;
+}
diff --git a/src/util/schemas/RoleModifySchema.ts b/src/util/schemas/RoleModifySchema.ts
new file mode 100644
index 00000000..f3f4a20e
--- /dev/null
+++ b/src/util/schemas/RoleModifySchema.ts
@@ -0,0 +1,10 @@
+export interface RoleModifySchema {
+	name?: string;
+	permissions?: string;
+	color?: number;
+	hoist?: boolean; // whether the role should be displayed separately in the sidebar
+	mentionable?: boolean; // whether the role should be mentionable
+	position?: number;
+	icon?: string;
+	unicode_emoji?: string;
+}
diff --git a/src/util/schemas/RolePositionUpdateSchema.ts b/src/util/schemas/RolePositionUpdateSchema.ts
new file mode 100644
index 00000000..993d1ae0
--- /dev/null
+++ b/src/util/schemas/RolePositionUpdateSchema.ts
@@ -0,0 +1,4 @@
+export type RolePositionUpdateSchema = {
+	id: string;
+	position: number;
+}[];
diff --git a/src/util/schemas/TemplateCreateSchema.ts b/src/util/schemas/TemplateCreateSchema.ts
new file mode 100644
index 00000000..160934f5
--- /dev/null
+++ b/src/util/schemas/TemplateCreateSchema.ts
@@ -0,0 +1,4 @@
+export interface TemplateCreateSchema {
+	name: string;
+	description?: string;
+}
diff --git a/src/util/schemas/TemplateModifySchema.ts b/src/util/schemas/TemplateModifySchema.ts
new file mode 100644
index 00000000..f9c9d14b
--- /dev/null
+++ b/src/util/schemas/TemplateModifySchema.ts
@@ -0,0 +1,4 @@
+export interface TemplateModifySchema {
+	name: string;
+	description?: string;
+}
diff --git a/src/util/schemas/TotpDisableSchema.ts b/src/util/schemas/TotpDisableSchema.ts
new file mode 100644
index 00000000..51446e1c
--- /dev/null
+++ b/src/util/schemas/TotpDisableSchema.ts
@@ -0,0 +1,3 @@
+export interface TotpDisableSchema {
+	code: string;
+}
diff --git a/src/util/schemas/TotpEnableSchema.ts b/src/util/schemas/TotpEnableSchema.ts
new file mode 100644
index 00000000..4e3551d9
--- /dev/null
+++ b/src/util/schemas/TotpEnableSchema.ts
@@ -0,0 +1,5 @@
+export interface TotpEnableSchema {
+	password: string;
+	code?: string;
+	secret?: string;
+}
diff --git a/src/util/schemas/TotpSchema.ts b/src/util/schemas/TotpSchema.ts
new file mode 100644
index 00000000..941a92ec
--- /dev/null
+++ b/src/util/schemas/TotpSchema.ts
@@ -0,0 +1,6 @@
+export interface TotpSchema {
+	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
new file mode 100644
index 00000000..622497d9
--- /dev/null
+++ b/src/util/schemas/UserModifySchema.ts
@@ -0,0 +1,19 @@
+export interface UserModifySchema {
+	/**
+	 * @minLength 1
+	 * @maxLength 100
+	 */
+	username?: string;
+	discriminator?: string;
+	avatar?: string | null;
+	/**
+	 * @maxLength 1024
+	 */
+	bio?: string;
+	accent_color?: number;
+	banner?: string | null;
+	password?: string;
+	new_password?: string;
+	code?: string;
+	email?: string;
+}
diff --git a/src/util/schemas/UserSettingsSchema.ts b/src/util/schemas/UserSettingsSchema.ts
new file mode 100644
index 00000000..eb9b316d
--- /dev/null
+++ b/src/util/schemas/UserSettingsSchema.ts
@@ -0,0 +1,3 @@
+import { UserSettings } from "@fosscord/util";
+
+export interface UserSettingsSchema extends Partial<UserSettings> {}
diff --git a/src/util/schemas/VanityUrlSchema.ts b/src/util/schemas/VanityUrlSchema.ts
new file mode 100644
index 00000000..4dd9b9da
--- /dev/null
+++ b/src/util/schemas/VanityUrlSchema.ts
@@ -0,0 +1,7 @@
+export interface VanityUrlSchema {
+	/**
+	 * @minLength 1
+	 * @maxLength 20
+	 */
+	code?: string;
+}
diff --git a/src/util/schemas/VoiceStateUpdateSchema.ts b/src/util/schemas/VoiceStateUpdateSchema.ts
new file mode 100644
index 00000000..ea286b1a
--- /dev/null
+++ b/src/util/schemas/VoiceStateUpdateSchema.ts
@@ -0,0 +1,18 @@
+export const VoiceStateUpdateSchema = {
+	$guild_id: String,
+	$channel_id: String,
+	self_mute: Boolean,
+	self_deaf: Boolean,
+	self_video: Boolean
+};
+
+//TODO need more testing when community guild and voice stage channel are working
+export interface VoiceStateUpdateSchema {
+	channel_id: string;
+	guild_id?: string;
+	suppress?: boolean;
+	request_to_speak_timestamp?: Date;
+	self_mute?: boolean;
+	self_deaf?: boolean;
+	self_video?: boolean;
+}
diff --git a/src/util/schemas/WebhookCreateSchema.ts b/src/util/schemas/WebhookCreateSchema.ts
new file mode 100644
index 00000000..12ab1869
--- /dev/null
+++ b/src/util/schemas/WebhookCreateSchema.ts
@@ -0,0 +1,8 @@
+// TODO: webhooks
+export interface WebhookCreateSchema {
+	/**
+	 * @maxLength 80
+	 */
+	name: string;
+	avatar?: string;
+}
diff --git a/src/util/schemas/WidgetModifySchema.ts b/src/util/schemas/WidgetModifySchema.ts
new file mode 100644
index 00000000..26d4504f
--- /dev/null
+++ b/src/util/schemas/WidgetModifySchema.ts
@@ -0,0 +1,4 @@
+export interface WidgetModifySchema {
+	enabled: boolean; // whether the widget is enabled
+	channel_id: string; // the widget channel id
+}
diff --git a/src/util/schemas/index.ts b/src/util/schemas/index.ts
new file mode 100644
index 00000000..a15ab4b0
--- /dev/null
+++ b/src/util/schemas/index.ts
@@ -0,0 +1,43 @@
+export * from "./ActivitySchema";
+export * from "./BanCreateSchema";
+export * from "./BanModeratorSchema";
+export * from "./BanRegistrySchema";
+export * from "./BulkDeleteSchema";
+export * from "./ChannelModifySchema";
+export * from "./ChannelPermissionOverwriteSchema";
+export * from "./ChannelReorderSchema";
+export * from "./DmChannelCreateSchema";
+export * from "./EmojiCreateSchema";
+export * from "./EmojiModifySchema";
+export * from "./GuildCreateSchema";
+export * from "./GuildTemplateCreateSchema";
+export * from "./GuildUpdateSchema";
+export * from "./GuildUpdateWelcomeScreenSchema";
+export * from "./IdentifySchema";
+export * from "./InviteCreateSchema";
+export * from "./LazyRequestSchema";
+export * from "./LoginSchema";
+export * from "./MemberChangeSchema";
+export * from "./MemberNickChangeSchema";
+export * from "./MessageAcknowledgeSchema";
+export * from "./MessageCreateSchema";
+export * from "./MfaCodesSchema";
+export * from "./ModifyGuildStickerSchema";
+export * from "./PruneSchema";
+export * from "./PurgeSchema";
+export * from "./RegisterSchema";
+export * from "./RelationshipPostSchema";
+export * from "./RelationshipPutSchema";
+export * from "./RoleModifySchema";
+export * from "./RolePositionUpdateSchema";
+export * from "./TemplateCreateSchema";
+export * from "./TemplateModifySchema";
+export * from "./TotpDisableSchema";
+export * from "./TotpEnableSchema";
+export * from "./TotpSchema";
+export * from "./UserModifySchema";
+export * from "./UserSettingsSchema";
+export * from "./VanityUrlSchema";
+export * from "./VoiceStateUpdateSchema";
+export * from "./WebhookCreateSchema";
+export * from "./WidgetModifySchema";
diff --git a/src/util/util/ApiError.ts b/src/util/util/ApiError.ts
new file mode 100644
index 00000000..c133e6e7
--- /dev/null
+++ b/src/util/util/ApiError.ts
@@ -0,0 +1,27 @@
+export class ApiError extends Error {
+	constructor(
+		readonly message: string,
+		public readonly code: number,
+		public readonly httpStatus: number = 400,
+		public readonly defaultParams?: string[]
+	) {
+		super(message);
+	}
+
+	withDefaultParams(): ApiError {
+		if (this.defaultParams) 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);
+	}
+}
+
+export function applyParamsToString(s: string, params: (string | number)[]): string {
+	let newString = s;
+	params.forEach((a) => {
+		newString = newString.replace("{}", "" + a);
+	});
+	return newString;
+}
diff --git a/src/util/util/Array.ts b/src/util/util/Array.ts
new file mode 100644
index 00000000..5a45d1b5
--- /dev/null
+++ b/src/util/util/Array.ts
@@ -0,0 +1,3 @@
+export function containsAll(arr: any[], target: any[]) {
+	return target.every((v) => arr.includes(v));
+}
diff --git a/src/util/util/AutoUpdate.ts b/src/util/util/AutoUpdate.ts
new file mode 100644
index 00000000..08418040
--- /dev/null
+++ b/src/util/util/AutoUpdate.ts
@@ -0,0 +1,83 @@
+import fs from "fs/promises";
+import fetch from "node-fetch";
+import path from "path";
+import ProxyAgent from "proxy-agent";
+import readline from "readline";
+
+const rl = readline.createInterface({
+	input: process.stdin,
+	output: process.stdout
+});
+
+export function enableAutoUpdate(opts: {
+	checkInterval: number | boolean;
+	packageJsonLink: string;
+	path: string;
+	downloadUrl: string;
+	downloadType?: "zip";
+}) {
+	if (!opts.checkInterval) return;
+	let interval = 1000 * 60 * 60 * 24;
+	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 ...`);
+			await download(opts.downloadUrl, opts.path);
+		}
+	}, interval);
+	setImmediate(async () => {
+		const currentVersion = await getCurrentVersion(opts.path);
+		const latestVersion = await getLatestVersion(opts.packageJsonLink);
+		if (currentVersion !== latestVersion) {
+			rl.question(
+				`[Auto Update] Current version (${currentVersion}) is out of date, would you like to update? (yes/no)`,
+				(answer) => {
+					if (answer.toBoolean()) {
+						console.log(`[Auto update] updating ...`);
+						download(opts.downloadUrl, opts.path);
+					} else {
+						console.log(`[Auto update] aborted`);
+					}
+				}
+			);
+		}
+	});
+}
+
+async function download(url: string, dir: string) {
+	try {
+		// TODO: use file stream instead of buffer (to prevent crash because of high memory usage for big files)
+		// TODO check file hash
+		const agent = new ProxyAgent();
+		const response = await fetch(url, { agent });
+		const buffer = await response.buffer();
+		const tempDir = await fs.mkdtemp("fosscord");
+		fs.writeFile(path.join(tempDir, "Fosscord.zip"), buffer);
+	} catch (error) {
+		console.error(`[Auto Update] download failed`, error);
+	}
+}
+
+async function getCurrentVersion(dir: string) {
+	try {
+		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);
+	}
+}
+
+async function getLatestVersion(url: string) {
+	try {
+		const agent = new ProxyAgent();
+		const response = await fetch(url, { agent });
+		const content: any = await response.json();
+		return content.version;
+	} catch (error) {
+		throw new Error("[Auto update] check failed for " + url);
+	}
+}
diff --git a/src/util/util/BitField.ts b/src/util/util/BitField.ts
new file mode 100644
index 00000000..306bfb32
--- /dev/null
+++ b/src/util/util/BitField.ts
@@ -0,0 +1,150 @@
+"use strict";
+
+// 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[];
+
+/**
+ * Data structure that makes it easy to interact with a bitfield.
+ */
+export class BitField {
+	public bitfield: bigint = BigInt(0);
+
+	public static FLAGS: Record<string, bigint> = {};
+
+	constructor(bits: BitFieldResolvable = 0) {
+		this.bitfield = BitField.resolve.call(this, bits);
+	}
+
+	/**
+	 * Checks whether the bitfield has a bit, or any of multiple bits.
+	 */
+	any(bit: BitFieldResolvable): boolean {
+		return (this.bitfield & BitField.resolve.call(this, bit)) !== BigInt(0);
+	}
+
+	/**
+	 * Checks if this bitfield equals another
+	 */
+	equals(bit: BitFieldResolvable): boolean {
+		return this.bitfield === BitField.resolve.call(this, bit);
+	}
+
+	/**
+	 * Checks whether the bitfield has a bit, or multiple bits.
+	 */
+	has(bit: BitFieldResolvable): boolean {
+		if (Array.isArray(bit)) return bit.every((p) => this.has(p));
+		const BIT = BitField.resolve.call(this, bit);
+		return (this.bitfield & BIT) === BIT;
+	}
+
+	/**
+	 * Gets all given bits that are missing from the bitfield.
+	 */
+	missing(bits: BitFieldResolvable) {
+		if (!Array.isArray(bits)) bits = new BitField(bits).toArray();
+		return bits.filter((p) => !this.has(p));
+	}
+
+	/**
+	 * Freezes these bits, making them immutable.
+	 */
+	freeze(): Readonly<BitField> {
+		return Object.freeze(this);
+	}
+
+	/**
+	 * Adds bits to these ones.
+	 * @param {...BitFieldResolvable} [bits] Bits to add
+	 * @returns {BitField} These bits or new BitField if the instance is frozen.
+	 */
+	add(...bits: BitFieldResolvable[]): BitField {
+		let total = BigInt(0);
+		for (const bit of bits) {
+			total |= BitField.resolve.call(this, bit);
+		}
+		if (Object.isFrozen(this)) return new BitField(this.bitfield | total);
+		this.bitfield |= total;
+		return this;
+	}
+
+	/**
+	 * Removes bits from these.
+	 * @param {...BitFieldResolvable} [bits] Bits to remove
+	 */
+	remove(...bits: BitFieldResolvable[]) {
+		let total = BigInt(0);
+		for (const bit of bits) {
+			total |= BitField.resolve.call(this, bit);
+		}
+		if (Object.isFrozen(this)) return new BitField(this.bitfield & ~total);
+		this.bitfield &= ~total;
+		return this;
+	}
+
+	/**
+	 * Gets an object mapping field names to a {@link boolean} indicating whether the
+	 * bit is available.
+	 * @param {...*} hasParams Additional parameters for the has method, if any
+	 */
+	serialize() {
+		const serialized: Record<string, boolean> = {};
+		for (const [flag, bit] of Object.entries(BitField.FLAGS)) serialized[flag] = this.has(bit);
+		return serialized;
+	}
+
+	/**
+	 * Gets an {@link Array} of bitfield names based on the bits available.
+	 */
+	toArray(): string[] {
+		return Object.keys(BitField.FLAGS).filter((bit) => this.has(bit));
+	}
+
+	toJSON() {
+		return this.bitfield;
+	}
+
+	valueOf() {
+		return this.bitfield;
+	}
+
+	*[Symbol.iterator]() {
+		yield* this.toArray();
+	}
+
+	/**
+	 * Data that can be resolved to give a bitfield. This can be:
+	 * * A bit number (this can be a number literal or a value taken from {@link BitField.FLAGS})
+	 * * An instance of BitField
+	 * * An Array of BitFieldResolvable
+	 * @typedef {number|BitField|BitFieldResolvable[]} BitFieldResolvable
+	 */
+
+	/**
+	 * Resolves bitfields to their numeric form.
+	 * @param {BitFieldResolvable} [bit=0] - bit(s) to resolve
+	 * @returns {number}
+	 */
+	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 (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));
+		}
+		if (typeof bit === "string" && typeof FLAGS[bit] !== "undefined") return FLAGS[bit];
+		if (bit === "0") return BigInt(0); //special case: 0
+		if (typeof bit === "string") return BigInt(bit); //last ditch effort...
+		if (/--debug|--inspect/.test(process.execArgv.join(" "))) debugger; //if you're here, we have an invalid bitfield... if bit is 0, thats fine, I guess...
+		throw new RangeError("BITFIELD_INVALID: " + bit);
+	}
+}
+
+export function BitFlag(x: bigint | number) {
+	return BigInt(1) << BigInt(x);
+}
diff --git a/src/util/util/Categories.ts b/src/util/util/Categories.ts
new file mode 100644
index 00000000..cd706a8a
--- /dev/null
+++ b/src/util/util/Categories.ts
@@ -0,0 +1 @@
+//TODO: populate default discord categories + init, get and set methods
diff --git a/src/util/util/Config.ts b/src/util/util/Config.ts
new file mode 100644
index 00000000..cc7090a6
--- /dev/null
+++ b/src/util/util/Config.ts
@@ -0,0 +1,105 @@
+import fs from "fs";
+import path from "path";
+import { OrmUtils } from ".";
+import { ConfigValue } from "../config";
+import { ConfigEntity } from "../entities/Config";
+
+// TODO: yaml instead of json
+const overridePath = process.env.CONFIG_PATH ?? "";
+
+let config: ConfigValue;
+let pairs: ConfigEntity[];
+
+// TODO: use events to inform about config updates
+// Config keys are separated with _
+
+export const Config = {
+	init: async function init() {
+		if (config) return config;
+		console.log("[Config] Loading configuration...");
+		pairs = await ConfigEntity.find();
+		config = pairsToConfig(pairs);
+		//config = (config || {}).merge(new ConfigValue());
+		config = OrmUtils.mergeDeep(new ConfigValue(), config);
+
+		if (process.env.CONFIG_PATH)
+			try {
+				const overrideConfig = JSON.parse(fs.readFileSync(overridePath, { encoding: "utf8" }));
+				config = OrmUtils.mergeDeep(config, overrideConfig);
+			} catch (error) {
+				fs.writeFileSync(overridePath, JSON.stringify(config, null, 4));
+			}
+
+		if (fs.existsSync(path.join(process.cwd(), "initial.json")))
+			try {
+				console.log("[Config] Found initial configuration, merging...");
+				const overrideConfig = JSON.parse(fs.readFileSync(path.join(process.cwd(), "initial.json"), { encoding: "utf8" }));
+				config = OrmUtils.mergeDeep(config, overrideConfig);
+				fs.rmSync(path.join(process.cwd(), "initial.json"));
+			} catch (error) {
+				fs.writeFileSync(path.join(process.cwd(), "failed.conf"), JSON.stringify(config, null, 4));
+			}
+
+		return this.set(config);
+	},
+	get: function get() {
+		if (!config) {
+			if (/--debug|--inspect/.test(process.execArgv.join(" ")))
+				console.log(
+					"Oops.. trying to get config without config existing... Returning defaults... (Is the database still initialising?)"
+				);
+			return new ConfigValue();
+		}
+		return config;
+	},
+	set: function set(val: Partial<ConfigValue>) {
+		if (!config || !val) return;
+		config = val.merge(config);
+
+		return applyConfig(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)));
+
+		let pair = pairs.find((x) => x.key === key);
+		if (!pair) pair = new ConfigEntity();
+
+		pair.key = key;
+		pair.value = obj;
+		return pair.save();
+	}
+	if (process.env.CONFIG_PATH) {
+		if (/--debug|--inspect/.test(process.execArgv.join(" "))) console.log(`Writing config: ${process.env.CONFIG_PATH}`);
+		fs.writeFileSync(overridePath, JSON.stringify(val, null, 4));
+	}
+
+	return apply(val);
+}
+
+function pairsToConfig(pairs: ConfigEntity[]) {
+	let value: any = {};
+
+	pairs.forEach((p) => {
+		const keys = p.key.split("_");
+		let obj = value;
+		let prev = "";
+		let prevObj = obj;
+		let i = 0;
+
+		for (const key of keys) {
+			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] = {};
+
+			prev = key;
+			prevObj = obj;
+			obj = obj[key];
+		}
+	});
+
+	return value as ConfigValue;
+}
diff --git a/src/util/util/Constants.ts b/src/util/util/Constants.ts
new file mode 100644
index 00000000..f7aff26a
--- /dev/null
+++ b/src/util/util/Constants.ts
@@ -0,0 +1,726 @@
+import { ApiError } from "./ApiError";
+
+export const WSCodes = {
+	1000: "WS_CLOSE_REQUESTED",
+	4004: "TOKEN_INVALID",
+	4010: "SHARDING_INVALID",
+	4011: "SHARDING_REQUIRED",
+	4013: "INVALID_INTENTS",
+	4014: "DISALLOWED_INTENTS"
+};
+
+/**
+ * The current status of the client. Here are the available statuses:
+ * * READY: 0
+ * * CONNECTING: 1
+ * * RECONNECTING: 2
+ * * IDLE: 3
+ * * NEARLY: 4
+ * * DISCONNECTED: 5
+ * * WAITING_FOR_GUILDS: 6
+ * * IDENTIFYING: 7
+ * * RESUMING: 8
+ * @typedef {number} Status
+ */
+export const WsStatus = {
+	READY: 0,
+	CONNECTING: 1,
+	RECONNECTING: 2,
+	IDLE: 3,
+	NEARLY: 4,
+	DISCONNECTED: 5,
+	WAITING_FOR_GUILDS: 6,
+	IDENTIFYING: 7,
+	RESUMING: 8
+};
+
+/**
+ * The current status of a voice connection. Here are the available statuses:
+ * * CONNECTED: 0
+ * * CONNECTING: 1
+ * * AUTHENTICATING: 2
+ * * RECONNECTING: 3
+ * * DISCONNECTED: 4
+ * @typedef {number} VoiceStatus
+ */
+export const VoiceStatus = {
+	CONNECTED: 0,
+	CONNECTING: 1,
+	AUTHENTICATING: 2,
+	RECONNECTING: 3,
+	DISCONNECTED: 4
+};
+
+export const OPCodes = {
+	DISPATCH: 0,
+	HEARTBEAT: 1,
+	IDENTIFY: 2,
+	STATUS_UPDATE: 3,
+	VOICE_STATE_UPDATE: 4,
+	VOICE_GUILD_PING: 5,
+	RESUME: 6,
+	RECONNECT: 7,
+	REQUEST_GUILD_MEMBERS: 8,
+	INVALID_SESSION: 9,
+	HELLO: 10,
+	HEARTBEAT_ACK: 11
+};
+
+export const VoiceOPCodes = {
+	IDENTIFY: 0,
+	SELECT_PROTOCOL: 1,
+	READY: 2,
+	HEARTBEAT: 3,
+	SESSION_DESCRIPTION: 4,
+	SPEAKING: 5,
+	HELLO: 8,
+	CLIENT_CONNECT: 12,
+	CLIENT_DISCONNECT: 13
+};
+
+export const Events = {
+	RATE_LIMIT: "rateLimit",
+	CLIENT_READY: "ready",
+	GUILD_CREATE: "guildCreate",
+	GUILD_DELETE: "guildDelete",
+	GUILD_UPDATE: "guildUpdate",
+	GUILD_UNAVAILABLE: "guildUnavailable",
+	GUILD_AVAILABLE: "guildAvailable",
+	GUILD_MEMBER_ADD: "guildMemberAdd",
+	GUILD_MEMBER_REMOVE: "guildMemberRemove",
+	GUILD_MEMBER_UPDATE: "guildMemberUpdate",
+	GUILD_MEMBER_AVAILABLE: "guildMemberAvailable",
+	GUILD_MEMBER_SPEAKING: "guildMemberSpeaking",
+	GUILD_MEMBERS_CHUNK: "guildMembersChunk",
+	GUILD_INTEGRATIONS_UPDATE: "guildIntegrationsUpdate",
+	GUILD_ROLE_CREATE: "roleCreate",
+	GUILD_ROLE_DELETE: "roleDelete",
+	INVITE_CREATE: "inviteCreate",
+	INVITE_DELETE: "inviteDelete",
+	GUILD_ROLE_UPDATE: "roleUpdate",
+	GUILD_EMOJI_CREATE: "emojiCreate",
+	GUILD_EMOJI_DELETE: "emojiDelete",
+	GUILD_EMOJI_UPDATE: "emojiUpdate",
+	GUILD_BAN_ADD: "guildBanAdd",
+	GUILD_BAN_REMOVE: "guildBanRemove",
+	CHANNEL_CREATE: "channelCreate",
+	CHANNEL_DELETE: "channelDelete",
+	CHANNEL_UPDATE: "channelUpdate",
+	CHANNEL_PINS_UPDATE: "channelPinsUpdate",
+	MESSAGE_CREATE: "message",
+	MESSAGE_DELETE: "messageDelete",
+	MESSAGE_UPDATE: "messageUpdate",
+	MESSAGE_BULK_DELETE: "messageDeleteBulk",
+	MESSAGE_REACTION_ADD: "messageReactionAdd",
+	MESSAGE_REACTION_REMOVE: "messageReactionRemove",
+	MESSAGE_REACTION_REMOVE_ALL: "messageReactionRemoveAll",
+	MESSAGE_REACTION_REMOVE_EMOJI: "messageReactionRemoveEmoji",
+	USER_UPDATE: "userUpdate",
+	PRESENCE_UPDATE: "presenceUpdate",
+	VOICE_SERVER_UPDATE: "voiceServerUpdate",
+	VOICE_STATE_UPDATE: "voiceStateUpdate",
+	VOICE_BROADCAST_SUBSCRIBE: "subscribe",
+	VOICE_BROADCAST_UNSUBSCRIBE: "unsubscribe",
+	TYPING_START: "typingStart",
+	TYPING_STOP: "typingStop",
+	WEBHOOKS_UPDATE: "webhookUpdate",
+	ERROR: "error",
+	WARN: "warn",
+	DEBUG: "debug",
+	SHARD_DISCONNECT: "shardDisconnect",
+	SHARD_ERROR: "shardError",
+	SHARD_RECONNECTING: "shardReconnecting",
+	SHARD_READY: "shardReady",
+	SHARD_RESUME: "shardResume",
+	INVALIDATED: "invalidated",
+	RAW: "raw"
+};
+
+export const ShardEvents = {
+	CLOSE: "close",
+	DESTROYED: "destroyed",
+	INVALID_SESSION: "invalidSession",
+	READY: "ready",
+	RESUMED: "resumed",
+	ALL_READY: "allReady"
+};
+
+/**
+ * The type of Structure allowed to be a partial:
+ * * USER
+ * * CHANNEL (only affects DMChannels)
+ * * GUILD_MEMBER
+ * * MESSAGE
+ * * REACTION
+ * <warn>Partials require you to put checks in place when handling data, read the Partials topic listed in the
+ * sidebar for more information.</warn>
+ * @typedef {string} PartialType
+ */
+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:
+ * * READY
+ * * RESUMED
+ * * GUILD_CREATE
+ * * GUILD_DELETE
+ * * GUILD_UPDATE
+ * * INVITE_CREATE
+ * * INVITE_DELETE
+ * * GUILD_MEMBER_ADD
+ * * GUILD_MEMBER_REMOVE
+ * * GUILD_MEMBER_UPDATE
+ * * GUILD_MEMBERS_CHUNK
+ * * GUILD_INTEGRATIONS_UPDATE
+ * * GUILD_ROLE_CREATE
+ * * GUILD_ROLE_DELETE
+ * * GUILD_ROLE_UPDATE
+ * * GUILD_BAN_ADD
+ * * GUILD_BAN_REMOVE
+ * * GUILD_EMOJIS_UPDATE
+ * * CHANNEL_CREATE
+ * * CHANNEL_DELETE
+ * * CHANNEL_UPDATE
+ * * CHANNEL_PINS_UPDATE
+ * * MESSAGE_CREATE
+ * * MESSAGE_DELETE
+ * * MESSAGE_UPDATE
+ * * MESSAGE_DELETE_BULK
+ * * MESSAGE_REACTION_ADD
+ * * MESSAGE_REACTION_REMOVE
+ * * MESSAGE_REACTION_REMOVE_ALL
+ * * MESSAGE_REACTION_REMOVE_EMOJI
+ * * USER_UPDATE
+ * * PRESENCE_UPDATE
+ * * TYPING_START
+ * * VOICE_STATE_UPDATE
+ * * VOICE_SERVER_UPDATE
+ * * WEBHOOKS_UPDATE
+ * @typedef {string} WSEventType
+ */
+export const WSEvents = keyMirror([
+	"READY",
+	"RESUMED",
+	"GUILD_CREATE",
+	"GUILD_DELETE",
+	"GUILD_UPDATE",
+	"INVITE_CREATE",
+	"INVITE_DELETE",
+	"GUILD_MEMBER_ADD",
+	"GUILD_MEMBER_REMOVE",
+	"GUILD_MEMBER_UPDATE",
+	"GUILD_MEMBERS_CHUNK",
+	"GUILD_INTEGRATIONS_UPDATE",
+	"GUILD_ROLE_CREATE",
+	"GUILD_ROLE_DELETE",
+	"GUILD_ROLE_UPDATE",
+	"GUILD_BAN_ADD",
+	"GUILD_BAN_REMOVE",
+	"GUILD_EMOJIS_UPDATE",
+	"CHANNEL_CREATE",
+	"CHANNEL_DELETE",
+	"CHANNEL_UPDATE",
+	"CHANNEL_PINS_UPDATE",
+	"MESSAGE_CREATE",
+	"MESSAGE_DELETE",
+	"MESSAGE_UPDATE",
+	"MESSAGE_DELETE_BULK",
+	"MESSAGE_REACTION_ADD",
+	"MESSAGE_REACTION_REMOVE",
+	"MESSAGE_REACTION_REMOVE_ALL",
+	"MESSAGE_REACTION_REMOVE_EMOJI",
+	"USER_UPDATE",
+	"PRESENCE_UPDATE",
+	"TYPING_START",
+	"VOICE_STATE_UPDATE",
+	"VOICE_SERVER_UPDATE",
+	"WEBHOOKS_UPDATE"
+]);
+
+/**
+ * The type of a message, e.g. `DEFAULT`. Here are the available types:
+ * * DEFAULT
+ * * RECIPIENT_ADD
+ * * RECIPIENT_REMOVE
+ * * CALL
+ * * CHANNEL_NAME_CHANGE
+ * * CHANNEL_ICON_CHANGE
+ * * PINS_ADD
+ * * GUILD_MEMBER_JOIN
+ * * USER_PREMIUM_GUILD_SUBSCRIPTION
+ * * USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_1
+ * * USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_2
+ * * USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_3
+ * * CHANNEL_FOLLOW_ADD
+ * * GUILD_DISCOVERY_DISQUALIFIED
+ * * GUILD_DISCOVERY_REQUALIFIED
+ * * REPLY
+ * @typedef {string} MessageType
+ */
+export const MessageTypes = [
+	"DEFAULT",
+	"RECIPIENT_ADD",
+	"RECIPIENT_REMOVE",
+	"CALL",
+	"CHANNEL_NAME_CHANGE",
+	"CHANNEL_ICON_CHANGE",
+	"PINS_ADD",
+	"GUILD_MEMBER_JOIN",
+	"USER_PREMIUM_GUILD_SUBSCRIPTION",
+	"USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_1",
+	"USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_2",
+	"USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_3",
+	"CHANNEL_FOLLOW_ADD",
+	null,
+	"GUILD_DISCOVERY_DISQUALIFIED",
+	"GUILD_DISCOVERY_REQUALIFIED",
+	null,
+	null,
+	null,
+	"REPLY"
+];
+
+/**
+ * The types of messages that are `System`. The available types are `MessageTypes` excluding:
+ * * DEFAULT
+ * * REPLY
+ * @typedef {string} SystemMessageType
+ */
+export const SystemMessageTypes = MessageTypes.filter((type: string | null) => type && type !== "DEFAULT" && type !== "REPLY");
+
+/**
+ * <info>Bots cannot set a `CUSTOM_STATUS`, it is only for custom statuses received from users</info>
+ * The type of an activity of a users presence, e.g. `PLAYING`. Here are the available types:
+ * * PLAYING
+ * * STREAMING
+ * * LISTENING
+ * * WATCHING
+ * * CUSTOM_STATUS
+ * * COMPETING
+ * @typedef {string} ActivityType
+ */
+export const ActivityTypes = ["PLAYING", "STREAMING", "LISTENING", "WATCHING", "CUSTOM_STATUS", "COMPETING"];
+
+export const ChannelTypes = {
+	TEXT: 0,
+	DM: 1,
+	VOICE: 2,
+	GROUP: 3,
+	CATEGORY: 4,
+	NEWS: 5,
+	STORE: 6
+};
+
+export const ClientApplicationAssetTypes = {
+	SMALL: 1,
+	BIG: 2
+};
+
+export const Colors = {
+	DEFAULT: 0x000000,
+	WHITE: 0xffffff,
+	AQUA: 0x1abc9c,
+	GREEN: 0x2ecc71,
+	BLUE: 0x3498db,
+	YELLOW: 0xffff00,
+	PURPLE: 0x9b59b6,
+	LUMINOUS_VIVID_PINK: 0xe91e63,
+	GOLD: 0xf1c40f,
+	ORANGE: 0xe67e22,
+	RED: 0xe74c3c,
+	GREY: 0x95a5a6,
+	NAVY: 0x34495e,
+	DARK_AQUA: 0x11806a,
+	DARK_GREEN: 0x1f8b4c,
+	DARK_BLUE: 0x206694,
+	DARK_PURPLE: 0x71368a,
+	DARK_VIVID_PINK: 0xad1457,
+	DARK_GOLD: 0xc27c0e,
+	DARK_ORANGE: 0xa84300,
+	DARK_RED: 0x992d22,
+	DARK_GREY: 0x979c9f,
+	DARKER_GREY: 0x7f8c8d,
+	LIGHT_GREY: 0xbcc0c0,
+	DARK_NAVY: 0x2c3e50,
+	BLURPLE: 0x7289da,
+	GREYPLE: 0x99aab5,
+	DARK_BUT_NOT_BLACK: 0x2c2f33,
+	NOT_QUITE_BLACK: 0x23272a
+};
+
+/**
+ * The value set for the explicit content filter levels for a guild:
+ * * DISABLED
+ * * MEMBERS_WITHOUT_ROLES
+ * * ALL_MEMBERS
+ * @typedef {string} ExplicitContentFilterLevel
+ */
+export const ExplicitContentFilterLevels = ["DISABLED", "MEMBERS_WITHOUT_ROLES", "ALL_MEMBERS"];
+
+/**
+ * The value set for the verification levels for a guild:
+ * * NONE
+ * * LOW
+ * * MEDIUM
+ * * HIGH
+ * * VERY_HIGH
+ * @typedef {string} VerificationLevel
+ */
+export const VerificationLevels = ["NONE", "LOW", "MEDIUM", "HIGH", "VERY_HIGH"];
+
+/**
+ * An error encountered while performing an API request. Here are the potential errors:
+ * * GENERAL_ERROR
+ * * UNKNOWN_ACCOUNT
+ * * UNKNOWN_APPLICATION
+ * * UNKNOWN_CHANNEL
+ * * UNKNOWN_GUILD
+ * * UNKNOWN_INTEGRATION
+ * * UNKNOWN_INVITE
+ * * UNKNOWN_MEMBER
+ * * UNKNOWN_MESSAGE
+ * * UNKNOWN_OVERWRITE
+ * * UNKNOWN_PROVIDER
+ * * UNKNOWN_ROLE
+ * * UNKNOWN_TOKEN
+ * * UNKNOWN_USER
+ * * UNKNOWN_EMOJI
+ * * UNKNOWN_WEBHOOK
+ * * UNKNOWN_WEBHOOK_SERVICE
+ * * UNKNOWN_SESSION
+ * * UNKNOWN_BAN
+ * * UNKNOWN_SKU
+ * * UNKNOWN_STORE_LISTING
+ * * UNKNOWN_ENTITLEMENT
+ * * UNKNOWN_BUILD
+ * * UNKNOWN_LOBBY
+ * * UNKNOWN_BRANCH
+ * * UNKNOWN_STORE_DIRECTORY_LAYOUT
+ * * UNKNOWN_REDISTRIBUTABLE
+ * * UNKNOWN_GIFT_CODE
+ * * UNKNOWN_STREAM
+ * * UNKNOWN_PREMIUM_SERVER_SUBSCRIBE_COOLDOWN
+ * * UNKNOWN_GUILD_TEMPLATE
+ * * UNKNOWN_DISCOVERABLE_SERVER_CATEGORY
+ * * UNKNOWN_STICKER
+ * * UNKNOWN_INTERACTION
+ * * UNKNOWN_APPLICATION_COMMAND
+ * * UNKNOWN_APPLICATION_COMMAND_PERMISSIONS
+ * * UNKNOWN_STAGE_INSTANCE
+ * * UNKNOWN_GUILD_MEMBER_VERIFICATION_FORM
+ * * UNKNOWN_GUILD_WELCOME_SCREEN
+ * * UNKNOWN_GUILD_SCHEDULED_EVENT
+ * * UNKNOWN_GUILD_SCHEDULED_EVENT_USER
+ * * BOT_PROHIBITED_ENDPOINT
+ * * BOT_ONLY_ENDPOINT
+ * * EXPLICIT_CONTENT_CANNOT_BE_SENT_TO_RECIPIENT
+ * * ACTION_NOT_AUTHORIZED_ON_APPLICATION
+ * * SLOWMODE_RATE_LIMIT
+ * * ONLY_OWNER
+ * * ANNOUNCEMENT_RATE_LIMITS
+ * * CHANNEL_WRITE_RATELIMIT
+ * * WORDS_NOT_ALLOWED
+ * * GUILD_PREMIUM_LEVEL_TOO_LOW
+ * * MAXIMUM_GUILDS
+ * * MAXIMUM_FRIENDS
+ * * MAXIMUM_PINS
+ * * MAXIMUM_NUMBER_OF_RECIPIENTS_REACHED
+ * * MAXIMUM_ROLES
+ * * MAXIMUM_WEBHOOKS
+ * * MAXIMUM_NUMBER_OF_EMOJIS_REACHED
+ * * MAXIMUM_REACTIONS
+ * * MAXIMUM_CHANNELS
+ * * MAXIMUM_ATTACHMENTS
+ * * MAXIMUM_INVITES
+ * * MAXIMUM_ANIMATED_EMOJIS
+ * * MAXIMUM_SERVER_MEMBERS
+ * * MAXIMUM_SERVER_CATEGORIES
+ * * GUILD_ALREADY_HAS_TEMPLATE
+ * * MAXIMUM_THREAD_PARTICIPANTS
+ * * MAXIMUM_BANS_FOR_NON_GUILD_MEMBERS
+ * * MAXIMUM_BANS_FETCHES
+ * * MAXIMUM_STICKERS
+ * * MAXIMUM_PRUNE_REQUESTS
+ * * UNAUTHORIZED
+ * * ACCOUNT_VERIFICATION_REQUIRED
+ * * OPENING_DIRECT_MESSAGES_TOO_FAST
+ * * REQUEST_ENTITY_TOO_LARGE
+ * * FEATURE_TEMPORARILY_DISABLED
+ * * USER_BANNED
+ * * TARGET_USER_IS_NOT_CONNECTED_TO_VOICE
+ * * ALREADY_CROSSPOSTED
+ * * APPLICATION_COMMAND_ALREADY_EXISTS
+ * * MISSING_ACCESS
+ * * INVALID_ACCOUNT_TYPE
+ * * CANNOT_EXECUTE_ON_DM
+ * * EMBED_DISABLED
+ * * CANNOT_EDIT_MESSAGE_BY_OTHER
+ * * CANNOT_SEND_EMPTY_MESSAGE
+ * * CANNOT_MESSAGE_USER
+ * * CANNOT_SEND_MESSAGES_IN_VOICE_CHANNEL
+ * * CHANNEL_VERIFICATION_LEVEL_TOO_HIGH
+ * * OAUTH2_APPLICATION_BOT_ABSENT
+ * * MAXIMUM_OAUTH2_APPLICATIONS
+ * * INVALID_OAUTH_STATE
+ * * MISSING_PERMISSIONS
+ * * INVALID_AUTHENTICATION_TOKEN
+ * * NOTE_TOO_LONG
+ * * INVALID_BULK_DELETE_QUANTITY
+ * * CANNOT_PIN_MESSAGE_IN_OTHER_CHANNEL
+ * * INVALID_OR_TAKEN_INVITE_CODE
+ * * CANNOT_EXECUTE_ON_SYSTEM_MESSAGE
+ * * CANNOT_EXECUTE_ON_THIS_CHANNEL_TYPE
+ * * INVALID_OAUTH_TOKEN
+ * * MISSING_REQUIRED_OAUTH2_SCOPE
+ * * INVALID_WEBHOOK_TOKEN_PROVIDED
+ * * INVALID_ROLE
+ * * INVALID_RECIPIENT
+ * * BULK_DELETE_MESSAGE_TOO_OLD
+ * * INVALID_FORM_BODY
+ * * INVITE_ACCEPTED_TO_GUILD_NOT_CONTAINING_BOT
+ * * INVALID_API_VERSION
+ * * FILE_EXCEEDS_MAXIMUM_SIZE
+ * * INVALID_FILE_UPLOADED
+ * * CANNOT_SELF_REDEEM_GIFT
+ * * PAYMENT_SOURCE_REQUIRED
+ * * CANNOT_DELETE_COMMUNITY_REQUIRED_CHANNEL
+ * * INVALID_STICKER_SENT
+ * * CANNOT_EDIT_ARCHIVED_THREAD
+ * * INVALID_THREAD_NOTIFICATION_SETTINGS
+ * * BEFORE_EARLIER_THAN_THREAD_CREATION_DATE
+ * * SERVER_NOT_AVAILABLE_IN_YOUR_LOCATION
+ * * SERVER_NEEDS_MONETIZATION_ENABLED
+ * * TWO_FACTOR_REQUIRED
+ * * NO_USERS_WITH_DISCORDTAG_EXIST
+ * * REACTION_BLOCKED
+ * * RESOURCE_OVERLOADED
+ * * STAGE_ALREADY_OPEN
+ * * THREAD_ALREADY_CREATED_FOR_THIS_MESSAGE
+ * * THREAD_IS_LOCKED
+ * * MAXIMUM_NUMBER_OF_ACTIVE_THREADS
+ * * MAXIMUM_NUMBER_OF_ACTIVE_ANNOUNCEMENT_THREADS
+ * * INVALID_JSON_FOR_UPLOADED_LOTTIE_FILE
+ * * LOTTIES_CANNOT_CONTAIN_RASTERIZED_IMAGES
+ * * STICKER_MAXIMUM_FRAMERATE
+ * * STICKER_MAXIMUM_FRAME_COUNT
+ * * LOTTIE_ANIMATION_MAXIMUM_DIMENSIONS
+ * * STICKER_FRAME_RATE_TOO_SMALL_OR_TOO_LARGE
+ * * STICKER_ANIMATION_DURATION_MAXIMUM
+ * * UNKNOWN_VOICE_STATE
+ * @typedef {string} APIError
+ */
+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),
+	UNKNOWN_ACCOUNT: new ApiError("Unknown account", 10001),
+	UNKNOWN_APPLICATION: new ApiError("Unknown application", 10002),
+	UNKNOWN_CHANNEL: new ApiError("Unknown channel", 10003),
+	UNKNOWN_GUILD: new ApiError("Unknown guild", 10004),
+	UNKNOWN_INTEGRATION: new ApiError("Unknown integration", 10005),
+	UNKNOWN_INVITE: new ApiError("Unknown invite", 10006),
+	UNKNOWN_MEMBER: new ApiError("Unknown member", 10007),
+	UNKNOWN_MESSAGE: new ApiError("Unknown message", 10008),
+	UNKNOWN_OVERWRITE: new ApiError("Unknown permission overwrite", 10009),
+	UNKNOWN_PROVIDER: new ApiError("Unknown provider", 10010),
+	UNKNOWN_ROLE: new ApiError("Unknown role", 10011),
+	UNKNOWN_TOKEN: new ApiError("Unknown token", 10012),
+	UNKNOWN_USER: new ApiError("Unknown user", 10013),
+	UNKNOWN_EMOJI: new ApiError("Unknown emoji", 10014),
+	UNKNOWN_WEBHOOK: new ApiError("Unknown webhook", 10015),
+	UNKNOWN_WEBHOOK_SERVICE: new ApiError("Unknown webhook service", 10016),
+	UNKNOWN_SESSION: new ApiError("Unknown session", 10020),
+	UNKNOWN_BAN: new ApiError("Unknown ban", 10026),
+	UNKNOWN_SKU: new ApiError("Unknown SKU", 10027),
+	UNKNOWN_STORE_LISTING: new ApiError("Unknown Store Listing", 10028),
+	UNKNOWN_ENTITLEMENT: new ApiError("Unknown entitlement", 10029),
+	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_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_GUILD_TEMPLATE: new ApiError("Unknown guild template", 10057),
+	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_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),
+	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),
+	ACTION_NOT_AUTHORIZED_ON_APPLICATION: new ApiError("You are not authorized to perform this action on this application", 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),
+	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),
+	MAXIMUM_SERVER_CATEGORIES: new ApiError("Maximum number of server categories has been reached ({})", 30030, undefined, ["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),
+	MAXIMUM_BANS_FOR_NON_GUILD_MEMBERS: new ApiError("Maximum number of bans for non-guild members have been exceeded", 30035),
+	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),
+	ACCOUNT_VERIFICATION_REQUIRED: new ApiError("You need to verify your account in order to perform this action", 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),
+	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),
+	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),
+	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),
+	CHANNEL_VERIFICATION_LEVEL_TOO_HIGH: new ApiError("Channel verification level is too high for you to gain access", 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),
+	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),
+	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"]
+	),
+	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),
+	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),
+	INVALID_FORM_BODY: new ApiError(
+		"Invalid form body (returned for both application/json and multipart/form-data bodies), or invalid Content-Type provided",
+		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),
+	INVALID_API_VERSION: new ApiError("Invalid API version provided", 50041),
+	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_DELETE_COMMUNITY_REQUIRED_CHANNEL: new ApiError("Cannot delete a channel required for Community guilds", 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
+	),
+	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),
+	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),
+	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),
+	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_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_ANNOUNCEMENT_THREADS: new ApiError("Maximum number of active announcement threads reached", 160007),
+	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),
+	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),
+	STICKER_ANIMATION_DURATION_MAXIMUM: new ApiError("Sticker animation duration exceeds maximum of {} seconds", 170007, undefined, ["5"]),
+
+	//Other errors
+	UNKNOWN_VOICE_STATE: new ApiError("Unknown Voice State", 10065, 404)
+};
+
+/**
+ * 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),
+	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_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)
+};
+
+/**
+ * The value set for a guild's default message notifications, e.g. `ALL`. Here are the available types:
+ * * ALL
+ * * MENTIONS
+ * * MUTED (Fosscord extension)
+ * @typedef {string} DefaultMessageNotifications
+ */
+export const DefaultMessageNotifications = ["ALL", "MENTIONS", "MUTED"];
+
+/**
+ * The value set for a team members's membership state:
+ * * INVITED
+ * * ACCEPTED
+ * * INSERTED (Fosscord extension)
+ * @typedef {string} MembershipStates
+ */
+export const MembershipStates = ["INSERTED", "INVITED", "ACCEPTED"];
+
+/**
+ * The value set for a webhook's type:
+ * * Incoming
+ * * Channel Follower
+ * * Custom (Fosscord extension)
+ * @typedef {string} WebhookTypes
+ */
+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
new file mode 100644
index 00000000..b9f8365e
--- /dev/null
+++ b/src/util/util/Database.ts
@@ -0,0 +1,107 @@
+import { config } from "dotenv";
+import fs from "fs";
+import path from "path";
+import { green, red, yellow } from "picocolors";
+import { exit } from "process";
+import "reflect-metadata";
+import { DataSource, DataSourceOptions, PrimaryColumn, PrimaryGeneratedColumn } from "typeorm";
+import * as Models from "../entities";
+import { BaseClass, BaseClassWithoutId } from "../entities";
+
+// UUID extension option is only supported with postgres
+// We want to generate all id's with Snowflakes that's why we have our own BaseEntity class
+
+let promise: Promise<any>;
+let dataSource: DataSource;
+
+export async function getOrInitialiseDatabase(): Promise<DataSource> {
+	//if (dataSource) return dataSource; // prevent initalizing multiple times
+
+	if (dataSource.isInitialized) return dataSource;
+
+	await dataSource.initialize();
+	console.log(`[Database] ${green("Connected!")}`);
+	await dataSource.runMigrations();
+	console.log(`[Database] ${green("Up to date!")}`);
+
+	if ("DB_MIGRATE" in process.env) {
+		console.log("DB_MIGRATE specified, exiting!");
+		exit(0);
+	}
+	return dataSource;
+}
+
+export function closeDatabase() {
+	dataSource?.destroy();
+}
+
+function getDataSourceOptions(): DataSourceOptions {
+	config();
+	//get connection string and check for migrations
+	const dbConnectionString = process.env.DATABASE || path.join(process.cwd(), "database.db");
+	const type = dbConnectionString.includes("://") ? dbConnectionString.split(":")[0]?.replace("+srv", "") : ("sqlite" as any);
+	const isSqlite = type.includes("sqlite");
+	const migrationsExist = fs.existsSync(path.join(__dirname, "..", "migrations", type));
+	//read env vars
+	const synchronizeInsteadOfMigrations = "DB_UNSAFE" in process.env;
+	const verboseDb = "DB_VERBOSE" in process.env;
+
+	if (isSqlite)
+		console.log(`[Database] ${red(`You are running sqlite! Please keep in mind that we recommend setting up a dedicated database!`)}`);
+	if (verboseDb)
+		console.log(
+			`[Database] ${red(`Verbose database logging is enabled, this might impact performance! Unset DB_VERBOSE to disable.`)}`
+		);
+
+	if (synchronizeInsteadOfMigrations) {
+		console.log(
+			`[Database] ${red(
+				`Unsafe database upgrades are enabled! We are not responsible for broken databases! Unset DB_UNSAFE to disable.`
+			)}`
+		);
+	} else if (!migrationsExist) {
+		console.log(`[Database] ${red(`Database engine not supported! Set UNSAFE_DB to bypass.`)}`);
+		console.log(`[Database] ${red(`Please mention this to Fosscord developers, and provide this info:`)}`);
+		console.log(
+			`[Database]\n${red(
+				JSON.stringify(
+					{
+						db_type: type,
+						migrations_exist: migrationsExist
+					},
+					null,
+					4
+				)
+			)}`
+		);
+
+		if (!("DB_MIGRATE" in process.env)) exit(1);
+	}
+	console.log(`[Database] ${yellow(`Configuring data source to use ${type} database...`)}`);
+	return {
+		type,
+		charset: "utf8mb4",
+		url: isSqlite ? undefined : dbConnectionString,
+		database: isSqlite ? dbConnectionString : undefined,
+		// @ts-ignore
+		//entities: Object.values(Models).filter((x) => x.constructor.name !== "Object" && x.constructor.name !== "Array" && x.constructor.name !== "BigInt" && x).map(x=>x.name),
+		entities: Object.values(Models).filter((x) => x.constructor.name == "Function" && shouldIncludeEntity(x.name)),
+		synchronize: synchronizeInsteadOfMigrations,
+		logging: verboseDb ? "all" : false,
+		cache: {
+			duration: 1000 * 3 // cache all find queries for 3 seconds
+		},
+		bigNumberStrings: false,
+		supportBigNumbers: true,
+		name: "default",
+		migrations: synchronizeInsteadOfMigrations ? [] : [path.join(__dirname, "..", "migrations", type, "*.js")],
+		migrationsRun: !synchronizeInsteadOfMigrations,
+		applicationName: `Fosscord Server`,
+	} as DataSourceOptions;
+}
+
+function shouldIncludeEntity(name: string): boolean {
+	return ![BaseClassWithoutId, PrimaryColumn, BaseClass, PrimaryGeneratedColumn].map((x) => x.name).includes(name);
+}
+
+export default dataSource = new DataSource(getDataSourceOptions());
diff --git a/src/util/util/Email.ts b/src/util/util/Email.ts
new file mode 100644
index 00000000..c98ccff0
--- /dev/null
+++ b/src/util/util/Email.ts
@@ -0,0 +1,25 @@
+export const EMAIL_REGEX =
+	/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
+
+export function adjustEmail(email?: string): string | undefined {
+	if (!email) return email;
+	// body parser already checked if it is a valid email
+	const parts = <RegExpMatchArray>email.match(EMAIL_REGEX);
+	// @ts-ignore
+	if (!parts || parts.length < 5) return undefined;
+	const domain = parts[5];
+	const user = parts[1];
+
+	// TODO: check accounts with uncommon email domains
+	if (domain === "gmail.com" || domain === "googlemail.com") {
+		// replace .dots and +alternatives -> Gmail Dot Trick https://support.google.com/mail/answer/7436150 and https://generator.email/blog/gmail-generator
+		let v = user.replace(/[.]|(\+.*)/g, "") + "@gmail.com";
+	}
+
+	if (domain === "google.com") {
+		// replace .dots and +alternatives -> Google Staff GMail Dot Trick
+		let v = user.replace(/[.]|(\+.*)/g, "") + "@google.com";
+	}
+
+	return email;
+}
diff --git a/src/util/util/Event.ts b/src/util/util/Event.ts
new file mode 100644
index 00000000..383e4e50
--- /dev/null
+++ b/src/util/util/Event.ts
@@ -0,0 +1,117 @@
+import { Channel } from "amqplib";
+import EventEmitter from "events";
+import { EVENT, Event } from "../interfaces";
+import { RabbitMQ } from "./RabbitMQ";
+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;
+	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 });
+
+		// 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 });
+		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);
+	} else {
+		events.emit(id, payload);
+	}
+}
+
+export async function initEvent() {
+	await RabbitMQ.init(); // does nothing if rabbitmq is not setup
+	if (RabbitMQ.connection) {
+	} else {
+		// use event emitter
+		// use process messages
+	}
+}
+
+export interface EventOpts extends Event {
+	acknowledge?: Function;
+	channel?: Channel;
+	cancel: Function;
+}
+
+export interface ListenEventOpts {
+	channel?: Channel;
+	acknowledge?: boolean;
+}
+
+export interface ProcessEvent {
+	type: "event";
+	event: Event;
+	id: string;
+}
+
+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 });
+	} else if (process.env.EVENT_TRANSMISSION === "process") {
+		const cancel = () => {
+			process.removeListener("message", listener);
+			process.setMaxListeners(process.getMaxListeners() - 1);
+		};
+
+		const listener = (message: any) => {
+			message.type === "event" && message.id === event && callback({ ...message.event, cancel });
+		};
+
+		process.addListener("message", listener);
+		process.setMaxListeners(process.getMaxListeners() + 1);
+
+		return cancel;
+	} else {
+		const listener = (opts: any) => callback({ ...opts, cancel });
+		const cancel = () => {
+			events.removeListener(event, listener);
+			events.setMaxListeners(events.getMaxListeners() - 1);
+		};
+		events.setMaxListeners(events.getMaxListeners() + 1);
+		events.addListener(event, listener);
+
+		return cancel;
+	}
+}
+
+async function rabbitListen(channel: Channel, id: string, callback: (event: EventOpts) => any, opts?: { acknowledge?: boolean }) {
+	await channel.assertExchange(id, "fanout", { durable: false });
+	const q = await channel.assertQueue("", { exclusive: true, autoDelete: true });
+
+	const cancel = () => {
+		channel.cancel(q.queue);
+		channel.unbindQueue(q.queue, id, "");
+	};
+
+	channel.bindQueue(q.queue, id, "");
+	channel.consume(
+		q.queue,
+		(opts) => {
+			if (!opts) return;
+
+			const data = JSON.parse(opts.content.toString());
+			const event = opts.properties.type as EVENT;
+
+			callback({
+				event,
+				data,
+				acknowledge() {
+					channel.ack(opts);
+				},
+				channel,
+				cancel
+			});
+			// rabbitCh.ack(opts);
+		},
+		{
+			noAck: !opts?.acknowledge
+		}
+	);
+
+	return cancel;
+}
diff --git a/src/util/util/FieldError.ts b/src/util/util/FieldError.ts
new file mode 100644
index 00000000..bdffd618
--- /dev/null
+++ b/src/util/util/FieldError.ts
@@ -0,0 +1,23 @@
+export function FieldErrors(fields: Record<string, { code?: string; message: string }>) {
+	return new FieldError(
+		50035,
+		"Invalid Form Body",
+		fields.map(({ message, code }) => ({
+			_errors: [
+				{
+					message,
+					code: code || "BASE_TYPE_INVALID"
+				}
+			]
+		}))
+	);
+}
+
+// TODO: implement Image data type: Data URI scheme that supports JPG, GIF, and PNG formats. An example Data URI format is: data:image/jpeg;base64,BASE64_ENCODED_JPEG_IMAGE_DATA
+// 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) {
+		super(message);
+	}
+}
diff --git a/src/util/util/Intents.ts b/src/util/util/Intents.ts
new file mode 100644
index 00000000..db4c9e28
--- /dev/null
+++ b/src/util/util/Intents.ts
@@ -0,0 +1,33 @@
+import { BitField } from "./BitField";
+
+export class Intents extends BitField {
+	static FLAGS = {
+		GUILDS: BigInt(1) << BigInt(0), // guilds and guild merge-split events affecting the user
+		GUILD_MEMBERS: BigInt(1) << BigInt(1), // memberships
+		GUILD_BANS: BigInt(1) << BigInt(2), // bans and ban lists
+		GUILD_EMOJIS: BigInt(1) << BigInt(3), // custom emojis
+		GUILD_INTEGRATIONS: BigInt(1) << BigInt(4), // applications
+		GUILD_WEBHOOKS: BigInt(1) << BigInt(5), // webhooks
+		GUILD_INVITES: BigInt(1) << BigInt(6), // mass invites (no user can receive user specific invites of another user)
+		GUILD_VOICE_STATES: BigInt(1) << BigInt(7), // voice updates
+		GUILD_PRESENCES: BigInt(1) << BigInt(8), // presence updates
+		GUILD_MESSAGES_METADATA: BigInt(1) << BigInt(9), // guild message metadata
+		GUILD_MESSAGE_REACTIONS: BigInt(1) << BigInt(10), // guild message reactions
+		GUILD_MESSAGE_TYPING: BigInt(1) << BigInt(11), // guild channel typing notifications
+		DIRECT_MESSAGES: BigInt(1) << BigInt(12), // DM or orphan channels
+		DIRECT_MESSAGE_REACTIONS: BigInt(1) << BigInt(13), // DM or orphan channel message reactions
+		DIRECT_MESSAGE_TYPING: BigInt(1) << BigInt(14), // DM typing notifications
+		GUILD_MESSAGES_CONTENT: BigInt(1) << BigInt(15), // guild message content
+		GUILD_POLICIES: BigInt(1) << BigInt(20), // guild policies
+		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
+		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_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
+	};
+}
diff --git a/src/util/util/InvisibleCharacters.ts b/src/util/util/InvisibleCharacters.ts
new file mode 100644
index 00000000..9bffec58
--- /dev/null
+++ b/src/util/util/InvisibleCharacters.ts
@@ -0,0 +1,57 @@
+// List from https://invisible-characters.com/
+export const InvisibleCharacters = [
+	"\u{9}", //Tab
+	"\u{c}", //Form feed
+	//'\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 -- WJ is required in some languages that don't use spaces to split words
+	"\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/MFA.ts b/src/util/util/MFA.ts
new file mode 100644
index 00000000..b9af6d23
--- /dev/null
+++ b/src/util/util/MFA.ts
@@ -0,0 +1,18 @@
+import crypto from "crypto";
+import { Config } from ".";
+import { BackupCode } from "../entities/BackupCodes";
+
+export function generateMfaBackupCodes(user_id: string) {
+	let backup_codes: BackupCode[] = [];
+	for (let i = 0; i < Config.get().security.mfaBackupCodeCount; i++) {
+		const code = BackupCode.create({
+			user: { id: user_id },
+			code: crypto.randomBytes(Config.get().security.mfaBackupCodeBytes).toString("hex"), // 8 characters
+			consumed: false,
+			expired: false
+		});
+		backup_codes.push(code);
+	}
+
+	return backup_codes;
+}
diff --git a/src/util/util/MessageFlags.ts b/src/util/util/MessageFlags.ts
new file mode 100644
index 00000000..c5d5d02a
--- /dev/null
+++ b/src/util/util/MessageFlags.ts
@@ -0,0 +1,20 @@
+// based on https://github.com/discordjs/discord.js/blob/master/src/util/MessageFlags.js
+// Apache License Version 2.0 Copyright 2015 - 2021 Amish Shah, 2022 Erkin Alp Güney
+
+import { BitField } from "./BitField";
+
+export class MessageFlags extends BitField {
+	static FLAGS = {
+		CROSSPOSTED: BigInt(1) << BigInt(0),
+		IS_CROSSPOST: BigInt(1) << BigInt(1),
+		SUPPRESS_EMBEDS: BigInt(1) << BigInt(2),
+		// SOURCE_MESSAGE_DELETED: BigInt(1) << BigInt(3), // fosscord will delete them from destination too, making this redundant
+		URGENT: BigInt(1) << BigInt(4),
+		// HAS_THREAD: BigInt(1) << BigInt(5) // does not apply to fosscord due to infrastructural differences
+		PRIVATE_ROUTE: BigInt(1) << BigInt(6), // it that has been routed to only some of the users that can see the channel
+		INTERACTION_WAIT: BigInt(1) << BigInt(7), // discord.com calls this LOADING
+		// FAILED_TO_MENTION_SOME_ROLES_IN_THREAD: BigInt(1) << BigInt(8)
+		SCRIPT_WAIT: BigInt(1) << BigInt(24), // waiting for the self command to complete
+		IMPORT_WAIT: BigInt(1) << BigInt(25) // latest message of a bulk import, waiting for the rest of the channel to be backfilled
+	};
+}
diff --git a/src/util/util/Permissions.ts b/src/util/util/Permissions.ts
new file mode 100644
index 00000000..b8d0d8ae
--- /dev/null
+++ b/src/util/util/Permissions.ts
@@ -0,0 +1,273 @@
+// https://github.com/discordjs/discord.js/blob/master/src/util/Permissions.js
+// Apache License Version 2.0 Copyright 2015 - 2021 Amish Shah
+import { HTTPError } from "..";
+import { Channel, ChannelPermissionOverwrite, Guild, Member, Role } from "../entities";
+import { BitField, BitFieldResolvable, BitFlag } from "./BitField";
+
+export type PermissionResolvable = bigint | number | Permissions | PermissionResolvable[] | PermissionString;
+
+type PermissionString = keyof typeof Permissions.FLAGS;
+
+// BigInt doesn't have a bit limit (https://stackoverflow.com/questions/53335545/whats-the-biggest-bigint-value-in-js-as-per-spec)
+const CUSTOM_PERMISSION_OFFSET = BigInt(1) << BigInt(64); // 27 permission bits left for discord to add new ones
+
+export class Permissions extends BitField {
+	cache: PermissionCache = {};
+
+	constructor(bits: BitFieldResolvable = 0) {
+		super(bits);
+		if (this.bitfield & Permissions.FLAGS.ADMINISTRATOR) {
+			this.bitfield = ALL_PERMISSIONS;
+		}
+	}
+
+	static FLAGS = {
+		CREATE_INSTANT_INVITE: BitFlag(0),
+		KICK_MEMBERS: BitFlag(1),
+		BAN_MEMBERS: BitFlag(2),
+		ADMINISTRATOR: BitFlag(3),
+		MANAGE_CHANNELS: BitFlag(4),
+		MANAGE_GUILD: BitFlag(5),
+		ADD_REACTIONS: BitFlag(6),
+		VIEW_AUDIT_LOG: BitFlag(7),
+		PRIORITY_SPEAKER: BitFlag(8),
+		STREAM: BitFlag(9),
+		VIEW_CHANNEL: BitFlag(10),
+		SEND_MESSAGES: BitFlag(11),
+		SEND_TTS_MESSAGES: BitFlag(12),
+		MANAGE_MESSAGES: BitFlag(13),
+		EMBED_LINKS: BitFlag(14),
+		ATTACH_FILES: BitFlag(15),
+		READ_MESSAGE_HISTORY: BitFlag(16),
+		MENTION_EVERYONE: BitFlag(17),
+		USE_EXTERNAL_EMOJIS: BitFlag(18),
+		VIEW_GUILD_INSIGHTS: BitFlag(19),
+		CONNECT: BitFlag(20),
+		SPEAK: BitFlag(21),
+		MUTE_MEMBERS: BitFlag(22),
+		DEAFEN_MEMBERS: BitFlag(23),
+		MOVE_MEMBERS: BitFlag(24),
+		USE_VAD: BitFlag(25),
+		CHANGE_NICKNAME: BitFlag(26),
+		MANAGE_NICKNAMES: BitFlag(27),
+		MANAGE_ROLES: BitFlag(28),
+		MANAGE_WEBHOOKS: BitFlag(29),
+		MANAGE_EMOJIS_AND_STICKERS: BitFlag(30),
+		USE_APPLICATION_COMMANDS: BitFlag(31),
+		REQUEST_TO_SPEAK: BitFlag(32),
+		// TODO: what is permission 33?
+		MANAGE_THREADS: BitFlag(34),
+		USE_PUBLIC_THREADS: BitFlag(35),
+		USE_PRIVATE_THREADS: BitFlag(36),
+		USE_EXTERNAL_STICKERS: BitFlag(37)
+
+		/**
+		 * CUSTOM PERMISSIONS ideas:
+		 * - allow user to dm members
+		 * - allow user to pin messages (without MANAGE_MESSAGES)
+		 * - allow user to publish messages (without MANAGE_MESSAGES)
+		 */
+		// CUSTOM_PERMISSION: BigInt(1) << BigInt(0) + CUSTOM_PERMISSION_OFFSET
+	};
+
+	any(permission: PermissionResolvable, checkAdmin = true) {
+		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);
+	}
+
+	/**
+	 * Checks whether the bitfield has a permission, or multiple permissions, but throws an Error if user fails to match auth criteria.
+	 */
+	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);
+	}
+
+	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 === 1 && x.id == this.cache.user_id) return true;
+			return false;
+		});
+		return new Permissions(Permissions.channelPermission(overwrites, this.bitfield));
+	}
+
+	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);
+			// ~ 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)
+		}, init || BigInt(0));
+	}
+
+	static rolePermission(roles: Role[]) {
+		// adds all permissions of all roles together (Bit OR)
+		return roles.reduce((permission, role) => permission | BigInt(role.permissions), BigInt(0));
+	}
+
+	static finalPermission({
+		user,
+		guild,
+		channel
+	}: {
+		user: { id: string; roles: string[] };
+		guild: { roles: Role[] };
+		channel?: {
+			overwrites?: ChannelPermissionOverwrite[];
+			recipient_ids?: string[] | null;
+			owner_id?: string;
+		};
+	}) {
+		if (user.id === "0") return new Permissions("ADMINISTRATOR"); // system user id
+
+		let roles = guild.roles.filter((x) => user.roles.includes(x.id));
+		let permission = Permissions.rolePermission(roles);
+
+		if (channel?.overwrites) {
+			let overwrites = channel.overwrites.filter((x) => {
+				if (x.type === 0 && user.roles.includes(x.id)) return true;
+				if (x.type === 1 && x.id == user.id) return true;
+				return false;
+			});
+			permission = Permissions.channelPermission(overwrites, permission);
+		}
+
+		if (channel?.recipient_ids) {
+			if (channel?.owner_id === user.id) return new Permissions("ADMINISTRATOR");
+			if (channel.recipient_ids.includes(user.id)) {
+				// Default dm permissions
+				return new Permissions([
+					"VIEW_CHANNEL",
+					"SEND_MESSAGES",
+					"STREAM",
+					"ADD_REACTIONS",
+					"EMBED_LINKS",
+					"ATTACH_FILES",
+					"READ_MESSAGE_HISTORY",
+					"MENTION_EVERYONE",
+					"USE_EXTERNAL_EMOJIS",
+					"CONNECT",
+					"SPEAK",
+					"MANAGE_CHANNELS"
+				]);
+			}
+
+			return new Permissions();
+		}
+
+		return new Permissions(permission);
+	}
+}
+
+const ALL_PERMISSIONS = Object.values(Permissions.FLAGS).reduce((total, val) => total | val, BigInt(0));
+
+export type PermissionCache = {
+	channel?: Channel | undefined;
+	member?: Member | undefined;
+	guild?: Guild | undefined;
+	roles?: Role[] | undefined;
+	user_id?: string;
+};
+
+export async function getPermission(
+	user_id?: string,
+	guild_id?: string,
+	channel_id?: string,
+	opts: {
+		guild_select?: (keyof Guild)[];
+		guild_relations?: string[];
+		channel_select?: (keyof Channel)[];
+		channel_relations?: string[];
+		member_select?: (keyof Member)[];
+		member_relations?: string[];
+	} = {}
+) {
+	if (!user_id) throw new HTTPError("User not found");
+	let channel: Channel | undefined;
+	let member: Member | undefined;
+	let guild: Guild | undefined;
+
+	if (channel_id) {
+		channel = await Channel.findOneOrFail({
+			where: { id: channel_id },
+			relations: ["recipients", ...(opts.channel_relations || [])],
+			select: [
+				"id",
+				"recipients",
+				"permission_overwrites",
+				"owner_id",
+				"guild_id",
+				// @ts-ignore
+				...(opts.channel_select || [])
+			]
+		});
+		if (channel.guild_id) guild_id = channel.guild_id; // derive guild_id from the channel
+	}
+
+	if (guild_id) {
+		guild = await Guild.findOneOrFail({
+			where: { id: guild_id },
+			select: [
+				"id",
+				"owner_id",
+				// @ts-ignore
+				...(opts.guild_select || [])
+			],
+			relations: opts.guild_relations
+		});
+		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",
+				"roles",
+				"index",
+				// @ts-ignore
+				...(opts.member_select || [])
+			]
+		});
+	}
+
+	let recipient_ids: any = channel?.recipients?.map((x) => x.user_id);
+	if (!recipient_ids?.length) recipient_ids = null;
+
+	// TODO: remove guild.roles and convert recipient_ids to recipients
+	let permission = Permissions.finalPermission({
+		user: {
+			id: user_id,
+			roles: member?.roles.map((x) => x.id) || []
+		},
+		guild: {
+			roles: member?.roles || []
+		},
+		channel: {
+			overwrites: channel?.permission_overwrites,
+			owner_id: channel?.owner_id,
+			recipient_ids
+		}
+	});
+
+	const obj = new Permissions(permission);
+
+	// pass cache to permission for possible future getPermission calls
+	obj.cache = { guild, member, channel, roles: member?.roles, user_id };
+
+	return obj;
+}
diff --git a/src/util/util/RabbitMQ.ts b/src/util/util/RabbitMQ.ts
new file mode 100644
index 00000000..638b805b
--- /dev/null
+++ b/src/util/util/RabbitMQ.ts
@@ -0,0 +1,19 @@
+import { Channel, Connection } from "amqplib";
+// import Config from "./Config";
+
+export const RabbitMQ: { connection: Connection | null; channel: Channel | null; init: () => Promise<void> } = {
+	connection: null,
+	channel: null,
+	init: async function () {
+		return;
+		// const host = Config.get().rabbitmq.host;
+		// if (!host) return;
+		// console.log(`[RabbitMQ] connect: ${host}`);
+		// this.connection = await amqp.connect(host, {
+		// 	timeout: 1000 * 60,
+		// });
+		// console.log(`[RabbitMQ] connected`);
+		// this.channel = await this.connection.createChannel();
+		// console.log(`[RabbitMQ] channel created`);
+	}
+};
diff --git a/src/util/util/Regex.ts b/src/util/util/Regex.ts
new file mode 100644
index 00000000..83fc9fe8
--- /dev/null
+++ b/src/util/util/Regex.ts
@@ -0,0 +1,7 @@
+export const DOUBLE_WHITE_SPACE = /\s\s+/g;
+export const SPECIAL_CHAR = /[@#`:\r\n\t\f\v\p{C}]/gu;
+export const CHANNEL_MENTION = /<#(\d+)>/g;
+export const USER_MENTION = /<@!?(\d+)>/g;
+export const ROLE_MENTION = /<@&(\d+)>/g;
+export const EVERYONE_MENTION = /@everyone/g;
+export const HERE_MENTION = /@here/g;
diff --git a/src/util/util/Rights.ts b/src/util/util/Rights.ts
new file mode 100644
index 00000000..51bb098c
--- /dev/null
+++ b/src/util/util/Rights.ts
@@ -0,0 +1,94 @@
+import { HTTPError } from "..";
+import { User } from "../entities";
+import { BitField, BitFieldResolvable, BitFlag } from "./BitField";
+
+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
+
+export class Rights extends BitField {
+	constructor(bits: BitFieldResolvable = 0) {
+		super(bits);
+		if (this.bitfield & Rights.FLAGS.OPERATOR) {
+			this.bitfield = ALL_RIGHTS;
+		}
+	}
+
+	static FLAGS = {
+		OPERATOR: BitFlag(0), // has all rights
+		MANAGE_APPLICATIONS: BitFlag(1),
+		MANAGE_GUILDS: BitFlag(2),
+		MANAGE_MESSAGES: BitFlag(3), // Can't see other messages but delete/edit them in channels that they can see
+		MANAGE_RATE_LIMITS: BitFlag(4),
+		MANAGE_ROUTING: BitFlag(5), // can create custom message routes to any channel/guild
+		MANAGE_TICKETS: BitFlag(6), // can respond to and resolve support tickets
+		MANAGE_USERS: BitFlag(7),
+		ADD_MEMBERS: BitFlag(8), // can manually add any members in their guilds
+		BYPASS_RATE_LIMITS: BitFlag(9),
+		CREATE_APPLICATIONS: BitFlag(10),
+		CREATE_CHANNELS: BitFlag(11), // can create guild channels or threads in the guilds that they have permission
+		CREATE_DMS: BitFlag(12),
+		CREATE_DM_GROUPS: BitFlag(13), // can create group DMs or custom orphan channels
+		CREATE_GUILDS: BitFlag(14),
+		CREATE_INVITES: BitFlag(15), // can create mass invites in the guilds that they have CREATE_INSTANT_INVITE
+		CREATE_ROLES: BitFlag(16),
+		CREATE_TEMPLATES: BitFlag(17),
+		CREATE_WEBHOOKS: BitFlag(18),
+		JOIN_GUILDS: BitFlag(19),
+		PIN_MESSAGES: BitFlag(20),
+		SELF_ADD_REACTIONS: BitFlag(21),
+		SELF_DELETE_MESSAGES: BitFlag(22),
+		SELF_EDIT_MESSAGES: BitFlag(23),
+		SELF_EDIT_NAME: BitFlag(24),
+		SEND_MESSAGES: BitFlag(25),
+		USE_ACTIVITIES: BitFlag(26), // use (game) activities in voice channels (e.g. Watch together)
+		USE_VIDEO: BitFlag(27),
+		USE_VOICE: BitFlag(28),
+		INVITE_USERS: BitFlag(29), // can create user-specific invites in the guilds that they have INVITE_USERS
+		SELF_DELETE_DISABLE: BitFlag(30), // can disable/delete own account
+		DEBTABLE: BitFlag(31), // can use pay-to-use features
+		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),
+		// 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
+		SELF_ADD_DISCOVERABLE: BitFlag(36), // can mark discoverable guilds that they have permissions to mark as discoverable
+		MANAGE_GUILD_DIRECTORY: BitFlag(37), // can change anything in the primary guild directory
+		POGGERS: BitFlag(38), // can send confetti, screenshake, random user mention (@someone)
+		USE_ACHIEVEMENTS: BitFlag(39), // can use achievements and cheers
+		INITIATE_INTERACTIONS: BitFlag(40), // can initiate interactions
+		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
+	};
+
+	any(permission: RightResolvable, checkOperator = true) {
+		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);
+	}
+
+	hasThrow(permission: RightResolvable) {
+		if (this.has(permission)) return true;
+		// @ts-ignore
+		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));
+
+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
new file mode 100644
index 00000000..89f4f0c3
--- /dev/null
+++ b/src/util/util/Snowflake.ts
@@ -0,0 +1,131 @@
+// @ts-nocheck
+import * as cluster from "cluster";
+
+// https://github.com/discordjs/discord.js/blob/master/src/util/Snowflake.js
+// Apache License Version 2.0 Copyright 2015 - 2021 Amish Shah
+("use strict");
+
+// Discord epoch (2015-01-01T00:00:00.000Z)
+
+/**
+ * A container for useful snowflake-related methods.
+ */
+export class Snowflake {
+	static readonly EPOCH = 1420070400000;
+	static INCREMENT = 0n; // max 4095
+	static processId = BigInt(process.pid % 31); // max 31
+	static workerId = BigInt((cluster.worker?.id || 0) % 31); // max 31
+
+	constructor() {
+		throw new Error(`The ${this.constructor.name} class may not be instantiated.`);
+	}
+
+	/**
+	 * A Twitter-like snowflake, except the epoch is 2015-01-01T00:00:00.000Z
+	 * ```
+	 * If we have a snowflake '266241948824764416' we can represent it as binary:
+	 *
+	 * 64                                          22     17     12          0
+	 *  000000111011000111100001101001000101000000  00001  00000  000000000000
+	 *       number of ms since Discord epoch       worker  pid    increment
+	 * ```
+	 * @typedef {string} Snowflake
+	 */
+
+	/**
+	 * Transforms a snowflake from a decimal string to a bit string.
+	 * @param  {Snowflake} num Snowflake to be transformed
+	 * @returns {string}
+	 * @private
+	 */
+	static idToBinary(num) {
+		let bin = "";
+		let high = parseInt(num.slice(0, -10)) || 0;
+		let low = parseInt(num.slice(-10));
+		while (low > 0 || high > 0) {
+			bin = String(low & 1) + bin;
+			low = Math.floor(low / 2);
+			if (high > 0) {
+				low += 5000000000 * (high % 2);
+				high = Math.floor(high / 2);
+			}
+		}
+		return bin;
+	}
+
+	/**
+	 * Transforms a snowflake from a bit string to a decimal string.
+	 * @param  {string} num Bit string to be transformed
+	 * @returns {Snowflake}
+	 * @private
+	 */
+	static binaryToID(num) {
+		let dec = "";
+
+		while (num.length > 50) {
+			const high = parseInt(num.slice(0, -32), 2);
+			const low = parseInt((high % 10).toString(2) + num.slice(-32), 2);
+
+			dec = (low % 10).toString() + dec;
+			num =
+				Math.floor(high / 10).toString(2) +
+				Math.floor(low / 10)
+					.toString(2)
+					.padStart(32, "0");
+		}
+
+		num = parseInt(num, 2);
+		while (num > 0) {
+			dec = (num % 10).toString() + dec;
+			num = Math.floor(num / 10);
+		}
+
+		return dec;
+	}
+
+	static generateWorkerProcess() {
+		// worker process - returns a number
+		let time = BigInt(Date.now() - Snowflake.EPOCH) << BigInt(22);
+		let worker = Snowflake.workerId << 17n;
+		let process = Snowflake.processId << 12n;
+		let increment = Snowflake.INCREMENT++;
+		return BigInt(time | worker | process | increment);
+	}
+
+	static generate() {
+		return Snowflake.generateWorkerProcess().toString();
+	}
+	/**
+	 * A deconstructed snowflake.
+	 * @typedef {Object} DeconstructedSnowflake
+	 * @property {number} timestamp Timestamp the snowflake was created
+	 * @property {Date} date Date the snowflake was created
+	 * @property {number} workerID Worker ID in the snowflake
+	 * @property {number} processID Process ID in the snowflake
+	 * @property {number} increment Increment in the snowflake
+	 * @property {string} binary Binary representation of the snowflake
+	 */
+
+	/**
+	 * Deconstructs a Discord snowflake.
+	 * @param {Snowflake} snowflake Snowflake to deconstruct
+	 * @returns {DeconstructedSnowflake} Deconstructed snowflake
+	 */
+	static deconstruct(snowflake) {
+		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),
+			processID: parseInt(BINARY.substring(47, 52), 2),
+			increment: parseInt(BINARY.substring(52, 64), 2),
+			binary: BINARY
+		};
+		Object.defineProperty(res, "date", {
+			get: function get() {
+				return new Date(this.timestamp);
+			},
+			enumerable: true
+		});
+		return res;
+	}
+}
diff --git a/src/util/util/String.ts b/src/util/util/String.ts
new file mode 100644
index 00000000..55f11e8d
--- /dev/null
+++ b/src/util/util/String.ts
@@ -0,0 +1,7 @@
+import { SPECIAL_CHAR } from "./Regex";
+
+export function trimSpecial(str?: string): string {
+	// @ts-ignore
+	if (!str) return;
+	return str.replace(SPECIAL_CHAR, "").trim();
+}
diff --git a/src/util/util/Token.ts b/src/util/util/Token.ts
new file mode 100644
index 00000000..d192a13a
--- /dev/null
+++ b/src/util/util/Token.ts
@@ -0,0 +1,50 @@
+import jwt, { VerifyOptions } from "jsonwebtoken";
+import { User } from "../entities";
+import { Config } from "./Config";
+
+export const JWTOptions: VerifyOptions = { algorithms: ["HS256"] };
+
+export function checkToken(token: string, jwtSecret: string): Promise<any> {
+	return new Promise((res, rej) => {
+		token = token.replace("Bot ", "");
+		/**
+		in fosscord, even with instances that have bot distinction; we won't enforce "Bot" prefix,
+		as we don't really have separate pathways for bots 
+		**/
+
+		jwt.verify(token, jwtSecret, JWTOptions, async (err, decoded: any) => {
+			if (err || !decoded) return rej("Invalid Token");
+
+			const user = await User.findOne({
+				where: { id: decoded.id },
+				select: ["data", "bot", "disabled", "deleted", "rights"]
+			});
+			if (!user) return rej("Invalid Token");
+			// we need to round it to seconds as it saved as seconds in jwt iat and valid_tokens_since is stored in milliseconds
+			if (decoded.iat * 1000 < new Date(user.data.valid_tokens_since).setSeconds(0, 0)) return rej("Invalid Token");
+			if (user.disabled) return rej("User disabled");
+			if (user.deleted) return rej("User not found");
+
+			return res({ decoded, user });
+		});
+	});
+}
+
+export async function generateToken(id: string) {
+	const iat = Math.floor(Date.now() / 1000);
+	const algorithm = "HS256";
+
+	return new Promise((res, rej) => {
+		jwt.sign(
+			{ id: id, iat },
+			Config.get().security.jwtSecret,
+			{
+				algorithm
+			},
+			(err, token) => {
+				if (err) return rej(err);
+				return res(token);
+			}
+		);
+	});
+}
diff --git a/src/util/util/TraverseDirectory.ts b/src/util/util/TraverseDirectory.ts
new file mode 100644
index 00000000..6f60e73b
--- /dev/null
+++ b/src/util/util/TraverseDirectory.ts
@@ -0,0 +1,10 @@
+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 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));
+}
diff --git a/src/util/util/cdn.ts b/src/util/util/cdn.ts
new file mode 100644
index 00000000..5573b848
--- /dev/null
+++ b/src/util/util/cdn.ts
@@ -0,0 +1,55 @@
+import FormData from "form-data";
+import fetch from "node-fetch";
+import { HTTPError } from "..";
+import { Config } from "./Config";
+
+export async function uploadFile(path: string, file?: Express.Multer.File) {
+	if (!file?.buffer) throw new HTTPError("Missing file in body");
+
+	const form = new FormData();
+	form.append("file", file.buffer, {
+		contentType: file.mimetype,
+		filename: file.originalname
+	});
+
+	const response = await fetch(`${Config.get().cdn.endpointPrivate || "http://localhost:3003"}${path}`, {
+		headers: {
+			signature: Config.get().security.requestSignature,
+			...form.getHeaders()
+		},
+		method: "POST",
+		body: form
+	});
+	const result = await response.json();
+
+	if (response.status !== 200) throw result;
+	return result;
+}
+
+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" });
+		return id;
+	} catch (error) {
+		console.error(error);
+		throw new HTTPError("Invalid " + path);
+	}
+}
+
+export async function deleteFile(path: string) {
+	const response = await fetch(`${Config.get().cdn.endpointPrivate || "http://localhost:3003"}${path}`, {
+		headers: {
+			signature: Config.get().security.requestSignature
+		},
+		method: "DELETE"
+	});
+	const result = await response.json();
+
+	if (response.status !== 200) throw result;
+	return result;
+}
diff --git a/src/util/util/imports/Checks.ts b/src/util/util/imports/Checks.ts
new file mode 100644
index 00000000..bd3c6343
--- /dev/null
+++ b/src/util/util/imports/Checks.ts
@@ -0,0 +1,121 @@
+//source: https://github.com/Flam3rboy/-server/blob/master/src/check.ts
+import { NextFunction, Request, Response } from "express";
+import { HTTPError } from ".";
+
+const OPTIONAL_PREFIX = "$";
+const EMAIL_REGEX =
+	/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
+
+export function check(schema: any) {
+	return (req: Request, res: Response, next: NextFunction) => {
+		try {
+			const result = instanceOf(schema, req.body, { path: "body" });
+			if (result === true) return next();
+			throw result;
+		} catch (error) {
+			next(new HTTPError((error as any).toString(), 400));
+		}
+	};
+}
+export class Tuple {
+	public types: any[];
+	constructor(...types: any[]) {
+		this.types = types;
+	}
+}
+
+export class Email {
+	constructor(public email: string) {}
+	check() {
+		return !!this.email.match(EMAIL_REGEX);
+	}
+}
+export function instanceOf(type: any, value: any, { path = "", optional = false }: { path?: string; optional?: boolean } = {}): boolean {
+	if (!type) return true; // no type was specified
+
+	if (value == null) {
+		if (optional) return true;
+		throw `${path} is required`;
+	}
+
+	switch (type) {
+		case String:
+			if (typeof value === "string") return true;
+			throw `${path} must be a string`;
+		case Number:
+			value = Number(value);
+			if (typeof value === "number" && !isNaN(value)) return true;
+			throw `${path} must be a number`;
+		case BigInt:
+			try {
+				value = BigInt(value);
+				if (typeof value === "bigint") return true;
+			} catch (error) {}
+			throw `${path} must be a bigint`;
+		case Boolean:
+			if (value == "true") value = true;
+			if (value == "false") value = false;
+			if (typeof value === "boolean") return true;
+			throw `${path} must be a boolean`;
+		case Object:
+			if (typeof value === "object" && value !== null) return true;
+			throw `${path} must be a object`;
+	}
+
+	if (typeof type === "object") {
+		if (Array.isArray(type)) {
+			if (!Array.isArray(value)) throw `${path} must be an array`;
+			if (!type.length) return true; // type array didn't specify any type
+
+			return value.every((val, i) => instanceOf(type[0], val, { path: `${path}[${i}]`, optional }));
+		}
+		if (type?.constructor?.name != "Object") {
+			if (type instanceof Tuple) {
+				if (
+					(<Tuple>type).types.some((x) => {
+						try {
+							return instanceOf(x, value, { path, optional });
+						} catch (error) {
+							return false;
+						}
+					})
+				) {
+					return true;
+				}
+				throw `${path} must be one of ${type.types}`;
+			}
+			if (type instanceof Email) {
+				if ((<Email>type).check()) return true;
+				throw `${path} is not a valid E-Mail`;
+			}
+			if (value instanceof type) return true;
+			throw `${path} must be an instance of ${type}`;
+		}
+		if (typeof value !== "object") throw `${path} must be a object`;
+
+		const diff = Object.keys(value).missing(
+			Object.keys(type).map((x) => (x.startsWith(OPTIONAL_PREFIX) ? x.slice(OPTIONAL_PREFIX.length) : x))
+		);
+
+		if (diff.length) throw `Unkown key ${diff}`;
+
+		return Object.keys(type).every((key) => {
+			let newKey = key;
+			const OPTIONAL = key.startsWith(OPTIONAL_PREFIX);
+			if (OPTIONAL) newKey = newKey.slice(OPTIONAL_PREFIX.length);
+
+			return instanceOf(type[key], value[newKey], {
+				path: `${path}.${newKey}`,
+				optional: OPTIONAL
+			});
+		});
+	} else if (typeof type === "number" || typeof type === "string" || typeof type === "boolean") {
+		if (value === type) return true;
+		throw `${path} must be ${value}`;
+	} else if (typeof type === "bigint") {
+		if (BigInt(value) === type) return true;
+		throw `${path} must be ${value}`;
+	}
+
+	return type == value;
+}
diff --git a/src/util/util/imports/HTTPError.ts b/src/util/util/imports/HTTPError.ts
new file mode 100644
index 00000000..70ba92a8
--- /dev/null
+++ b/src/util/util/imports/HTTPError.ts
@@ -0,0 +1,5 @@
+export class HTTPError extends Error {
+	constructor(message: string, public code: number = 400) {
+		super(message);
+	}
+}
diff --git a/src/util/util/imports/OrmUtils.ts b/src/util/util/imports/OrmUtils.ts
new file mode 100644
index 00000000..0556994b
--- /dev/null
+++ b/src/util/util/imports/OrmUtils.ts
@@ -0,0 +1,96 @@
+//source: https://github.com/typeorm/typeorm/blob/master/src/util/OrmUtils.ts
+export class OrmUtils {
+	// Checks if it's an object made by Object.create(null), {} or new Object()
+	private static isPlainObject(item: any) {
+		if (item === null || item === undefined) {
+			return false;
+		}
+
+		return !item.constructor || item.constructor === Object;
+	}
+
+	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);
+			return;
+		}
+
+		if (value instanceof Promise) {
+			// Skip promises entirely.
+			// This is a hold-over from the old code & is because we don't want to pull in
+			// the lazy fields.  Ideally we'd remove these promises via another function first
+			// but for now we have to do it here.
+			return;
+		}
+
+		if (!this.isPlainObject(value) && !Array.isArray(value)) {
+			target[key] = value;
+			return;
+		}
+
+		if (!target[key]) {
+			target[key] = Array.isArray(value) ? [] : {};
+		}
+
+		memo.set(value, target[key]);
+		this.merge(target[key], value, memo);
+		memo.delete(value);
+	}
+
+	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) });
+			return;
+		}
+
+		if (value instanceof Promise) {
+			// Skip promises entirely.
+			// This is a hold-over from the old code & is because we don't want to pull in
+			// the lazy fields.  Ideally we'd remove these promises via another function first
+			// but for now we have to do it here.
+			return;
+		}
+
+		if (!this.isPlainObject(value) && !Array.isArray(value)) {
+			Object.assign(target, { [key]: value });
+			return;
+		}
+
+		if (!target[key]) {
+			Object.assign(target, { [key]: value });
+		}
+
+		memo.set(value, target[key]);
+		this.merge(target[key], value, memo);
+		memo.delete(value);
+	}
+
+	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);
+			}
+		} else {
+			for (const key of Object.keys(source)) {
+				this.mergeObjectKey(target, key, source[key], memo);
+			}
+		}
+	}
+
+	/**
+	 * Deep Object.assign.
+	 */
+	static mergeDeep(target: any, ...sources: any[]): any {
+		if (!sources.length) {
+			return target;
+		}
+
+		for (const source of sources) {
+			OrmUtils.merge(target, source);
+		}
+
+		return target;
+	}
+}
diff --git a/src/util/util/imports/index.ts b/src/util/util/imports/index.ts
new file mode 100644
index 00000000..120cff11
--- /dev/null
+++ b/src/util/util/imports/index.ts
@@ -0,0 +1,3 @@
+export * from "./Checks";
+export * from "./HTTPError";
+export * from "./OrmUtils";
diff --git a/src/util/util/index.ts b/src/util/util/index.ts
new file mode 100644
index 00000000..11f0b72a
--- /dev/null
+++ b/src/util/util/index.ts
@@ -0,0 +1,25 @@
+export * from "./ApiError";
+export * from "./Array";
+export * from "./BitField";
+//export * from "./Categories";
+export * from "./cdn";
+export * from "./Config";
+export * from "./Constants";
+export * from "./Database";
+export * from "./Email";
+export * from "./Event";
+export * from "./FieldError";
+export * from "./imports/HTTPError";
+export * from "./imports/index";
+export * from "./imports/OrmUtils";
+export * from "./Intents";
+export * from "./InvisibleCharacters";
+export * from "./MessageFlags";
+export * from "./Permissions";
+export * from "./RabbitMQ";
+export * from "./Regex";
+export * from "./Rights";
+export * from "./Snowflake";
+export * from "./String";
+export * from "./Token";
+export * from "./TraverseDirectory";