summary refs log tree commit diff
diff options
context:
space:
mode:
-rwxr-xr-x.githooks/pre-commit55
-rw-r--r--.gitignore5
-rw-r--r--.prettierrc6
-rw-r--r--assets/checkLocale.js90
-rw-r--r--assets/developers.html76
-rw-r--r--assets/fosscord-login.css12
-rw-r--r--assets/fosscord.css68
-rw-r--r--assets/index.html154
-rw-r--r--assets/schemas.json2740
-rw-r--r--assets/user.css2
-rw-r--r--build.json.default16
-rw-r--r--docker-compose.cfg.yml7
-rw-r--r--docker-compose.yml41
-rw-r--r--env-vars.md32
-rw-r--r--fosscord-server.code-workspace19
-rw-r--r--package.json28
-rw-r--r--scripts/benchmark.js6
-rw-r--r--scripts/benchmark/connections.js6
-rw-r--r--scripts/benchmark/users.js4
-rw-r--r--scripts/build.js116
-rw-r--r--scripts/build/clean.js18
-rw-r--r--scripts/build/compile_tsc.js48
-rw-r--r--scripts/build/plugin_prepare.js31
-rw-r--r--scripts/build/plugin_resources.js13
-rw-r--r--scripts/build/remap_imports.js15
-rw-r--r--scripts/build_new.js31
-rw-r--r--scripts/code_quality.js75
-rw-r--r--scripts/depcheck.js44
-rw-r--r--scripts/depclean.js25
-rw-r--r--scripts/first_setup.js185
-rw-r--r--scripts/gen_index.js47
-rw-r--r--scripts/generate_schema.js11
-rw-r--r--scripts/migrate_db_engine.js6
-rw-r--r--scripts/rights.js18
-rw-r--r--scripts/update_schemas.js2
-rw-r--r--scripts/utils.js48
-rw-r--r--tests/cdn_endpoints.test.js96
-rw-r--r--tests/routes.test.ts8
-rw-r--r--tests/setupJest.js4
-rw-r--r--tsconfig.json164
40 files changed, 2370 insertions, 2002 deletions
diff --git a/.githooks/pre-commit b/.githooks/pre-commit
new file mode 100755
index 00000000..0d2c8db7
--- /dev/null
+++ b/.githooks/pre-commit
@@ -0,0 +1,55 @@
+#!/bin/sh
+#
+# An example hook script to verify what is about to be committed.
+# Called by "git commit" with no arguments.  The hook should
+# exit with non-zero status after issuing an appropriate message if
+# it wants to stop the commit.
+#
+# To enable this hook, rename this file to "pre-commit".
+
+if git rev-parse --verify HEAD >/dev/null 2>&1
+then
+	against=HEAD
+else
+	# Initial commit: diff against an empty tree object
+	against=$(git hash-object -t tree /dev/null)
+fi
+
+# If you want to allow non-ASCII filenames set this variable to true.
+allownonascii=$(git config --type=bool hooks.allownonascii)
+
+# Redirect output to stderr.
+exec 1>&2
+
+# Cross platform projects tend to avoid non-ASCII filenames; prevent
+# them from being added to the repository. We exploit the fact that the
+# printable range starts at the space character and ends with tilde.
+if [ "$allownonascii" != "true" ] &&
+	# Note that the use of brackets around a tr range is ok here, (it's
+	# even required, for portability to Solaris 10's /usr/bin/tr), since
+	# the square bracket bytes happen to fall in the designated range.
+	test $(git diff --cached --name-only --diff-filter=A -z $against |
+	  LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
+then
+	cat <<\EOF
+Error: Attempt to add a non-ASCII file name.
+
+This can cause problems if you want to work with people on other platforms.
+
+To be portable it is advisable to rename the file.
+
+If you know what you are doing you can disable this check using:
+
+  git config hooks.allownonascii true
+EOF
+	exit 1
+fi
+
+rm -rf dist
+
+#npx prettier -w .
+npx --yes -p prettier@latest -p pretty-quick pretty-quick
+git update-index --again
+
+# If there are whitespace errors, print the offending file names and fail.
+#exec git diff-index --check --cached $against --
diff --git a/.gitignore b/.gitignore
index e9f3f39c..9629f85c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,5 +19,6 @@ api/assets/plugins/*.js
 bundle/depclean.*
 *.tmp
 tmp/
-
-assets/cache/
\ No newline at end of file
+assets/cache/
+*.generated
+initial.json
diff --git a/.prettierrc b/.prettierrc
index 0defea23..cf69bed0 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -2,5 +2,7 @@
 	"tabWidth": 4,
 	"useTabs": true,
 	"printWidth": 140,
-	"trailingComma": "none"
-}
\ No newline at end of file
+	"trailingComma": "none",
+	"pluginSearchDirs": ["./node_modules"],
+	"plugins": ["prettier-plugin-organize-imports"]
+}
diff --git a/assets/checkLocale.js b/assets/checkLocale.js
index 016d66c8..091add1f 100644
--- a/assets/checkLocale.js
+++ b/assets/checkLocale.js
@@ -1,47 +1,47 @@
-			const localStorage = window.localStorage;
-			// TODO: remote auth
-			// window.GLOBAL_ENV.REMOTE_AUTH_ENDPOINT = window.GLOBAL_ENV.GATEWAY_ENDPOINT.replace(/wss?:/, "");
-			localStorage.setItem("gatewayURL", window.GLOBAL_ENV.GATEWAY_ENDPOINT);
-			localStorage.setItem(
-				"DeveloperOptionsStore",
-				`{"trace":false,"canary":false,"logGatewayEvents":true,"logOverlayEvents":true,"logAnalyticsEvents":true,"sourceMapsEnabled":false,"axeEnabled":false}`
-			);
+const localStorage = window.localStorage;
+// TODO: remote auth
+// window.GLOBAL_ENV.REMOTE_AUTH_ENDPOINT = window.GLOBAL_ENV.GATEWAY_ENDPOINT.replace(/wss?:/, "");
+localStorage.setItem("gatewayURL", window.GLOBAL_ENV.GATEWAY_ENDPOINT);
+localStorage.setItem(
+	"DeveloperOptionsStore",
+	`{"trace":false,"canary":false,"logGatewayEvents":true,"logOverlayEvents":true,"logAnalyticsEvents":true,"sourceMapsEnabled":false,"axeEnabled":false}`
+);
 
-			const supportedLocales = [
-				"bg",
-				"cs",
-				"da",
-				"de",
-				"el",
-				"en-GB",
-				"es-ES",
-				"fi",
-				"fr",
-				"hi",
-				"hr",
-				"hu",
-				"it",
-				"ja",
-				"ko",
-				"lt",
-				"nl",
-				"no",
-				"pl",
-				"pt-BR",
-				"ro",
-				"ru",
-				"sv-SE",
-				"th",
-				"tr",
-				"uk",
-				"vi",
-				"zh-CN",
-				"zh-TW"
-			];
+const supportedLocales = [
+	"bg",
+	"cs",
+	"da",
+	"de",
+	"el",
+	"en-GB",
+	"es-ES",
+	"fi",
+	"fr",
+	"hi",
+	"hr",
+	"hu",
+	"it",
+	"ja",
+	"ko",
+	"lt",
+	"nl",
+	"no",
+	"pl",
+	"pt-BR",
+	"ro",
+	"ru",
+	"sv-SE",
+	"th",
+	"tr",
+	"uk",
+	"vi",
+	"zh-CN",
+	"zh-TW"
+];
 
-			const settings = JSON.parse(localStorage.getItem("UserSettingsStore"));
-			if (settings && !supportedLocales.includes(settings.locale)) {
-				// fix client locale wrong and client not loading at all
-				settings.locale = "en-US";
-				localStorage.setItem("UserSettingsStore", JSON.stringify(settings));
-			}
\ No newline at end of file
+const settings = JSON.parse(localStorage.getItem("UserSettingsStore"));
+if (settings && !supportedLocales.includes(settings.locale)) {
+	// fix client locale wrong and client not loading at all
+	settings.locale = "en-US";
+	localStorage.setItem("UserSettingsStore", JSON.stringify(settings));
+}
diff --git a/assets/developers.html b/assets/developers.html
index 87595e77..b33009dd 100644
--- a/assets/developers.html
+++ b/assets/developers.html
@@ -1,44 +1,42 @@
 <!DOCTYPE html>
 <html class="theme-dark" data-theme="dark">
+	<head>
+		<meta charset="utf-8" />
+		<meta content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=no" name="viewport" />
 
-<head>
-	<meta charset="utf-8" />
-	<meta content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=no" name="viewport" />
+		<link rel="stylesheet" href="/assets/532.03aaeef88460fae60534.css" integrity="" />
+		<link rel="icon" href="/assets/07dca80a102d4149e9736d4b162cff6f.ico" />
+		<title>Discord Test Client Developer Portal</title>
+		<meta charset="utf-8" data-react-helmet="true" />
+	</head>
 
-	<link rel="stylesheet" href="/assets/532.03aaeef88460fae60534.css" integrity="" />
-	<link rel="icon" href="/assets/07dca80a102d4149e9736d4b162cff6f.ico" />
-	<title>Discord Test Client Developer Portal</title>
-	<meta charset="utf-8" data-react-helmet="true" />
-</head>
+	<body>
+		<div id="app-mount"></div>
+		<script>
+			window.GLOBAL_ENV = {
+				API_VERSION: 9,
+				API_ENDPOINT: "/api",
+				WEBAPP_ENDPOINT: "",
+				CDN_HOST: `${location.hostname}:3003`,
 
-<body>
-	<div id="app-mount"></div>
-	<script>
-		window.GLOBAL_ENV = {
-			API_VERSION: 9,
-			API_ENDPOINT: "/api",
-			WEBAPP_ENDPOINT: "",
-			CDN_HOST: `${location.hostname}:3003`,
-
-			BRAINTREE_KEY: "production_5st77rrc_49pp2rp4phym7387",
-			STRIPE_KEY: "pk_live_CUQtlpQUF0vufWpnpUmQvcdi",
-			MARKETING_ENDPOINT: "//discord.com",
-			RELEASE_CHANNEL: "stable",
-			ALGOLIA_KEY: "aca0d7082e4e63af5ba5917d5e96bed0"
-		};
-		GLOBAL_ENV.MEDIA_PROXY_ENDPOINT = location.protocol + "//" + GLOBAL_ENV.CDN_HOST;
-		const localStorage = window.localStorage;
-		// TODO: remote auth
-		// window.GLOBAL_ENV.REMOTE_AUTH_ENDPOINT = window.GLOBAL_ENV.GATEWAY_ENDPOINT.replace(/wss?:/, "");
-		localStorage.setItem("gatewayURL", window.GLOBAL_ENV.GATEWAY_ENDPOINT);
-		localStorage.setItem(
-			"DeveloperOptionsStore",
-			`{"trace":false,"canary":false,"logGatewayEvents":true,"logOverlayEvents":true,"logAnalyticsEvents":true,"sourceMapsEnabled":false,"axeEnabled":false}`
-		);
-	</script>
-	<script src="/assets/38f40c32d3c8a2fdf73b.js" integrity=""></script>
-	<script src="/assets/aa190934324e05fcc35c.js" integrity=""></script>
-	<script src="/assets/45664a0209e828a528b4.js" integrity=""></script>
-</body>
-
-</html>
\ No newline at end of file
+				BRAINTREE_KEY: "production_5st77rrc_49pp2rp4phym7387",
+				STRIPE_KEY: "pk_live_CUQtlpQUF0vufWpnpUmQvcdi",
+				MARKETING_ENDPOINT: "//discord.com",
+				RELEASE_CHANNEL: "stable",
+				ALGOLIA_KEY: "aca0d7082e4e63af5ba5917d5e96bed0"
+			};
+			GLOBAL_ENV.MEDIA_PROXY_ENDPOINT = location.protocol + "//" + GLOBAL_ENV.CDN_HOST;
+			const localStorage = window.localStorage;
+			// TODO: remote auth
+			// window.GLOBAL_ENV.REMOTE_AUTH_ENDPOINT = window.GLOBAL_ENV.GATEWAY_ENDPOINT.replace(/wss?:/, "");
+			localStorage.setItem("gatewayURL", window.GLOBAL_ENV.GATEWAY_ENDPOINT);
+			localStorage.setItem(
+				"DeveloperOptionsStore",
+				`{"trace":false,"canary":false,"logGatewayEvents":true,"logOverlayEvents":true,"logAnalyticsEvents":true,"sourceMapsEnabled":false,"axeEnabled":false}`
+			);
+		</script>
+		<script src="/assets/38f40c32d3c8a2fdf73b.js" integrity=""></script>
+		<script src="/assets/aa190934324e05fcc35c.js" integrity=""></script>
+		<script src="/assets/45664a0209e828a528b4.js" integrity=""></script>
+	</body>
+</html>
diff --git a/assets/fosscord-login.css b/assets/fosscord-login.css
index d507c545..975bf908 100644
--- a/assets/fosscord-login.css
+++ b/assets/fosscord-login.css
@@ -1,12 +1,12 @@
 /* replace tos acceptance popup */
 #app-mount > div:nth-child(7) > div > div > div.tooltipContent-bqVLWK {
-    visibility: hidden;
+	visibility: hidden;
 }
-#app-mount > div:nth-child(7) > div > div > div.tooltipContent-bqVLWK::after{
-    visibility: visible;
-    display: block;
-    content: "You need to agree to this instance's rules to continue";
-    margin-top: -32px;
+#app-mount > div:nth-child(7) > div > div > div.tooltipContent-bqVLWK::after {
+	visibility: visible;
+	display: block;
+	content: "You need to agree to this instance's rules to continue";
+	margin-top: -32px;
 }
 /* replace login header */
 #app-mount > div.app-1q1i1E > div > div > div > div > form > div > div > div.mainLoginContainer-1ddwnR > h3 {
diff --git a/assets/fosscord.css b/assets/fosscord.css
index 6078fdeb..fa503d39 100644
--- a/assets/fosscord.css
+++ b/assets/fosscord.css
@@ -1,4 +1,3 @@
-
 /* loading spinner */
 #app-mount > div.app-1q1i1E > div.container-16j22k.fixClipping-3qAKRb > div.content-1-zrf2 > video {
 	filter: opacity(1);
@@ -11,14 +10,62 @@
 }
 
 /* home button icon */
-#app-mount > div.app-1q1i1E > div > div.layers-3iHuyZ.layers-3q14ss > div > div > nav > ul > div.scroller-1Bvpku.none-2Eo-qx.scrollerBase-289Jih > div.tutorialContainer-2sGCg9 > div > div.listItemWrapper-KhRmzM > div > svg > foreignObject > div > div
-{
-    background-image: url(https://raw.githubusercontent.com/fosscord/fosscord/master/assets-rebrand/svg/Fosscord-Icon-Rounded-Subtract.svg);
-    background-size: contain;
-    border-radius: 50%;
+#app-mount
+	> div.app-1q1i1E
+	> div
+	> div.layers-3iHuyZ.layers-3q14ss
+	> div
+	> div
+	> nav
+	> ul
+	> div.scroller-1Bvpku.none-2Eo-qx.scrollerBase-289Jih
+	> div.tutorialContainer-2sGCg9
+	> div
+	> div.listItemWrapper-KhRmzM
+	> div
+	> svg
+	> foreignObject
+	> div
+	> div {
+	background-image: url(https://raw.githubusercontent.com/fosscord/fosscord/master/assets-rebrand/svg/Fosscord-Icon-Rounded-Subtract.svg);
+	background-size: contain;
+	border-radius: 50%;
 }
 
-#app-mount > div.app-1q1i1E > div > div.layers-3iHuyZ.layers-3q14ss > div > div > nav > ul > div.scroller-1Bvpku.none-2Eo-qx.scrollerBase-289Jih > div.tutorialContainer-2sGCg9 > div > div.listItemWrapper-KhRmzM > div > svg > foreignObject > div > div, #app-mount > div.app-1q1i1E > div > div.layers-3iHuyZ.layers-3q14ss > div > div > nav > ul > div.scroller-1Bvpku.none-2Eo-qx.scrollerBase-289Jih > div.tutorialContainer-2sGCg9 > div > div.listItemWrapper-KhRmzM > div > svg > foreignObject > div > div:hover {
+#app-mount
+	> div.app-1q1i1E
+	> div
+	> div.layers-3iHuyZ.layers-3q14ss
+	> div
+	> div
+	> nav
+	> ul
+	> div.scroller-1Bvpku.none-2Eo-qx.scrollerBase-289Jih
+	> div.tutorialContainer-2sGCg9
+	> div
+	> div.listItemWrapper-KhRmzM
+	> div
+	> svg
+	> foreignObject
+	> div
+	> div,
+#app-mount
+	> div.app-1q1i1E
+	> div
+	> div.layers-3iHuyZ.layers-3q14ss
+	> div
+	> div
+	> nav
+	> ul
+	> div.scroller-1Bvpku.none-2Eo-qx.scrollerBase-289Jih
+	> div.tutorialContainer-2sGCg9
+	> div
+	> div.listItemWrapper-KhRmzM
+	> div
+	> svg
+	> foreignObject
+	> div
+	> div:hover {
 	background-color: white;
 }
 /* Login QR */
@@ -40,7 +87,6 @@
 /* Thread permissions etc popups */
 #app-mount > div.app-1q1i1E > div > div.layers-3iHuyZ.layers-3q14ss > div > div > div > div.content-98HsJk > div.sidebar-2K8pFh.hasNotice-1XRy4h > nav > div.container-3O_wAf,
 /* home button icon */
-#app-mount > div.app-1q1i1E > div > div.layers-3iHuyZ.layers-3q14ss > div > div > nav > ul > div.scroller-1Bvpku.none-2Eo-qx.scrollerBase-289Jih > div.tutorialContainer-2sGCg9 > div > div.listItemWrapper-KhRmzM > div > svg > foreignObject > div > div > svg
-{
-    display: none;
-}
\ No newline at end of file
+#app-mount > div.app-1q1i1E > div > div.layers-3iHuyZ.layers-3q14ss > div > div > nav > ul > div.scroller-1Bvpku.none-2Eo-qx.scrollerBase-289Jih > div.tutorialContainer-2sGCg9 > div > div.listItemWrapper-KhRmzM > div > svg > foreignObject > div > div > svg {
+	display: none;
+}
diff --git a/assets/index.html b/assets/index.html
index 64a2bdbf..1d4e4543 100644
--- a/assets/index.html
+++ b/assets/index.html
@@ -1,84 +1,82 @@
 <!DOCTYPE html>
 <html lang="en">
+	<head>
+		<meta charset="UTF-8" />
+		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+		<title>Discord Test Client</title>
+		<link rel="stylesheet" href="/assets/fosscord.css" />
+		<link id="logincss" rel="stylesheet" href="/assets/fosscord-login.css" />
+		<link id="customcss" rel="stylesheet" href="/assets/user.css" />
+		<!-- inline plugin marker -->
+		<!-- preload plugin marker -->
+	</head>
 
-<head>
-	<meta charset="UTF-8" />
-	<meta name="viewport" content="width=device-width, initial-scale=1.0" />
-	<title>Discord Test Client</title>
-	<link rel="stylesheet" href="/assets/fosscord.css" />
-	<link id="logincss" rel="stylesheet" href="/assets/fosscord-login.css" />
-	<link id="customcss" rel="stylesheet" href="/assets/user.css" />
-	<!-- inline plugin marker -->
-	<!-- preload plugin marker -->
-</head>
+	<body>
+		<div id="app-mount"></div>
+		<script>
+			window.__OVERLAY__ = /overlay/.test(location.pathname);
+			window.__BILLING_STANDALONE__ = /^\/billing/.test(location.pathname);
+			window.GLOBAL_ENV = {
+				API_ENDPOINT: "/api",
+				API_VERSION: 9,
+				GATEWAY_ENDPOINT: `${location.protocol === "https:" ? "wss://" : "ws://"}${location.host}`,
+				WEBAPP_ENDPOINT: "",
+				CDN_HOST: `${location.hostname}:3003`,
+				ASSET_ENDPOINT: "",
+				MEDIA_PROXY_ENDPOINT: "https://media.discordapp.net",
+				WIDGET_ENDPOINT: `//${location.host}/widget`,
+				INVITE_HOST: `${location.hostname}/invite`,
+				GUILD_TEMPLATE_HOST: "${location.host}",
+				GIFT_CODE_HOST: "${location.hostname}",
+				RELEASE_CHANNEL: "stable",
+				MARKETING_ENDPOINT: "//discord.com",
+				BRAINTREE_KEY: "production_5st77rrc_49pp2rp4phym7387",
+				STRIPE_KEY: "pk_live_CUQtlpQUF0vufWpnpUmQvcdi",
+				NETWORKING_ENDPOINT: "//router.discordapp.net",
+				RTC_LATENCY_ENDPOINT: "//${location.hostname}/rtc",
+				ACTIVITY_APPLICATION_HOST: "discordsays.com",
+				PROJECT_ENV: "production",
+				REMOTE_AUTH_ENDPOINT: "//localhost:3020",
+				SENTRY_TAGS: { buildId: "75e36d9", buildType: "normal" },
+				MIGRATION_SOURCE_ORIGIN: "https://${location.hostname}",
+				MIGRATION_DESTINATION_ORIGIN: "https://${location.hostname}",
+				HTML_TIMESTAMP: Date.now(),
+				ALGOLIA_KEY: "aca0d7082e4e63af5ba5917d5e96bed0"
+			};
+			GLOBAL_ENV.MEDIA_PROXY_ENDPOINT = location.protocol + "//" + GLOBAL_ENV.CDN_HOST;
+			const localStorage = window.localStorage;
+			// TODO: remote auth
+			// window.GLOBAL_ENV.REMOTE_AUTH_ENDPOINT = window.GLOBAL_ENV.GATEWAY_ENDPOINT.replace(/wss?:/, "");
+			localStorage.setItem("gatewayURL", window.GLOBAL_ENV.GATEWAY_ENDPOINT);
+			localStorage.setItem(
+				"DeveloperOptionsStore",
+				`{"trace":false,"canary":false,"logGatewayEvents":true,"logOverlayEvents":true,"logAnalyticsEvents":true,"sourceMapsEnabled":false,"axeEnabled":false}`
+			);
 
-<body>
-	<div id="app-mount"></div>
-	<script>
-		window.__OVERLAY__ = /overlay/.test(location.pathname);
-		window.__BILLING_STANDALONE__ = /^\/billing/.test(location.pathname);
-		window.GLOBAL_ENV = {
-			API_ENDPOINT: "/api",
-			API_VERSION: 9,
-			GATEWAY_ENDPOINT: `${location.protocol === "https:" ? "wss://" : "ws://"}${location.host}`,
-			WEBAPP_ENDPOINT: "",
-			CDN_HOST: `${location.hostname}:3003`,
-			ASSET_ENDPOINT: "",
-			MEDIA_PROXY_ENDPOINT: "https://media.discordapp.net",
-			WIDGET_ENDPOINT: `//${location.host}/widget`,
-			INVITE_HOST: `${location.hostname}/invite`,
-			GUILD_TEMPLATE_HOST: "${location.host}",
-			GIFT_CODE_HOST: "${location.hostname}",
-			RELEASE_CHANNEL: "stable",
-			MARKETING_ENDPOINT: "//discord.com",
-			BRAINTREE_KEY: "production_5st77rrc_49pp2rp4phym7387",
-			STRIPE_KEY: "pk_live_CUQtlpQUF0vufWpnpUmQvcdi",
-			NETWORKING_ENDPOINT: "//router.discordapp.net",
-			RTC_LATENCY_ENDPOINT: "//${location.hostname}/rtc",
-			ACTIVITY_APPLICATION_HOST: 'discordsays.com',
-			PROJECT_ENV: "production",
-			REMOTE_AUTH_ENDPOINT: "//localhost:3020",
-			SENTRY_TAGS: { buildId: "75e36d9", buildType: "normal" },
-			MIGRATION_SOURCE_ORIGIN: "https://${location.hostname}",
-			MIGRATION_DESTINATION_ORIGIN: "https://${location.hostname}",
-			HTML_TIMESTAMP: Date.now(),
-			ALGOLIA_KEY: "aca0d7082e4e63af5ba5917d5e96bed0",
-		};
-		GLOBAL_ENV.MEDIA_PROXY_ENDPOINT = location.protocol + "//" + GLOBAL_ENV.CDN_HOST;
-		const localStorage = window.localStorage;
-		// TODO: remote auth
-		// window.GLOBAL_ENV.REMOTE_AUTH_ENDPOINT = window.GLOBAL_ENV.GATEWAY_ENDPOINT.replace(/wss?:/, "");
-		localStorage.setItem("gatewayURL", window.GLOBAL_ENV.GATEWAY_ENDPOINT);
-		localStorage.setItem(
-			"DeveloperOptionsStore",
-			`{"trace":false,"canary":false,"logGatewayEvents":true,"logOverlayEvents":true,"logAnalyticsEvents":true,"sourceMapsEnabled":false,"axeEnabled":false}`
-		);
-
-		setInterval(() => {
-			let token = JSON.parse(localStorage.getItem("token"));
-			if (token) {
-				let logincss = document.querySelector('#logincss'),
-					canRemove = logincss ? logincss : "";
-				if (canRemove !== "") {
-					document.querySelector("#logincss").remove();
-					canRemove = "";
+			setInterval(() => {
+				let token = JSON.parse(localStorage.getItem("token"));
+				if (token) {
+					let logincss = document.querySelector("#logincss"),
+						canRemove = logincss ? logincss : "";
+					if (canRemove !== "") {
+						document.querySelector("#logincss").remove();
+						canRemove = "";
+					}
 				}
-			}
-		}, 1000)
+			}, 1000);
 
-		const settings = JSON.parse(localStorage.getItem("UserSettingsStore"));
-		if (settings && settings.locale.length <= 2) {
-			// fix client locale wrong and client not loading at all
-			settings.locale = "en-US";
-			localStorage.setItem("UserSettingsStore", JSON.stringify(settings));
-		}
-	</script>
-	<script src="/assets/checkLocale.js"></script>
-	<script src="/assets/2f2e0c25e45eb2f5a6f1.js"></script>
-	<script src="/assets/006e72c08a4c69cb66fc.js"></script>
-	<script src="/assets/2f94a3ba801087653a38.js"></script>
-	<script src="/assets/f7703f092bdbfc607cc7.js"></script>
-	<!-- plugin marker -->
-</body>
-
-</html>
\ No newline at end of file
+			const settings = JSON.parse(localStorage.getItem("UserSettingsStore"));
+			if (settings && settings.locale.length <= 2) {
+				// fix client locale wrong and client not loading at all
+				settings.locale = "en-US";
+				localStorage.setItem("UserSettingsStore", JSON.stringify(settings));
+			}
+		</script>
+		<script src="/assets/checkLocale.js"></script>
+		<script src="/assets/2f2e0c25e45eb2f5a6f1.js"></script>
+		<script src="/assets/006e72c08a4c69cb66fc.js"></script>
+		<script src="/assets/2f94a3ba801087653a38.js"></script>
+		<script src="/assets/f7703f092bdbfc607cc7.js"></script>
+		<!-- plugin marker -->
+	</body>
+</html>
diff --git a/assets/schemas.json b/assets/schemas.json
index 0fe3dfa1..e3200800 100644
--- a/assets/schemas.json
+++ b/assets/schemas.json
@@ -1,1471 +1,1271 @@
 {
-    "ActivitySchema": {
-        "type": "object",
-        "properties": {
-            "afk": {
-                "type": "boolean"
-            },
-            "status": {},
-            "activities": {
-                "type": "array",
-                "items": {}
-            },
-            "since": {
-                "type": "integer"
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "afk",
-            "status"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "BanCreateSchema": {
-        "type": "object",
-        "properties": {
-            "delete_message_days": {
-                "type": "string"
-            },
-            "reason": {
-                "type": "string"
-            }
-        },
-        "additionalProperties": false,
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "BanModeratorSchema": {
-        "type": "object",
-        "properties": {
-            "id": {
-                "type": "string"
-            },
-            "user_id": {
-                "type": "string"
-            },
-            "guild_id": {
-                "type": "string"
-            },
-            "executor_id": {
-                "type": "string"
-            },
-            "reason": {
-                "type": "string"
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "executor_id",
-            "guild_id",
-            "id",
-            "user_id"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "BanRegistrySchema": {
-        "type": "object",
-        "properties": {
-            "id": {
-                "type": "string"
-            },
-            "user_id": {
-                "type": "string"
-            },
-            "guild_id": {
-                "type": "string"
-            },
-            "executor_id": {
-                "type": "string"
-            },
-            "ip": {
-                "type": "string"
-            },
-            "reason": {
-                "type": "string"
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "executor_id",
-            "guild_id",
-            "id",
-            "user_id"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "BulkDeleteSchema": {
-        "type": "object",
-        "properties": {
-            "messages": {
-                "type": "array",
-                "items": {
-                    "type": "string"
-                }
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "messages"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "ts.server.TypingInstallerResponse": {
-        "type": "object",
-        "properties": {
-            "kind": {
-                "enum": [
-                    "action::invalidate",
-                    "action::packageInstalled",
-                    "action::set",
-                    "event::beginInstallTypes",
-                    "event::endInstallTypes",
-                    "event::initializationFailed",
-                    "event::typesRegistry"
-                ],
-                "type": "string"
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "kind"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "ts.server.PackageInstalledResponse": {
-        "type": "object",
-        "properties": {
-            "kind": {
-                "type": "string",
-                "enum": [
-                    "action::packageInstalled"
-                ]
-            },
-            "success": {
-                "type": "boolean"
-            },
-            "message": {
-                "type": "string"
-            },
-            "projectName": {
-                "type": "string"
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "kind",
-            "message",
-            "projectName",
-            "success"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "ts.server.InitializationFailedResponse": {
-        "type": "object",
-        "properties": {
-            "kind": {
-                "type": "string",
-                "enum": [
-                    "event::initializationFailed"
-                ]
-            },
-            "message": {
-                "type": "string"
-            },
-            "stack": {
-                "type": "string"
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "kind",
-            "message"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "ts.server.ProjectResponse": {
-        "type": "object",
-        "properties": {
-            "projectName": {
-                "type": "string"
-            },
-            "kind": {
-                "enum": [
-                    "action::invalidate",
-                    "action::packageInstalled",
-                    "action::set",
-                    "event::beginInstallTypes",
-                    "event::endInstallTypes",
-                    "event::initializationFailed",
-                    "event::typesRegistry"
-                ],
-                "type": "string"
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "kind",
-            "projectName"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "ChannelPermissionOverwriteSchema": {
-        "type": "object",
-        "additionalProperties": false,
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "ChannelReorderSchema": {
-        "type": "array",
-        "items": {
-            "type": "object",
-            "properties": {
-                "id": {
-                    "type": "string"
-                },
-                "position": {
-                    "type": "integer"
-                },
-                "lock_permissions": {
-                    "type": "boolean"
-                },
-                "parent_id": {
-                    "type": "string"
-                }
-            },
-            "additionalProperties": false,
-            "required": [
-                "id"
-            ]
-        },
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "DmChannelCreateSchema": {
-        "type": "object",
-        "properties": {
-            "name": {
-                "type": "string"
-            },
-            "recipients": {
-                "type": "array",
-                "items": {
-                    "type": "string"
-                }
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "recipients"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "EmojiCreateSchema": {
-        "type": "object",
-        "properties": {
-            "name": {
-                "type": "string"
-            },
-            "image": {
-                "type": "string"
-            },
-            "require_colons": {
-                "type": [
-                    "null",
-                    "boolean"
-                ]
-            },
-            "roles": {
-                "type": "array",
-                "items": {
-                    "type": "string"
-                }
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "image"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "EmojiModifySchema": {
-        "type": "object",
-        "properties": {
-            "name": {
-                "type": "string"
-            },
-            "roles": {
-                "type": "array",
-                "items": {
-                    "type": "string"
-                }
-            }
-        },
-        "additionalProperties": false,
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "GuildCreateSchema": {
-        "type": "object",
-        "properties": {
-            "name": {
-                "maxLength": 100,
-                "type": "string"
-            },
-            "region": {
-                "type": "string"
-            },
-            "icon": {
-                "type": [
-                    "null",
-                    "string"
-                ]
-            },
-            "channels": {
-                "type": "array",
-                "items": {
-                    "$ref": "#/definitions/ChannelModifySchema"
-                }
-            },
-            "guild_template_code": {
-                "type": "string"
-            },
-            "system_channel_id": {
-                "type": "string"
-            },
-            "rules_channel_id": {
-                "type": "string"
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "name"
-        ],
-        "definitions": {
-            "ChannelModifySchema": {
-                "type": "object",
-                "properties": {
-                    "name": {
-                        "maxLength": 100,
-                        "type": "string"
-                    },
-                    "type": {
-                        "enum": [
-                            0,
-                            1,
-                            10,
-                            11,
-                            12,
-                            13,
-                            14,
-                            15,
-                            2,
-                            255,
-                            3,
-                            33,
-                            34,
-                            35,
-                            4,
-                            5,
-                            6,
-                            64,
-                            7,
-                            8,
-                            9
-                        ],
-                        "type": "number"
-                    },
-                    "topic": {
-                        "type": "string"
-                    },
-                    "icon": {
-                        "type": [
-                            "null",
-                            "string"
-                        ]
-                    },
-                    "bitrate": {
-                        "type": "integer"
-                    },
-                    "user_limit": {
-                        "type": "integer"
-                    },
-                    "rate_limit_per_user": {
-                        "type": "integer"
-                    },
-                    "position": {
-                        "type": "integer"
-                    },
-                    "permission_overwrites": {
-                        "type": "array",
-                        "items": {
-                            "type": "object",
-                            "properties": {
-                                "id": {
-                                    "type": "string"
-                                },
-                                "type": {
-                                    "$ref": "#/definitions/ChannelPermissionOverwriteType"
-                                },
-                                "allow": {
-                                    "type": "string"
-                                },
-                                "deny": {
-                                    "type": "string"
-                                }
-                            },
-                            "additionalProperties": false,
-                            "required": [
-                                "allow",
-                                "deny",
-                                "id",
-                                "type"
-                            ]
-                        }
-                    },
-                    "parent_id": {
-                        "type": "string"
-                    },
-                    "id": {
-                        "type": "string"
-                    },
-                    "nsfw": {
-                        "type": "boolean"
-                    },
-                    "rtc_region": {
-                        "type": "string"
-                    },
-                    "default_auto_archive_duration": {
-                        "type": "integer"
-                    },
-                    "flags": {
-                        "type": "integer"
-                    },
-                    "default_thread_rate_limit_per_user": {
-                        "type": "integer"
-                    }
-                },
-                "additionalProperties": false
-            },
-            "ChannelPermissionOverwriteType": {
-                "enum": [
-                    0,
-                    1,
-                    2
-                ],
-                "type": "number"
-            }
-        },
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "GuildTemplateCreateSchema": {
-        "type": "object",
-        "properties": {
-            "name": {
-                "type": "string"
-            },
-            "avatar": {
-                "type": [
-                    "null",
-                    "string"
-                ]
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "name"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "GuildUpdateSchema": {
-        "type": "object",
-        "properties": {
-            "name": {
-                "type": "string"
-            },
-            "banner": {
-                "type": [
-                    "null",
-                    "string"
-                ]
-            },
-            "splash": {
-                "type": [
-                    "null",
-                    "string"
-                ]
-            },
-            "description": {
-                "type": "string"
-            },
-            "features": {
-                "type": "array",
-                "items": {
-                    "type": "string"
-                }
-            },
-            "verification_level": {
-                "type": "integer"
-            },
-            "default_message_notifications": {
-                "type": "integer"
-            },
-            "system_channel_flags": {
-                "type": "integer"
-            },
-            "explicit_content_filter": {
-                "type": "integer"
-            },
-            "public_updates_channel_id": {
-                "type": "string"
-            },
-            "afk_timeout": {
-                "type": "integer"
-            },
-            "afk_channel_id": {
-                "type": "string"
-            },
-            "preferred_locale": {
-                "type": "string"
-            },
-            "premium_progress_bar_enabled": {
-                "type": "boolean"
-            },
-            "region": {
-                "type": "string"
-            },
-            "icon": {
-                "type": [
-                    "null",
-                    "string"
-                ]
-            },
-            "guild_template_code": {
-                "type": "string"
-            },
-            "system_channel_id": {
-                "type": "string"
-            },
-            "rules_channel_id": {
-                "type": "string"
-            }
-        },
-        "additionalProperties": false,
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "GuildUpdateWelcomeScreenSchema": {
-        "type": "object",
-        "properties": {
-            "welcome_channels": {
-                "type": "array",
-                "items": {
-                    "type": "object",
-                    "properties": {
-                        "channel_id": {
-                            "type": "string"
-                        },
-                        "description": {
-                            "type": "string"
-                        },
-                        "emoji_id": {
-                            "type": "string"
-                        },
-                        "emoji_name": {
-                            "type": "string"
-                        }
-                    },
-                    "additionalProperties": false,
-                    "required": [
-                        "channel_id",
-                        "description",
-                        "emoji_name"
-                    ]
-                }
-            },
-            "enabled": {
-                "type": "boolean"
-            },
-            "description": {
-                "type": "string"
-            }
-        },
-        "additionalProperties": false,
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "IdentifySchema": {
-        "type": "object",
-        "properties": {
-            "token": {
-                "type": "string"
-            },
-            "properties": {
-                "type": "object",
-                "properties": {
-                    "os": {
-                        "type": "string"
-                    },
-                    "os_atch": {
-                        "type": "string"
-                    },
-                    "browser": {
-                        "type": "string"
-                    },
-                    "device": {
-                        "type": "string"
-                    },
-                    "$os": {
-                        "type": "string"
-                    },
-                    "$browser": {
-                        "type": "string"
-                    },
-                    "$device": {
-                        "type": "string"
-                    },
-                    "browser_user_agent": {
-                        "type": "string"
-                    },
-                    "browser_version": {
-                        "type": "string"
-                    },
-                    "os_version": {
-                        "type": "string"
-                    },
-                    "referrer": {
-                        "type": "string"
-                    },
-                    "referring_domain": {
-                        "type": "string"
-                    },
-                    "referrer_current": {
-                        "type": "string"
-                    },
-                    "referring_domain_current": {
-                        "type": "string"
-                    },
-                    "release_channel": {
-                        "enum": [
-                            "canary",
-                            "dev",
-                            "ptb",
-                            "stable"
-                        ],
-                        "type": "string"
-                    },
-                    "client_build_number": {
-                        "type": "integer"
-                    },
-                    "client_event_source": {},
-                    "client_version": {
-                        "type": "string"
-                    },
-                    "system_locale": {
-                        "type": "string"
-                    }
-                },
-                "additionalProperties": false
-            },
-            "intents": {
-                "type": "string"
-            },
-            "presence": {
-                "$ref": "#/definitions/ActivitySchema"
-            },
-            "compress": {
-                "type": "boolean"
-            },
-            "large_threshold": {
-                "type": "integer"
-            },
-            "shard": {
-                "type": "array",
-                "items": [
-                    {
-                        "type": "integer"
-                    },
-                    {
-                        "type": "integer"
-                    }
-                ],
-                "minItems": 2,
-                "maxItems": 2
-            },
-            "guild_subscriptions": {
-                "type": "boolean"
-            },
-            "capabilities": {
-                "type": "integer"
-            },
-            "client_state": {
-                "type": "object",
-                "properties": {
-                    "guild_hashes": {},
-                    "highest_last_message_id": {
-                        "type": "string"
-                    },
-                    "read_state_version": {
-                        "type": "integer"
-                    },
-                    "user_guild_settings_version": {
-                        "type": "integer"
-                    },
-                    "user_settings_version": {
-                        "type": "integer"
-                    }
-                },
-                "additionalProperties": false
-            },
-            "v": {
-                "type": "integer"
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "properties",
-            "token"
-        ],
-        "definitions": {
-            "ActivitySchema": {
-                "type": "object",
-                "properties": {
-                    "afk": {
-                        "type": "boolean"
-                    },
-                    "status": {},
-                    "activities": {
-                        "type": "array",
-                        "items": {}
-                    },
-                    "since": {
-                        "type": "integer"
-                    }
-                },
-                "additionalProperties": false,
-                "required": [
-                    "afk",
-                    "status"
-                ]
-            }
-        },
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "InviteCreateSchema": {
-        "type": "object",
-        "properties": {
-            "target_user_id": {
-                "type": "string"
-            },
-            "target_type": {
-                "type": "string"
-            },
-            "validate": {
-                "type": "string"
-            },
-            "max_age": {
-                "type": "integer"
-            },
-            "max_uses": {
-                "type": "integer"
-            },
-            "temporary": {
-                "type": "boolean"
-            },
-            "unique": {
-                "type": "boolean"
-            },
-            "target_user": {
-                "type": "string"
-            },
-            "target_user_type": {
-                "type": "integer"
-            }
-        },
-        "additionalProperties": false,
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "LoginSchema": {
-        "type": "object",
-        "properties": {
-            "login": {
-                "type": "string"
-            },
-            "password": {
-                "type": "string"
-            },
-            "undelete": {
-                "type": "boolean"
-            },
-            "captcha_key": {
-                "type": "string"
-            },
-            "login_source": {
-                "type": "string"
-            },
-            "gift_code_sku_id": {
-                "type": "string"
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "login",
-            "password"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "MemberChangeSchema": {
-        "type": "object",
-        "properties": {
-            "roles": {
-                "type": "array",
-                "items": {
-                    "type": "string"
-                }
-            }
-        },
-        "additionalProperties": false,
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "MemberNickChangeSchema": {
-        "type": "object",
-        "properties": {
-            "nick": {
-                "type": "string"
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "nick"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "MessageAcknowledgeSchema": {
-        "type": "object",
-        "properties": {
-            "manual": {
-                "type": "boolean"
-            },
-            "mention_count": {
-                "type": "integer"
-            }
-        },
-        "additionalProperties": false,
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "MessageCreateSchema": {
-        "type": "object",
-        "properties": {
-            "type": {
-                "type": "integer"
-            },
-            "content": {
-                "type": "string"
-            },
-            "nonce": {
-                "type": "string"
-            },
-            "channel_id": {
-                "type": "string"
-            },
-            "tts": {
-                "type": "boolean"
-            },
-            "flags": {
-                "type": "string"
-            },
-            "embeds": {
-                "type": "array",
-                "items": {}
-            },
-            "embed": {},
-            "allowed_mentions": {
-                "type": "object",
-                "properties": {
-                    "parse": {
-                        "type": "array",
-                        "items": {
-                            "type": "string"
-                        }
-                    },
-                    "roles": {
-                        "type": "array",
-                        "items": {
-                            "type": "string"
-                        }
-                    },
-                    "users": {
-                        "type": "array",
-                        "items": {
-                            "type": "string"
-                        }
-                    },
-                    "replied_user": {
-                        "type": "boolean"
-                    }
-                },
-                "additionalProperties": false
-            },
-            "message_reference": {
-                "type": "object",
-                "properties": {
-                    "message_id": {
-                        "type": "string"
-                    },
-                    "channel_id": {
-                        "type": "string"
-                    },
-                    "guild_id": {
-                        "type": "string"
-                    },
-                    "fail_if_not_exists": {
-                        "type": "boolean"
-                    }
-                },
-                "additionalProperties": false,
-                "required": [
-                    "channel_id",
-                    "message_id"
-                ]
-            },
-            "payload_json": {
-                "type": "string"
-            },
-            "file": {},
-            "attachments": {
-                "description": "TODO: we should create an interface for attachments\nTODO: OpenWAAO<-->attachment-style metadata conversion",
-                "type": "array",
-                "items": {}
-            },
-            "sticker_ids": {
-                "type": "array",
-                "items": {
-                    "type": "string"
-                }
-            }
-        },
-        "additionalProperties": false,
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "MfaCodesSchema": {
-        "type": "object",
-        "properties": {
-            "password": {
-                "type": "string"
-            },
-            "regenerate": {
-                "type": "boolean"
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "password"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "ModifyGuildStickerSchema": {
-        "type": "object",
-        "properties": {
-            "name": {
-                "minLength": 2,
-                "maxLength": 30,
-                "type": "string"
-            },
-            "description": {
-                "maxLength": 100,
-                "type": "string"
-            },
-            "tags": {
-                "maxLength": 200,
-                "type": "string"
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "name",
-            "tags"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "PruneSchema": {
-        "type": "object",
-        "properties": {
-            "days": {
-                "type": "integer"
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "days"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "PurgeSchema": {
-        "type": "object",
-        "properties": {
-            "before": {
-                "type": "string"
-            },
-            "after": {
-                "type": "string"
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "after",
-            "before"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "RegisterSchema": {
-        "type": "object",
-        "properties": {
-            "username": {
-                "minLength": 2,
-                "maxLength": 32,
-                "type": "string"
-            },
-            "password": {
-                "minLength": 1,
-                "maxLength": 72,
-                "type": "string"
-            },
-            "consent": {
-                "type": "boolean"
-            },
-            "email": {
-                "format": "email",
-                "type": "string"
-            },
-            "fingerprint": {
-                "type": "string"
-            },
-            "invite": {
-                "type": "string"
-            },
-            "date_of_birth": {
-                "type": "string"
-            },
-            "gift_code_sku_id": {
-                "type": "string"
-            },
-            "captcha_key": {
-                "type": "string"
-            },
-            "promotional_email_opt_in": {
-                "type": "boolean"
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "consent",
-            "username"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "RelationshipPostSchema": {
-        "type": "object",
-        "properties": {
-            "discriminator": {
-                "type": "string"
-            },
-            "username": {
-                "type": "string"
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "discriminator",
-            "username"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "RelationshipPutSchema": {
-        "type": "object",
-        "properties": {
-            "type": {}
-        },
-        "additionalProperties": false,
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "RoleModifySchema": {
-        "type": "object",
-        "properties": {
-            "name": {
-                "type": "string"
-            },
-            "permissions": {
-                "type": "string"
-            },
-            "color": {
-                "type": "integer"
-            },
-            "hoist": {
-                "type": "boolean"
-            },
-            "mentionable": {
-                "type": "boolean"
-            },
-            "position": {
-                "type": "integer"
-            },
-            "icon": {
-                "type": "string"
-            },
-            "unicode_emoji": {
-                "type": "string"
-            }
-        },
-        "additionalProperties": false,
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "RolePositionUpdateSchema": {
-        "type": "array",
-        "items": {
-            "type": "object",
-            "properties": {
-                "id": {
-                    "type": "string"
-                },
-                "position": {
-                    "type": "integer"
-                }
-            },
-            "additionalProperties": false,
-            "required": [
-                "id",
-                "position"
-            ]
-        },
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "TemplateCreateSchema": {
-        "type": "object",
-        "properties": {
-            "name": {
-                "type": "string"
-            },
-            "description": {
-                "type": "string"
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "name"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "TemplateModifySchema": {
-        "type": "object",
-        "properties": {
-            "name": {
-                "type": "string"
-            },
-            "description": {
-                "type": "string"
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "name"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "TotpDisableSchema": {
-        "type": "object",
-        "properties": {
-            "code": {
-                "type": "string"
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "code"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "TotpEnableSchema": {
-        "type": "object",
-        "properties": {
-            "password": {
-                "type": "string"
-            },
-            "code": {
-                "type": "string"
-            },
-            "secret": {
-                "type": "string"
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "password"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "TotpSchema": {
-        "type": "object",
-        "properties": {
-            "code": {
-                "type": "string"
-            },
-            "ticket": {
-                "type": "string"
-            },
-            "gift_code_sku_id": {
-                "type": [
-                    "null",
-                    "string"
-                ]
-            },
-            "login_source": {
-                "type": [
-                    "null",
-                    "string"
-                ]
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "code",
-            "ticket"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "UserModifySchema": {
-        "type": "object",
-        "properties": {
-            "username": {
-                "minLength": 1,
-                "maxLength": 100,
-                "type": "string"
-            },
-            "discriminator": {
-                "type": "string"
-            },
-            "avatar": {
-                "type": [
-                    "null",
-                    "string"
-                ]
-            },
-            "bio": {
-                "maxLength": 1024,
-                "type": "string"
-            },
-            "accent_color": {
-                "type": "integer"
-            },
-            "banner": {
-                "type": [
-                    "null",
-                    "string"
-                ]
-            },
-            "password": {
-                "type": "string"
-            },
-            "new_password": {
-                "type": "string"
-            },
-            "code": {
-                "type": "string"
-            }
-        },
-        "additionalProperties": false,
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "UserSettingsSchema": {
-        "type": "object",
-        "additionalProperties": false,
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "VanityUrlSchema": {
-        "type": "object",
-        "properties": {
-            "code": {
-                "minLength": 1,
-                "maxLength": 20,
-                "type": "string"
-            }
-        },
-        "additionalProperties": false,
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "VoiceStateUpdateSchema": {
-        "type": "object",
-        "properties": {
-            "channel_id": {
-                "type": "string"
-            },
-            "guild_id": {
-                "type": "string"
-            },
-            "suppress": {
-                "type": "boolean"
-            },
-            "request_to_speak_timestamp": {
-                "type": "string",
-                "format": "date-time"
-            },
-            "self_mute": {
-                "type": "boolean"
-            },
-            "self_deaf": {
-                "type": "boolean"
-            },
-            "self_video": {
-                "type": "boolean"
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "channel_id"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "WebhookCreateSchema": {
-        "type": "object",
-        "properties": {
-            "name": {
-                "maxLength": 80,
-                "type": "string"
-            },
-            "avatar": {
-                "type": "string"
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "name"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "WidgetModifySchema": {
-        "type": "object",
-        "properties": {
-            "enabled": {
-                "type": "boolean"
-            },
-            "channel_id": {
-                "type": "string"
-            }
-        },
-        "additionalProperties": false,
-        "required": [
-            "channel_id",
-            "enabled"
-        ],
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    },
-    "ChannelModifySchema": {
-        "type": "object",
-        "properties": {
-            "name": {
-                "maxLength": 100,
-                "type": "string"
-            },
-            "type": {
-                "enum": [
-                    0,
-                    1,
-                    10,
-                    11,
-                    12,
-                    13,
-                    14,
-                    15,
-                    2,
-                    255,
-                    3,
-                    33,
-                    34,
-                    35,
-                    4,
-                    5,
-                    6,
-                    64,
-                    7,
-                    8,
-                    9
-                ],
-                "type": "number"
-            },
-            "topic": {
-                "type": "string"
-            },
-            "icon": {
-                "type": [
-                    "null",
-                    "string"
-                ]
-            },
-            "bitrate": {
-                "type": "integer"
-            },
-            "user_limit": {
-                "type": "integer"
-            },
-            "rate_limit_per_user": {
-                "type": "integer"
-            },
-            "position": {
-                "type": "integer"
-            },
-            "permission_overwrites": {
-                "type": "array",
-                "items": {
-                    "type": "object",
-                    "properties": {
-                        "id": {
-                            "type": "string"
-                        },
-                        "type": {
-                            "$ref": "#/definitions/ChannelPermissionOverwriteType"
-                        },
-                        "allow": {
-                            "type": "string"
-                        },
-                        "deny": {
-                            "type": "string"
-                        }
-                    },
-                    "additionalProperties": false,
-                    "required": [
-                        "allow",
-                        "deny",
-                        "id",
-                        "type"
-                    ]
-                }
-            },
-            "parent_id": {
-                "type": "string"
-            },
-            "id": {
-                "type": "string"
-            },
-            "nsfw": {
-                "type": "boolean"
-            },
-            "rtc_region": {
-                "type": "string"
-            },
-            "default_auto_archive_duration": {
-                "type": "integer"
-            },
-            "flags": {
-                "type": "integer"
-            },
-            "default_thread_rate_limit_per_user": {
-                "type": "integer"
-            }
-        },
-        "additionalProperties": false,
-        "definitions": {
-            "ChannelPermissionOverwriteType": {
-                "enum": [
-                    0,
-                    1,
-                    2
-                ],
-                "type": "number"
-            }
-        },
-        "$schema": "http://json-schema.org/draft-07/schema#"
-    }
-}
\ No newline at end of file
+	"ActivitySchema": {
+		"type": "object",
+		"properties": {
+			"afk": {
+				"type": "boolean"
+			},
+			"status": {},
+			"activities": {
+				"type": "array",
+				"items": {}
+			},
+			"since": {
+				"type": "integer"
+			}
+		},
+		"additionalProperties": false,
+		"required": ["afk", "status"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"BanCreateSchema": {
+		"type": "object",
+		"properties": {
+			"delete_message_days": {
+				"type": "string"
+			},
+			"reason": {
+				"type": "string"
+			}
+		},
+		"additionalProperties": false,
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"BanModeratorSchema": {
+		"type": "object",
+		"properties": {
+			"id": {
+				"type": "string"
+			},
+			"user_id": {
+				"type": "string"
+			},
+			"guild_id": {
+				"type": "string"
+			},
+			"executor_id": {
+				"type": "string"
+			},
+			"reason": {
+				"type": "string"
+			}
+		},
+		"additionalProperties": false,
+		"required": ["executor_id", "guild_id", "id", "user_id"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"BanRegistrySchema": {
+		"type": "object",
+		"properties": {
+			"id": {
+				"type": "string"
+			},
+			"user_id": {
+				"type": "string"
+			},
+			"guild_id": {
+				"type": "string"
+			},
+			"executor_id": {
+				"type": "string"
+			},
+			"ip": {
+				"type": "string"
+			},
+			"reason": {
+				"type": "string"
+			}
+		},
+		"additionalProperties": false,
+		"required": ["executor_id", "guild_id", "id", "user_id"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"BulkDeleteSchema": {
+		"type": "object",
+		"properties": {
+			"messages": {
+				"type": "array",
+				"items": {
+					"type": "string"
+				}
+			}
+		},
+		"additionalProperties": false,
+		"required": ["messages"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"ts.server.TypingInstallerResponse": {
+		"type": "object",
+		"properties": {
+			"kind": {
+				"enum": [
+					"action::invalidate",
+					"action::packageInstalled",
+					"action::set",
+					"event::beginInstallTypes",
+					"event::endInstallTypes",
+					"event::initializationFailed",
+					"event::typesRegistry"
+				],
+				"type": "string"
+			}
+		},
+		"additionalProperties": false,
+		"required": ["kind"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"ts.server.PackageInstalledResponse": {
+		"type": "object",
+		"properties": {
+			"kind": {
+				"type": "string",
+				"enum": ["action::packageInstalled"]
+			},
+			"success": {
+				"type": "boolean"
+			},
+			"message": {
+				"type": "string"
+			},
+			"projectName": {
+				"type": "string"
+			}
+		},
+		"additionalProperties": false,
+		"required": ["kind", "message", "projectName", "success"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"ts.server.InitializationFailedResponse": {
+		"type": "object",
+		"properties": {
+			"kind": {
+				"type": "string",
+				"enum": ["event::initializationFailed"]
+			},
+			"message": {
+				"type": "string"
+			},
+			"stack": {
+				"type": "string"
+			}
+		},
+		"additionalProperties": false,
+		"required": ["kind", "message"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"ts.server.ProjectResponse": {
+		"type": "object",
+		"properties": {
+			"projectName": {
+				"type": "string"
+			},
+			"kind": {
+				"enum": [
+					"action::invalidate",
+					"action::packageInstalled",
+					"action::set",
+					"event::beginInstallTypes",
+					"event::endInstallTypes",
+					"event::initializationFailed",
+					"event::typesRegistry"
+				],
+				"type": "string"
+			}
+		},
+		"additionalProperties": false,
+		"required": ["kind", "projectName"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"ChannelPermissionOverwriteSchema": {
+		"type": "object",
+		"additionalProperties": false,
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"ChannelReorderSchema": {
+		"type": "array",
+		"items": {
+			"type": "object",
+			"properties": {
+				"id": {
+					"type": "string"
+				},
+				"position": {
+					"type": "integer"
+				},
+				"lock_permissions": {
+					"type": "boolean"
+				},
+				"parent_id": {
+					"type": "string"
+				}
+			},
+			"additionalProperties": false,
+			"required": ["id"]
+		},
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"DmChannelCreateSchema": {
+		"type": "object",
+		"properties": {
+			"name": {
+				"type": "string"
+			},
+			"recipients": {
+				"type": "array",
+				"items": {
+					"type": "string"
+				}
+			}
+		},
+		"additionalProperties": false,
+		"required": ["recipients"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"EmojiCreateSchema": {
+		"type": "object",
+		"properties": {
+			"name": {
+				"type": "string"
+			},
+			"image": {
+				"type": "string"
+			},
+			"require_colons": {
+				"type": ["null", "boolean"]
+			},
+			"roles": {
+				"type": "array",
+				"items": {
+					"type": "string"
+				}
+			}
+		},
+		"additionalProperties": false,
+		"required": ["image"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"EmojiModifySchema": {
+		"type": "object",
+		"properties": {
+			"name": {
+				"type": "string"
+			},
+			"roles": {
+				"type": "array",
+				"items": {
+					"type": "string"
+				}
+			}
+		},
+		"additionalProperties": false,
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"GuildCreateSchema": {
+		"type": "object",
+		"properties": {
+			"name": {
+				"maxLength": 100,
+				"type": "string"
+			},
+			"region": {
+				"type": "string"
+			},
+			"icon": {
+				"type": ["null", "string"]
+			},
+			"channels": {
+				"type": "array",
+				"items": {
+					"$ref": "#/definitions/ChannelModifySchema"
+				}
+			},
+			"guild_template_code": {
+				"type": "string"
+			},
+			"system_channel_id": {
+				"type": "string"
+			},
+			"rules_channel_id": {
+				"type": "string"
+			}
+		},
+		"additionalProperties": false,
+		"required": ["name"],
+		"definitions": {
+			"ChannelModifySchema": {
+				"type": "object",
+				"properties": {
+					"name": {
+						"maxLength": 100,
+						"type": "string"
+					},
+					"type": {
+						"enum": [0, 1, 10, 11, 12, 13, 14, 15, 2, 255, 3, 33, 34, 35, 4, 5, 6, 64, 7, 8, 9],
+						"type": "number"
+					},
+					"topic": {
+						"type": "string"
+					},
+					"icon": {
+						"type": ["null", "string"]
+					},
+					"bitrate": {
+						"type": "integer"
+					},
+					"user_limit": {
+						"type": "integer"
+					},
+					"rate_limit_per_user": {
+						"type": "integer"
+					},
+					"position": {
+						"type": "integer"
+					},
+					"permission_overwrites": {
+						"type": "array",
+						"items": {
+							"type": "object",
+							"properties": {
+								"id": {
+									"type": "string"
+								},
+								"type": {
+									"$ref": "#/definitions/ChannelPermissionOverwriteType"
+								},
+								"allow": {
+									"type": "string"
+								},
+								"deny": {
+									"type": "string"
+								}
+							},
+							"additionalProperties": false,
+							"required": ["allow", "deny", "id", "type"]
+						}
+					},
+					"parent_id": {
+						"type": "string"
+					},
+					"id": {
+						"type": "string"
+					},
+					"nsfw": {
+						"type": "boolean"
+					},
+					"rtc_region": {
+						"type": "string"
+					},
+					"default_auto_archive_duration": {
+						"type": "integer"
+					},
+					"flags": {
+						"type": "integer"
+					},
+					"default_thread_rate_limit_per_user": {
+						"type": "integer"
+					}
+				},
+				"additionalProperties": false
+			},
+			"ChannelPermissionOverwriteType": {
+				"enum": [0, 1, 2],
+				"type": "number"
+			}
+		},
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"GuildTemplateCreateSchema": {
+		"type": "object",
+		"properties": {
+			"name": {
+				"type": "string"
+			},
+			"avatar": {
+				"type": ["null", "string"]
+			}
+		},
+		"additionalProperties": false,
+		"required": ["name"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"GuildUpdateSchema": {
+		"type": "object",
+		"properties": {
+			"name": {
+				"type": "string"
+			},
+			"banner": {
+				"type": ["null", "string"]
+			},
+			"splash": {
+				"type": ["null", "string"]
+			},
+			"description": {
+				"type": "string"
+			},
+			"features": {
+				"type": "array",
+				"items": {
+					"type": "string"
+				}
+			},
+			"verification_level": {
+				"type": "integer"
+			},
+			"default_message_notifications": {
+				"type": "integer"
+			},
+			"system_channel_flags": {
+				"type": "integer"
+			},
+			"explicit_content_filter": {
+				"type": "integer"
+			},
+			"public_updates_channel_id": {
+				"type": "string"
+			},
+			"afk_timeout": {
+				"type": "integer"
+			},
+			"afk_channel_id": {
+				"type": "string"
+			},
+			"preferred_locale": {
+				"type": "string"
+			},
+			"premium_progress_bar_enabled": {
+				"type": "boolean"
+			},
+			"region": {
+				"type": "string"
+			},
+			"icon": {
+				"type": ["null", "string"]
+			},
+			"guild_template_code": {
+				"type": "string"
+			},
+			"system_channel_id": {
+				"type": "string"
+			},
+			"rules_channel_id": {
+				"type": "string"
+			}
+		},
+		"additionalProperties": false,
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"GuildUpdateWelcomeScreenSchema": {
+		"type": "object",
+		"properties": {
+			"welcome_channels": {
+				"type": "array",
+				"items": {
+					"type": "object",
+					"properties": {
+						"channel_id": {
+							"type": "string"
+						},
+						"description": {
+							"type": "string"
+						},
+						"emoji_id": {
+							"type": "string"
+						},
+						"emoji_name": {
+							"type": "string"
+						}
+					},
+					"additionalProperties": false,
+					"required": ["channel_id", "description", "emoji_name"]
+				}
+			},
+			"enabled": {
+				"type": "boolean"
+			},
+			"description": {
+				"type": "string"
+			}
+		},
+		"additionalProperties": false,
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"IdentifySchema": {
+		"type": "object",
+		"properties": {
+			"token": {
+				"type": "string"
+			},
+			"properties": {
+				"type": "object",
+				"properties": {
+					"os": {
+						"type": "string"
+					},
+					"os_atch": {
+						"type": "string"
+					},
+					"browser": {
+						"type": "string"
+					},
+					"device": {
+						"type": "string"
+					},
+					"$os": {
+						"type": "string"
+					},
+					"$browser": {
+						"type": "string"
+					},
+					"$device": {
+						"type": "string"
+					},
+					"browser_user_agent": {
+						"type": "string"
+					},
+					"browser_version": {
+						"type": "string"
+					},
+					"os_version": {
+						"type": "string"
+					},
+					"referrer": {
+						"type": "string"
+					},
+					"referring_domain": {
+						"type": "string"
+					},
+					"referrer_current": {
+						"type": "string"
+					},
+					"referring_domain_current": {
+						"type": "string"
+					},
+					"release_channel": {
+						"enum": ["canary", "dev", "ptb", "stable"],
+						"type": "string"
+					},
+					"client_build_number": {
+						"type": "integer"
+					},
+					"client_event_source": {},
+					"client_version": {
+						"type": "string"
+					},
+					"system_locale": {
+						"type": "string"
+					}
+				},
+				"additionalProperties": false
+			},
+			"intents": {
+				"type": "string"
+			},
+			"presence": {
+				"$ref": "#/definitions/ActivitySchema"
+			},
+			"compress": {
+				"type": "boolean"
+			},
+			"large_threshold": {
+				"type": "integer"
+			},
+			"shard": {
+				"type": "array",
+				"items": [
+					{
+						"type": "integer"
+					},
+					{
+						"type": "integer"
+					}
+				],
+				"minItems": 2,
+				"maxItems": 2
+			},
+			"guild_subscriptions": {
+				"type": "boolean"
+			},
+			"capabilities": {
+				"type": "integer"
+			},
+			"client_state": {
+				"type": "object",
+				"properties": {
+					"guild_hashes": {},
+					"highest_last_message_id": {
+						"type": "string"
+					},
+					"read_state_version": {
+						"type": "integer"
+					},
+					"user_guild_settings_version": {
+						"type": "integer"
+					},
+					"user_settings_version": {
+						"type": "integer"
+					}
+				},
+				"additionalProperties": false
+			},
+			"v": {
+				"type": "integer"
+			}
+		},
+		"additionalProperties": false,
+		"required": ["properties", "token"],
+		"definitions": {
+			"ActivitySchema": {
+				"type": "object",
+				"properties": {
+					"afk": {
+						"type": "boolean"
+					},
+					"status": {},
+					"activities": {
+						"type": "array",
+						"items": {}
+					},
+					"since": {
+						"type": "integer"
+					}
+				},
+				"additionalProperties": false,
+				"required": ["afk", "status"]
+			}
+		},
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"InviteCreateSchema": {
+		"type": "object",
+		"properties": {
+			"target_user_id": {
+				"type": "string"
+			},
+			"target_type": {
+				"type": "string"
+			},
+			"validate": {
+				"type": "string"
+			},
+			"max_age": {
+				"type": "integer"
+			},
+			"max_uses": {
+				"type": "integer"
+			},
+			"temporary": {
+				"type": "boolean"
+			},
+			"unique": {
+				"type": "boolean"
+			},
+			"target_user": {
+				"type": "string"
+			},
+			"target_user_type": {
+				"type": "integer"
+			}
+		},
+		"additionalProperties": false,
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"LoginSchema": {
+		"type": "object",
+		"properties": {
+			"login": {
+				"type": "string"
+			},
+			"password": {
+				"type": "string"
+			},
+			"undelete": {
+				"type": "boolean"
+			},
+			"captcha_key": {
+				"type": "string"
+			},
+			"login_source": {
+				"type": "string"
+			},
+			"gift_code_sku_id": {
+				"type": "string"
+			}
+		},
+		"additionalProperties": false,
+		"required": ["login", "password"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"MemberChangeSchema": {
+		"type": "object",
+		"properties": {
+			"roles": {
+				"type": "array",
+				"items": {
+					"type": "string"
+				}
+			}
+		},
+		"additionalProperties": false,
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"MemberNickChangeSchema": {
+		"type": "object",
+		"properties": {
+			"nick": {
+				"type": "string"
+			}
+		},
+		"additionalProperties": false,
+		"required": ["nick"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"MessageAcknowledgeSchema": {
+		"type": "object",
+		"properties": {
+			"manual": {
+				"type": "boolean"
+			},
+			"mention_count": {
+				"type": "integer"
+			}
+		},
+		"additionalProperties": false,
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"MessageCreateSchema": {
+		"type": "object",
+		"properties": {
+			"type": {
+				"type": "integer"
+			},
+			"content": {
+				"type": "string"
+			},
+			"nonce": {
+				"type": "string"
+			},
+			"channel_id": {
+				"type": "string"
+			},
+			"tts": {
+				"type": "boolean"
+			},
+			"flags": {
+				"type": "string"
+			},
+			"embeds": {
+				"type": "array",
+				"items": {}
+			},
+			"embed": {},
+			"allowed_mentions": {
+				"type": "object",
+				"properties": {
+					"parse": {
+						"type": "array",
+						"items": {
+							"type": "string"
+						}
+					},
+					"roles": {
+						"type": "array",
+						"items": {
+							"type": "string"
+						}
+					},
+					"users": {
+						"type": "array",
+						"items": {
+							"type": "string"
+						}
+					},
+					"replied_user": {
+						"type": "boolean"
+					}
+				},
+				"additionalProperties": false
+			},
+			"message_reference": {
+				"type": "object",
+				"properties": {
+					"message_id": {
+						"type": "string"
+					},
+					"channel_id": {
+						"type": "string"
+					},
+					"guild_id": {
+						"type": "string"
+					},
+					"fail_if_not_exists": {
+						"type": "boolean"
+					}
+				},
+				"additionalProperties": false,
+				"required": ["channel_id", "message_id"]
+			},
+			"payload_json": {
+				"type": "string"
+			},
+			"file": {},
+			"attachments": {
+				"description": "TODO: we should create an interface for attachments\nTODO: OpenWAAO<-->attachment-style metadata conversion",
+				"type": "array",
+				"items": {}
+			},
+			"sticker_ids": {
+				"type": "array",
+				"items": {
+					"type": "string"
+				}
+			}
+		},
+		"additionalProperties": false,
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"MfaCodesSchema": {
+		"type": "object",
+		"properties": {
+			"password": {
+				"type": "string"
+			},
+			"regenerate": {
+				"type": "boolean"
+			}
+		},
+		"additionalProperties": false,
+		"required": ["password"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"ModifyGuildStickerSchema": {
+		"type": "object",
+		"properties": {
+			"name": {
+				"minLength": 2,
+				"maxLength": 30,
+				"type": "string"
+			},
+			"description": {
+				"maxLength": 100,
+				"type": "string"
+			},
+			"tags": {
+				"maxLength": 200,
+				"type": "string"
+			}
+		},
+		"additionalProperties": false,
+		"required": ["name", "tags"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"PruneSchema": {
+		"type": "object",
+		"properties": {
+			"days": {
+				"type": "integer"
+			}
+		},
+		"additionalProperties": false,
+		"required": ["days"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"PurgeSchema": {
+		"type": "object",
+		"properties": {
+			"before": {
+				"type": "string"
+			},
+			"after": {
+				"type": "string"
+			}
+		},
+		"additionalProperties": false,
+		"required": ["after", "before"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"RegisterSchema": {
+		"type": "object",
+		"properties": {
+			"username": {
+				"minLength": 2,
+				"maxLength": 32,
+				"type": "string"
+			},
+			"password": {
+				"minLength": 1,
+				"maxLength": 72,
+				"type": "string"
+			},
+			"consent": {
+				"type": "boolean"
+			},
+			"email": {
+				"format": "email",
+				"type": "string"
+			},
+			"fingerprint": {
+				"type": "string"
+			},
+			"invite": {
+				"type": "string"
+			},
+			"date_of_birth": {
+				"type": "string"
+			},
+			"gift_code_sku_id": {
+				"type": "string"
+			},
+			"captcha_key": {
+				"type": "string"
+			},
+			"promotional_email_opt_in": {
+				"type": "boolean"
+			}
+		},
+		"additionalProperties": false,
+		"required": ["consent", "username"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"RelationshipPostSchema": {
+		"type": "object",
+		"properties": {
+			"discriminator": {
+				"type": "string"
+			},
+			"username": {
+				"type": "string"
+			}
+		},
+		"additionalProperties": false,
+		"required": ["discriminator", "username"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"RelationshipPutSchema": {
+		"type": "object",
+		"properties": {
+			"type": {}
+		},
+		"additionalProperties": false,
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"RoleModifySchema": {
+		"type": "object",
+		"properties": {
+			"name": {
+				"type": "string"
+			},
+			"permissions": {
+				"type": "string"
+			},
+			"color": {
+				"type": "integer"
+			},
+			"hoist": {
+				"type": "boolean"
+			},
+			"mentionable": {
+				"type": "boolean"
+			},
+			"position": {
+				"type": "integer"
+			},
+			"icon": {
+				"type": "string"
+			},
+			"unicode_emoji": {
+				"type": "string"
+			}
+		},
+		"additionalProperties": false,
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"RolePositionUpdateSchema": {
+		"type": "array",
+		"items": {
+			"type": "object",
+			"properties": {
+				"id": {
+					"type": "string"
+				},
+				"position": {
+					"type": "integer"
+				}
+			},
+			"additionalProperties": false,
+			"required": ["id", "position"]
+		},
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"TemplateCreateSchema": {
+		"type": "object",
+		"properties": {
+			"name": {
+				"type": "string"
+			},
+			"description": {
+				"type": "string"
+			}
+		},
+		"additionalProperties": false,
+		"required": ["name"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"TemplateModifySchema": {
+		"type": "object",
+		"properties": {
+			"name": {
+				"type": "string"
+			},
+			"description": {
+				"type": "string"
+			}
+		},
+		"additionalProperties": false,
+		"required": ["name"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"TotpDisableSchema": {
+		"type": "object",
+		"properties": {
+			"code": {
+				"type": "string"
+			}
+		},
+		"additionalProperties": false,
+		"required": ["code"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"TotpEnableSchema": {
+		"type": "object",
+		"properties": {
+			"password": {
+				"type": "string"
+			},
+			"code": {
+				"type": "string"
+			},
+			"secret": {
+				"type": "string"
+			}
+		},
+		"additionalProperties": false,
+		"required": ["password"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"TotpSchema": {
+		"type": "object",
+		"properties": {
+			"code": {
+				"type": "string"
+			},
+			"ticket": {
+				"type": "string"
+			},
+			"gift_code_sku_id": {
+				"type": ["null", "string"]
+			},
+			"login_source": {
+				"type": ["null", "string"]
+			}
+		},
+		"additionalProperties": false,
+		"required": ["code", "ticket"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"UserModifySchema": {
+		"type": "object",
+		"properties": {
+			"username": {
+				"minLength": 1,
+				"maxLength": 100,
+				"type": "string"
+			},
+			"discriminator": {
+				"type": "string"
+			},
+			"avatar": {
+				"type": ["null", "string"]
+			},
+			"bio": {
+				"maxLength": 1024,
+				"type": "string"
+			},
+			"accent_color": {
+				"type": "integer"
+			},
+			"banner": {
+				"type": ["null", "string"]
+			},
+			"password": {
+				"type": "string"
+			},
+			"new_password": {
+				"type": "string"
+			},
+			"code": {
+				"type": "string"
+			}
+		},
+		"additionalProperties": false,
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"UserSettingsSchema": {
+		"type": "object",
+		"additionalProperties": false,
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"VanityUrlSchema": {
+		"type": "object",
+		"properties": {
+			"code": {
+				"minLength": 1,
+				"maxLength": 20,
+				"type": "string"
+			}
+		},
+		"additionalProperties": false,
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"VoiceStateUpdateSchema": {
+		"type": "object",
+		"properties": {
+			"channel_id": {
+				"type": "string"
+			},
+			"guild_id": {
+				"type": "string"
+			},
+			"suppress": {
+				"type": "boolean"
+			},
+			"request_to_speak_timestamp": {
+				"type": "string",
+				"format": "date-time"
+			},
+			"self_mute": {
+				"type": "boolean"
+			},
+			"self_deaf": {
+				"type": "boolean"
+			},
+			"self_video": {
+				"type": "boolean"
+			}
+		},
+		"additionalProperties": false,
+		"required": ["channel_id"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"WebhookCreateSchema": {
+		"type": "object",
+		"properties": {
+			"name": {
+				"maxLength": 80,
+				"type": "string"
+			},
+			"avatar": {
+				"type": "string"
+			}
+		},
+		"additionalProperties": false,
+		"required": ["name"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"WidgetModifySchema": {
+		"type": "object",
+		"properties": {
+			"enabled": {
+				"type": "boolean"
+			},
+			"channel_id": {
+				"type": "string"
+			}
+		},
+		"additionalProperties": false,
+		"required": ["channel_id", "enabled"],
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	},
+	"ChannelModifySchema": {
+		"type": "object",
+		"properties": {
+			"name": {
+				"maxLength": 100,
+				"type": "string"
+			},
+			"type": {
+				"enum": [0, 1, 10, 11, 12, 13, 14, 15, 2, 255, 3, 33, 34, 35, 4, 5, 6, 64, 7, 8, 9],
+				"type": "number"
+			},
+			"topic": {
+				"type": "string"
+			},
+			"icon": {
+				"type": ["null", "string"]
+			},
+			"bitrate": {
+				"type": "integer"
+			},
+			"user_limit": {
+				"type": "integer"
+			},
+			"rate_limit_per_user": {
+				"type": "integer"
+			},
+			"position": {
+				"type": "integer"
+			},
+			"permission_overwrites": {
+				"type": "array",
+				"items": {
+					"type": "object",
+					"properties": {
+						"id": {
+							"type": "string"
+						},
+						"type": {
+							"$ref": "#/definitions/ChannelPermissionOverwriteType"
+						},
+						"allow": {
+							"type": "string"
+						},
+						"deny": {
+							"type": "string"
+						}
+					},
+					"additionalProperties": false,
+					"required": ["allow", "deny", "id", "type"]
+				}
+			},
+			"parent_id": {
+				"type": "string"
+			},
+			"id": {
+				"type": "string"
+			},
+			"nsfw": {
+				"type": "boolean"
+			},
+			"rtc_region": {
+				"type": "string"
+			},
+			"default_auto_archive_duration": {
+				"type": "integer"
+			},
+			"flags": {
+				"type": "integer"
+			},
+			"default_thread_rate_limit_per_user": {
+				"type": "integer"
+			}
+		},
+		"additionalProperties": false,
+		"definitions": {
+			"ChannelPermissionOverwriteType": {
+				"enum": [0, 1, 2],
+				"type": "number"
+			}
+		},
+		"$schema": "http://json-schema.org/draft-07/schema#"
+	}
+}
diff --git a/assets/user.css b/assets/user.css
index a7e5c4f3..652306af 100644
--- a/assets/user.css
+++ b/assets/user.css
@@ -1 +1 @@
-/* Your custom CSS goes here, enjoy! */
\ No newline at end of file
+/* Your custom CSS goes here, enjoy! */
diff --git a/build.json.default b/build.json.default
new file mode 100644
index 00000000..cac0a850
--- /dev/null
+++ b/build.json.default
@@ -0,0 +1,16 @@
+{
+	"compiler": "tsc",
+	"verbose": true,
+	"writeBuildLog": true,
+	"writeAnsiBuildLog": true,
+	"logErrors": true,
+	"tsc": {
+		"prettyErrors": true
+	},
+	"clean": true,
+	"quiet": false,
+	"steps": {
+		"pre": ["clean"],
+		"post": ["remap_imports"]
+	}
+}
diff --git a/docker-compose.cfg.yml b/docker-compose.cfg.yml
index 18a7031d..e7a4b879 100644
--- a/docker-compose.cfg.yml
+++ b/docker-compose.cfg.yml
@@ -1,6 +1,5 @@
-version: '3.9'
+version: "3.9"
 
 services:
-
-  fosscord:
-    entrypoint: [ "npm", "run", "setup" ]
+    fosscord:
+        entrypoint: ["npm", "run", "setup"]
diff --git a/docker-compose.yml b/docker-compose.yml
index 4dc1ee41..8da4010c 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,25 +1,24 @@
-version: '3.9'
+version: "3.9"
 
 services:
-
-  fosscord:
-    container_name: fosscord
-    image: fosscord
-    restart: on-failure:5
-    build: .
-    ports:
-      - '3001-3005:3001-3005'
-    volumes:
-      - ./:/srv/fosscord-server/
-    environment:
-      THREADS: ${THREADS:-1}
-      HTTP_PORT: 3001
-      WS_PORT: 3002
-      CDN_PORT: 3003
-      RTC_PORT: 3004
-      ADMIN_PORT: 3005
+    fosscord:
+        container_name: fosscord
+        image: fosscord
+        restart: on-failure:5
+        build: .
+        ports:
+            - "3001-3005:3001-3005"
+        volumes:
+            - ./:/srv/fosscord-server/
+        environment:
+            THREADS: ${THREADS:-1}
+            HTTP_PORT: 3001
+            WS_PORT: 3002
+            CDN_PORT: 3003
+            RTC_PORT: 3004
+            ADMIN_PORT: 3005
 
 networks:
-  default:
-    name: fosscord
-    driver: bridge
+    default:
+        name: fosscord
+        driver: bridge
diff --git a/env-vars.md b/env-vars.md
index 6c56c184..c66a7a9b 100644
--- a/env-vars.md
+++ b/env-vars.md
@@ -1,18 +1,18 @@
 #Fosscord Environment Variables:
 
-|NAME|VALUE|DESCRIPTION|
-|----|-----|-----------|
-|LOG\_REQUESTS | ports to include, or exclude (-) | logs requests |
-|PORT|number|sets port number to listen on|
-|CDN|string|CDN address|
-|GATEWAY|string|Gateway address|
-|NODE\_ENV|production/development|sets node environment|
-|DATABASE|database url|points to what database to use|
-|EVENT\_TRANSMISSION|string|event transmission type|
-|STORAGE\_PROVIDER|s3/file|How to store files for CDN|
-|STORAGE\_LOCATION|path|Directory to store files in|
-|STORAGE\_BUCKET|s3 bucket name|S3 bucket name|
-|DB\_UNSAFE|any|Ignores migrations for database, enabled if defined|
-|DB\_VERBOSE|any|Log database queries, enabled if defined|
-|DB\_MIGRATE|any|Exit fosscord after connecting to and migrating database, used internally|
-|LOG\_INVALID\_BODY|any|Log request method, path and body if invalid|
+| NAME               | VALUE                            | DESCRIPTION                                                               |
+| ------------------ | -------------------------------- | ------------------------------------------------------------------------- |
+| LOG_REQUESTS       | ports to include, or exclude (-) | logs requests                                                             |
+| PORT               | number                           | sets port number to listen on                                             |
+| CDN                | string                           | CDN address                                                               |
+| GATEWAY            | string                           | Gateway address                                                           |
+| NODE_ENV           | production/development           | sets node environment                                                     |
+| DATABASE           | database url                     | points to what database to use                                            |
+| EVENT_TRANSMISSION | string                           | event transmission type                                                   |
+| STORAGE_PROVIDER   | s3/file                          | How to store files for CDN                                                |
+| STORAGE_LOCATION   | path                             | Directory to store files in                                               |
+| STORAGE_BUCKET     | s3 bucket name                   | S3 bucket name                                                            |
+| DB_UNSAFE          | any                              | Ignores migrations for database, enabled if defined                       |
+| DB_VERBOSE         | any                              | Log database queries, enabled if defined                                  |
+| DB_MIGRATE         | any                              | Exit fosscord after connecting to and migrating database, used internally |
+| LOG_INVALID_BODY   | any                              | Log request method, path and body if invalid                              |
diff --git a/fosscord-server.code-workspace b/fosscord-server.code-workspace
index f2df1e9e..56450f85 100644
--- a/fosscord-server.code-workspace
+++ b/fosscord-server.code-workspace
@@ -17,5 +17,22 @@
 		"files.exclude": {
 			"*.ansi": true,
 		}
+	},
+	"launch": {
+		"version": "0.2.0",
+		"configurations": [
+			{
+				"command": "npm run start:bundle:vscode-dbg",
+				"name": "Run Fosscord with debugger",
+				"request": "launch",
+				"type": "node-terminal"
+			},
+			{
+				"command": "kitty npm run start:bundle:vscode-dbg",
+				"name": "Run Fosscord with debugger (kitty)",
+				"request": "launch",
+				"type": "node-terminal"
+			}
+		]
 	}
-}
\ No newline at end of file
+}
diff --git a/package.json b/package.json
index a6d3ed0a..44be6b7f 100644
--- a/package.json
+++ b/package.json
@@ -4,18 +4,18 @@
 	"description": "",
 	"main": "src/start.js",
 	"scripts": {
-		"setup": "npm install --omit optional && ts-patch install -s && patch-package && npm run build",
+		"setup": "npm install --omit optional && patch-package && npm run build",
+		"build": "node scripts/build_new.js",
+		"start": "npm run build && npm run start:bundle",
+		"start:bundle": "node --enable-source-maps dist/start.js",
+		"start:bundle:dbg": "node --enable-source-maps --inspect dist/start.js",
+		"start:bundle:vscode-dbg": "npm run build && node --enable-source-maps --inspect dist/start.js",
 		"depclean": "node scripts/depclean.js",
 		"depcheck": "node scripts/depcheck.js",
-		"build": "node scripts/build.js",
-		"postinstall": "patch-package",
+		"tsnode": "npx ts-node --transpile-only -P tsnode.tsconfig.json src/start.ts",
 		"genschemas": "node scripts/generate_schemas.js",
-		"start": "node scripts/build.js && node --enable-source-maps dist/start.js",
-		"start:bundle": "node --enable-source-maps dist/start.js",
-		"start:bundle:dbg": "node --enable-source-maps --inspect dist/start.js",
-		"start:bundle:vscode-dbg": "npm run build clean logerrors pretty-errors && node --enable-source-maps --inspect dist/start.js",
 		"migrate": "cd ../util/ && npm i && node --require ts-node/register node_modules/typeorm/cli.js -f ../util/ormconfig.json migration:run",
-		"tsnode": "npx ts-node --transpile-only -P tsnode.tsconfig.json src/start.ts"
+		"postinstall": "patch-package && npx --yes node-git-hooks"
 	},
 	"repository": {
 		"type": "git",
@@ -28,12 +28,16 @@
 		"url": "https://github.com/fosscord/fosscord-server/issues"
 	},
 	"homepage": "https://fosscord.com",
+	"imports": {
+		"#*": "./dist/*/index.js"
+	},
 	"devDependencies": {
 		"@babel/core": "^7.18.9",
 		"@babel/preset-env": "^7.18.9",
 		"@babel/preset-typescript": "^7.15.0",
 		"@types/amqplib": "^0.8.1",
 		"@types/bcrypt": "^5.0.0",
+		"@types/bcryptjs": "^2.4.2",
 		"@types/body-parser": "^1.19.0",
 		"@types/dotenv": "^8.2.0",
 		"@types/express": "^4.17.12",
@@ -42,30 +46,29 @@
 		"@types/morgan": "^1.9.3",
 		"@types/multer": "^1.4.7",
 		"@types/node": "^18.7.3",
+		"@types/node-fetch": "^2.6.2",
 		"@types/node-os-utils": "^1.3.0",
 		"@types/ws": "^8.5.3",
 		"jest": "^28.1.3",
 		"jest-expect-message": "^1.0.2",
+		"prettier-plugin-organize-imports": "^3.0.3",
 		"supertest": "^6.1.6",
 		"ts-node": "^10.2.1",
 		"ts-node-dev": "^2.0.0",
-		"ts-patch": "^2.0.2",
 		"typescript": "^4.2.3",
 		"typescript-json-schema": "^0.54.0"
 	},
 	"dependencies": {
 		"@aws-sdk/client-s3": "^3.137.0",
 		"@babel/preset-typescript": "^7.15.0",
-		"@ovos-media/ts-transform-paths": "^1.7.18-1",
 		"@sentry/node": "^7.7.0",
 		"@sentry/tracing": "^7.7.0",
-		"@types/node-fetch": "^2.6.2",
 		"ajv": "^8.6.2",
 		"ajv-formats": "^2.1.1",
 		"amqplib": "^0.10.1",
 		"bcrypt": "^5.0.1",
+		"bcryptjs": "^2.4.3",
 		"body-parser": "^1.19.0",
-		"canvas": "^2.9.3",
 		"cheerio": "^1.0.0-rc.10",
 		"dotenv": "^16.0.1",
 		"exif-be-gone": "^1.3.1",
@@ -93,6 +96,7 @@
 		"ws": "^8.8.1"
 	},
 	"optionalDependencies": {
+		"canvas": "^2.9.3",
 		"mysql2": "^2.3.3",
 		"pg": "^8.7.3",
 		"sqlite3": "^5.0.11"
diff --git a/scripts/benchmark.js b/scripts/benchmark.js
index e7435191..53db92c5 100644
--- a/scripts/benchmark.js
+++ b/scripts/benchmark.js
@@ -3,9 +3,7 @@ const Models = require("../dist/entities");
 const { PrimaryColumn } = require("typeorm");
 
 function shouldIncludeEntity(name) {
-	return ![Models.BaseClassWithoutId, PrimaryColumn, Models.BaseClass, Models.PrimaryGeneratedColumn]
-		.map((x) => x?.name)
-		.includes(name);
+	return ![Models.BaseClassWithoutId, PrimaryColumn, Models.BaseClass, Models.PrimaryGeneratedColumn].map((x) => x?.name).includes(name);
 }
 
 async function main() {
@@ -14,7 +12,7 @@ async function main() {
 		type: "sqlite",
 		database: ":memory:",
 		entities: Object.values(Models).filter((x) => x.constructor.name == "Function" && shouldIncludeEntity(x.name)),
-		synchronize: true,
+		synchronize: true
 	});
 	await db.initialize();
 	console.log("Initialized database");
diff --git a/scripts/benchmark/connections.js b/scripts/benchmark/connections.js
index 661548c3..f74d0c6d 100644
--- a/scripts/benchmark/connections.js
+++ b/scripts/benchmark/connections.js
@@ -8,7 +8,7 @@ let cores = 1;
 try {
 	cores = Number(process.env.THREADS) || os.cpus().length;
 } catch {
-	console.log("[Bundle] Failed to get thread count! Using 1...")
+	console.log("[Bundle] Failed to get thread count! Using 1...");
 }
 
 if (!token) {
@@ -46,8 +46,8 @@ function connect() {
 						op: 2,
 						d: {
 							token,
-							properties: {},
-						},
+							properties: {}
+						}
 					})
 				);
 
diff --git a/scripts/benchmark/users.js b/scripts/benchmark/users.js
index bce67bf4..415d6d8b 100644
--- a/scripts/benchmark/users.js
+++ b/scripts/benchmark/users.js
@@ -14,9 +14,9 @@ async function main() {
 				consent: true,
 				date_of_birth: "2000-01-01",
 				gift_code_sku_id: null,
-				captcha_key: null,
+				captcha_key: null
 			}),
-			headers: { "content-type": "application/json" },
+			headers: { "content-type": "application/json" }
 		});
 		console.log(i);
 	}
diff --git a/scripts/build.js b/scripts/build.js
index 2c0d7328..f618100c 100644
--- a/scripts/build.js
+++ b/scripts/build.js
@@ -2,20 +2,22 @@ const { execSync } = require("child_process");
 const path = require("path");
 const fs = require("fs");
 const { argv, stdout, exit } = require("process");
-const {  execIn, parts } = require('./utils');
+const { execIn, parts, getDirs, walk, sanitizeVarName } = require("./utils");
 
-if(argv.includes("help")) {
+if (argv.includes("help")) {
 	console.log(`Fosscord build script help:
 Arguments:
   clean			Cleans up previous builds
   verbose		Enable verbose logging
   logerrors		Log build errors to console
   pretty-errors		Pretty-print build errors
-  silent		No output to console or files.`);
+  silent		No output to console or files.
+  propagate-err	Exit script with error code if build fails.`);
 	exit(0);
 }
 
-let steps = 1, i = 0;
+let steps = 5,
+	i = 0;
 if (argv.includes("clean")) steps++;
 
 const verbose = argv.includes("verbose") || argv.includes("v");
@@ -23,7 +25,7 @@ const logerr = argv.includes("logerrors");
 const pretty = argv.includes("pretty-errors");
 const silent = argv.includes("silent");
 
-if(silent) console.error = console.log = function(){}
+if (silent) console.error = console.log = function () {};
 
 if (argv.includes("clean")) {
 	console.log(`[${++i}/${steps}] Cleaning...`);
@@ -36,37 +38,79 @@ if (argv.includes("clean")) {
 
 console.log(`[${++i}/${steps}] Compiling src files ...`);
 
-let buildFlags = ''
-if(pretty) buildFlags += '--pretty '
+let buildFlags = "";
+if (pretty) buildFlags += "--pretty ";
 
-try {
-	execSync(
-		'node "' +
-			path.join(__dirname, "..", "node_modules", "typescript", "lib", "tsc.js") +
-			'" -p "' +
-			path.join(__dirname, "..") +
-			'" ' + buildFlags,
-		{
-			cwd: path.join(__dirname, ".."),
-			shell: true,
-			env: process.env,
-			encoding: "utf8"
-		}
-	)
-} catch (error) {
-	if(verbose || logerr) {
-		error.stdout.split(/\r?\n/).forEach((line) => {
-			let _line = line.replace('dist/','',1);
-			if(!pretty && _line.includes('.ts(')) {
-				//reformat file path for easy jumping
-				_line = _line.replace('(',':',1).replace(',',':',1).replace(')','',1)
-			}
-			console.error(_line);
-		})
+console.log(`[${++i}/${steps}] Building plugin index...`);
+let pluginDir = path.join(__dirname, "..", "src", "plugins");
+let output = 'import { Plugin } from "util/plugin";\n';
+
+const dirs = fs.readdirSync(pluginDir).filter((x) => {
+	try {
+		fs.readdirSync(path.join(pluginDir, x));
+		return true;
+	} catch (e) {
+		return false;
 	}
-	console.error(`Build failed! Please check build.log for info!`);
-	if(!silent){
-		if(pretty) fs.writeFileSync("build.log.ansi",  error.stdout);
-		fs.writeFileSync("build.log",  error.stdout.replaceAll(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, ''));
+});
+dirs.forEach((x) => {
+	let pluginManifest = require(path.join(pluginDir, x, "plugin.json"));
+	output += `import * as ${sanitizeVarName(x)} from "./${x}/${pluginManifest.mainClass}";\n`;
+});
+output += `\nexport const PluginIndex: any = {\n`;
+dirs.forEach((x) => {
+	output += `    "${x}": new ${sanitizeVarName(x)}.default(),\n`; //ctor test: '${path.resolve(path.join(pluginDir, x))}', require('./${x}/plugin.json')
+});
+output += `};`;
+
+fs.writeFileSync(path.join(__dirname, "..", "src", "plugins", "PluginIndex.ts"), output);
+
+if (!argv.includes("copyonly")) {
+	console.log(`[${++i}/${steps}] Compiling source code...`);
+
+	let buildFlags = "";
+	if (pretty) buildFlags += "--pretty ";
+
+	try {
+		execSync(
+			'node "' +
+				path.join(__dirname, "..", "node_modules", "typescript", "lib", "tsc.js") +
+				'" -p "' +
+				path.join(__dirname, "..") +
+				'" ' +
+				buildFlags,
+			{
+				cwd: path.join(__dirname, ".."),
+				shell: true,
+				env: process.env,
+				encoding: "utf8"
+			}
+		);
+	} catch (error) {
+		if (verbose || logerr) {
+			error.stdout.split(/\r?\n/).forEach((line) => {
+				let _line = line.replace("dist/", "", 1);
+				if (!pretty && _line.includes(".ts(")) {
+					//reformat file path for easy jumping
+					_line = _line.replace("(", ":", 1).replace(",", ":", 1).replace(")", "", 1);
+				}
+				console.error(_line);
+			});
+		}
+		console.error(`Build failed! Please check build.log for info!`);
+		if (!silent) {
+			if (pretty) fs.writeFileSync("build.log.ansi", error.stdout);
+			fs.writeFileSync(
+				"build.log",
+				error.stdout.replaceAll(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, "")
+			);
+		}
+		throw error;
 	}
-}
\ No newline at end of file
+}
+
+console.log(`[${++i}/${steps}] Copying plugin data...`);
+let pluginFiles = walk(pluginDir).filter((x) => !x.endsWith(".ts"));
+pluginFiles.forEach((x) => {
+	fs.copyFileSync(x, x.replace("src", "dist"));
+});
diff --git a/scripts/build/clean.js b/scripts/build/clean.js
new file mode 100644
index 00000000..92ec6d77
--- /dev/null
+++ b/scripts/build/clean.js
@@ -0,0 +1,18 @@
+const { execSync } = require("child_process");
+const path = require("path");
+const fs = require("fs");
+const { argv, stdout, exit } = require("process");
+const { execIn, parts, getDirs, walk, sanitizeVarName } = require("../utils");
+
+module.exports = function (config) {
+	if (fs.existsSync(config.buildLog)) fs.rmSync(config.buildLog);
+	if (fs.existsSync(config.buildLogAnsi)) fs.rmSync(config.buildLogAnsi);
+
+	if (config.clean) {
+		console.log(`==> Cleaning...`);
+		if (fs.existsSync(config.distDir)) {
+			fs.rmSync(config.distDir, { recursive: true });
+			if (config.verbose) console.log(`Deleted ${path.resolve(config.distDir)}!`);
+		}
+	}
+};
diff --git a/scripts/build/compile_tsc.js b/scripts/build/compile_tsc.js
new file mode 100644
index 00000000..179707a3
--- /dev/null
+++ b/scripts/build/compile_tsc.js
@@ -0,0 +1,48 @@
+const { execSync } = require("child_process");
+const path = require("path");
+const fs = require("fs");
+const { argv, stdout, exit } = require("process");
+const { execIn, parts, getDirs, walk, sanitizeVarName } = require("../utils");
+
+module.exports = function (config) {
+	console.log("==> Compiling source with tsc...");
+	let buildFlags = "";
+	if (config.pretty) buildFlags += "--pretty ";
+
+	try {
+		execSync(
+			'node "' +
+				path.join(config.rootDir, "node_modules", "typescript", "lib", "tsc.js") +
+				'" -p "' +
+				path.join(config.rootDir) +
+				'" ' +
+				buildFlags,
+			{
+				cwd: path.join(config.rootDir),
+				shell: true,
+				env: process.env,
+				encoding: "utf8"
+			}
+		);
+	} catch (error) {
+		if (config.verbose || config.logerr) {
+			error.stdout.split(/\r?\n/).forEach((line) => {
+				let _line = line.replace("dist/", "", 1);
+				if (!config.pretty && _line.includes(".ts(")) {
+					//reformat file path for easy jumping
+					_line = _line.replace("(", ":", 1).replace(",", ":", 1).replace(")", "", 1);
+				}
+				console.error(_line);
+			});
+		}
+		console.error(`Build failed! Please check build.log for info!`);
+		if (!config.silent) {
+			if (config.pretty) fs.writeFileSync(path.join(config.rootDir, "build.log.ansi"), error.stdout);
+			fs.writeFileSync(
+				path.join(config.rootDir, "build.log"),
+				error.stdout.replaceAll(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, "")
+			);
+		}
+		throw error;
+	}
+};
diff --git a/scripts/build/plugin_prepare.js b/scripts/build/plugin_prepare.js
new file mode 100644
index 00000000..247ad22d
--- /dev/null
+++ b/scripts/build/plugin_prepare.js
@@ -0,0 +1,31 @@
+const { execSync } = require("child_process");
+const path = require("path");
+const fs = require("fs");
+const { argv, stdout, exit } = require("process");
+const { execIn, parts, getDirs, walk, sanitizeVarName } = require("../utils");
+
+module.exports = function (config) {
+	console.log(`==> Building plugin index...`);
+	let output = 'import { Plugin } from "util/plugin";\n';
+
+	const dirs = fs.readdirSync(config.pluginDir).filter((x) => {
+		try {
+			fs.readdirSync(path.join(config.pluginDir, x));
+			return true;
+		} catch (e) {
+			return false;
+		}
+	});
+	dirs.forEach((x) => {
+		let pluginManifest = require(path.join(config.pluginDir, x, "plugin.json"));
+		console.log(`  ==> Registering plugin: ${pluginManifest.name} (${pluginManifest.id}) by ${pluginManifest.authors}`);
+		output += `import * as ${sanitizeVarName(x)} from "./${x}/${pluginManifest.mainClass}";\n`;
+	});
+	output += `\nexport const PluginIndex: any = {\n`;
+	dirs.forEach((x) => {
+		output += `    "${x}": new ${sanitizeVarName(x)}.default(),\n`; //ctor test: '${path.resolve(path.join(pluginDir, x))}', require('./${x}/plugin.json')
+	});
+	output += `};`;
+
+	fs.writeFileSync(path.join(config.pluginDir, "PluginIndex.ts"), output);
+};
diff --git a/scripts/build/plugin_resources.js b/scripts/build/plugin_resources.js
new file mode 100644
index 00000000..5b4b97f2
--- /dev/null
+++ b/scripts/build/plugin_resources.js
@@ -0,0 +1,13 @@
+const { execSync } = require("child_process");
+const path = require("path");
+const fs = require("fs");
+const { argv, stdout, exit } = require("process");
+const { execIn, parts, getDirs, walk, sanitizeVarName } = require("../utils");
+
+module.exports = function (config) {
+	console.log(`==> Copying all plugin resources...`);
+	let pluginFiles = walk(config.pluginDir).filter((x) => !x.endsWith(".ts"));
+	pluginFiles.forEach((x) => {
+		fs.copyFileSync(x, x.replace("src", "dist"));
+	});
+};
diff --git a/scripts/build/remap_imports.js b/scripts/build/remap_imports.js
new file mode 100644
index 00000000..cdcd571a
--- /dev/null
+++ b/scripts/build/remap_imports.js
@@ -0,0 +1,15 @@
+const { execSync } = require("child_process");
+const path = require("path");
+const fs = require("fs");
+const { argv, stdout, exit } = require("process");
+const { execIn, parts, getDirs, walk, sanitizeVarName } = require("../utils");
+
+module.exports = function (config) {
+	console.log(`==> Remapping module imports...`);
+	let files = walk(config.distDir).filter((x) => x.endsWith(".js"));
+	files.forEach((x) => {
+		let fc = fs.readFileSync(x).toString();
+		fc = fc.replaceAll("@fosscord/", "#");
+		fs.writeFileSync(x, fc);
+	});
+};
diff --git a/scripts/build_new.js b/scripts/build_new.js
new file mode 100644
index 00000000..6a56e7f7
--- /dev/null
+++ b/scripts/build_new.js
@@ -0,0 +1,31 @@
+const { execSync } = require("child_process");
+const path = require("path");
+const fs = require("fs");
+const { argv, stdout, exit } = require("process");
+const { execIn, parts, getDirs, walk, sanitizeVarName } = require("./utils");
+
+//file paths
+const rootDir = path.join(__dirname, "..");
+const srcDir = path.join(rootDir, "src");
+const distDir = path.join(rootDir, "dist");
+const scriptsDir = path.join(rootDir, "scripts");
+const configPath = path.join(rootDir, "build.json");
+const buildLog = path.join(rootDir, "build.log");
+const buildLogAnsi = path.join(rootDir, "build.log.ansi");
+const pluginDir = path.join(srcDir, "plugins");
+
+//more, dont export
+const buildStepDir = path.join(scriptsDir, "build");
+
+if (!fs.existsSync(configPath)) {
+	if (!fs.existsSync(path.join(configPath + ".default"))) {
+		console.log("build.json.default not found! Exiting!");
+		exit(1);
+	}
+	fs.copyFileSync(configPath + ".default", configPath);
+}
+let config = { rootDir, srcDir, distDir, configPath, buildLog, buildLogAnsi, pluginDir, ...require(configPath) };
+
+config.steps.pre.forEach((step) => require(path.join(buildStepDir, step))(config));
+require(path.join(buildStepDir, "compile_" + config.compiler))(config);
+config.steps.post.forEach((step) => require(path.join(buildStepDir, step))(config));
diff --git a/scripts/code_quality.js b/scripts/code_quality.js
new file mode 100644
index 00000000..aca01d24
--- /dev/null
+++ b/scripts/code_quality.js
@@ -0,0 +1,75 @@
+const path = require("path");
+const fs = require("fs").promises;
+const { execIn, getLines, walk, projectRoot } = require("./utils");
+
+let printTodos = process.argv.includes("TODOS");
+
+let root = path.resolve(path.join(__dirname, "..", "src"));
+let files = walk(root);
+let _files = [];
+let errors = 0,
+	warnings = 0,
+	todos = 0;
+
+Promise.all(files.map(getFile)).then((f) => {
+	Promise.all(Object.keys(_files).map(checkFile));
+	console.log(`\n${errors} errors, ${warnings} warnings, ${todos} TODOs.`);
+
+	let loc = 0;
+	Object.values(_files).forEach((x) => {
+		loc += x.length;
+	});
+	console.log("\nStats:\n");
+	console.log(`Lines of code: ${loc} lines in ${Object.values(_files).length} files.`);
+
+	debugger;
+});
+
+async function getFile(name) {
+	let contents = (await fs.readFile(name)).toString().split("\n");
+	_files[name] = contents;
+}
+
+async function checkFile(x) {
+	_files[x].forEach((line) => scanLine(x, line));
+}
+
+function log(file, line, msg) {
+	let lineNum = _files[file].indexOf(line) + 1;
+	console.log(msg, "File:", file.replace(root + "/", "") + ":" + lineNum);
+}
+
+function scanLine(x, line) {
+	if (/import/.test(line)) {
+		if (/import {?.*}? from '.*'/.test(line)) {
+			log(x, line, `[WARN] Inconsistent import syntax, please use double quotes!`);
+			warnings++;
+		}
+	} else {
+		if (line.trim().endsWith("TODO:")) {
+			log(x, line, `[ERRO] Empty TODO!`);
+			errors++;
+		} else if (/\/\/\s{0,3}TODO:/.test(line)) {
+			if (printTodos) log(x, line, `[TODO] Found a TODO: ${line.split("TODO:")[1].trim()}.`);
+			todos++;
+		}
+		if (/(:|=)/.test(line)) {
+			if (/(:|=) {2,}/.test(line)) {
+				log(x, line, `[WARN] Multiple spaces in assignment!`);
+				warnings++;
+			}
+			if (/(:|=)\t'/.test(line)) {
+				log(x, line, `[WARN] Tab in assignment!`);
+				warnings++;
+			}
+			if (/(:|=)\w'/.test(line)) {
+				log(x, line, `[WARN] Missing space in assignment!`);
+				warnings++;
+			}
+			if (/(:|=) undefined/.test(line) && !/(:|=){2,} undefined/.test(line)) {
+				log(x, line, `[WARN] Use of undefined!`);
+				warnings++;
+			}
+		}
+	}
+}
diff --git a/scripts/depcheck.js b/scripts/depcheck.js
index 08df156c..44ac2bb6 100644
--- a/scripts/depcheck.js
+++ b/scripts/depcheck.js
@@ -9,22 +9,22 @@ const { execIn, getLines } = require("./utils");
 let npmi_extra_flags = "";
 
 const resolveminor = argv.includes("resolveminor");
-if(argv.includes("nobuild")) npmi_extra_flags += "--ignore-scripts ";
+if (argv.includes("nobuild")) npmi_extra_flags += "--ignore-scripts ";
 
 parts.forEach((part) => {
 	let partDir = path.join(__dirname, "..", "..", part);
 	let distDir = path.join(partDir, "dist");
 	console.log(`Checking updates for ${part} (${partDir})`);
-	if(part == "bundle") {
-		execIn(`npm run syncdeps`, partDir)
+	if (part == "bundle") {
+		execIn(`npm run syncdeps`, partDir);
 	}
-    if(resolveminor) {
-        fs.rmSync(path.join(partDir, "node_modules"), {
+	if (resolveminor) {
+		fs.rmSync(path.join(partDir, "node_modules"), {
 			recursive: true,
-			force: true,
+			force: true
 		});
-        execIn(`npm i --save --no-fund --no-audit --no-package-lock ${npmi_extra_flags}`, partDir)
-    }
+		execIn(`npm i --save --no-fund --no-audit --no-package-lock ${npmi_extra_flags}`, partDir);
+	}
 	let x = [
 		[
 			"pkg",
@@ -33,24 +33,18 @@ parts.forEach((part) => {
 				wanted: "2.0",
 				latest: "2.0",
 				dependent: "cdn",
-				location: "/usr/src/fosscord/bundle/node_packages/pkg",
-			},
-		],
+				location: "/usr/src/fosscord/bundle/node_packages/pkg"
+			}
+		]
 	];
-	x = Object.entries(
-		JSON.parse(execIn("npm outdated --json", partDir))
-	);
+	x = Object.entries(JSON.parse(execIn("npm outdated --json", partDir)));
 	x.forEach((a) => {
-        let pkgname = a[0];
-        let pkginfo = a[1];
-        if(!pkginfo.current)
-            console.log(`MISSING ${pkgname}: ${pkginfo.current} -> ${pkginfo.wanted} (latest: ${pkginfo.latest})`);
-        else if(pkginfo.latest != pkginfo.wanted){
-            if(pkginfo.current != pkginfo.wanted) 
-                console.log(`MINOR   ${pkgname}: ${pkginfo.current} -> ${pkginfo.wanted}`);
-		    console.log(`MAJOR   ${pkgname}: ${pkginfo.current} -> ${pkginfo.latest}`);
-        }
-        else
-            console.log(`MINOR   ${pkgname}: ${pkginfo.current} -> ${pkginfo.wanted}`);
+		let pkgname = a[0];
+		let pkginfo = a[1];
+		if (!pkginfo.current) console.log(`MISSING ${pkgname}: ${pkginfo.current} -> ${pkginfo.wanted} (latest: ${pkginfo.latest})`);
+		else if (pkginfo.latest != pkginfo.wanted) {
+			if (pkginfo.current != pkginfo.wanted) console.log(`MINOR   ${pkgname}: ${pkginfo.current} -> ${pkginfo.wanted}`);
+			console.log(`MAJOR   ${pkgname}: ${pkginfo.current} -> ${pkginfo.latest}`);
+		} else console.log(`MINOR   ${pkgname}: ${pkginfo.current} -> ${pkginfo.wanted}`);
 	});
 });
diff --git a/scripts/depclean.js b/scripts/depclean.js
index 333f5aa0..5a402331 100644
--- a/scripts/depclean.js
+++ b/scripts/depclean.js
@@ -3,8 +3,7 @@ const fs = require("fs");
 const { env } = require("process");
 const { execSync } = require("child_process");
 const { argv, stdout, exit } = require("process");
-
-const { execIn, getLines } = require('./utils');
+const { execIn, getLines } = require("./utils");
 
 const bundleRequired = ["@ovos-media/ts-transform-paths"];
 const removeModules = argv.includes("cleanup");
@@ -15,13 +14,11 @@ execIn("npm i", path.join(__dirname, ".."));
 let partDir = path.join(__dirname, "..");
 let distDir = path.join(partDir, "dist");
 let start = 0;
-start = getLines(
-	execIn("npm ls --parseable --package-lock-only -a", partDir)
-);
+start = getLines(execIn("npm ls --parseable --package-lock-only -a", partDir));
 if (fs.existsSync(distDir))
 	fs.rmSync(distDir, {
 		recursive: true,
-		force: true,
+		force: true
 	});
 let x = {
 	dependencies: [],
@@ -29,17 +26,13 @@ let x = {
 	invalidDirs: [],
 	invalidFiles: [],
 	missing: [],
-	using: [],
+	using: []
 };
 let dcproc = execIn("npx depcheck --json", partDir);
-if(dcproc.stdout) x = JSON.parse(dcproc.stdout);
+if (dcproc.stdout) x = JSON.parse(dcproc.stdout);
 else x = JSON.parse(dcproc);
 
-fs.writeFileSync(
-	path.join(__dirname, "..", `depclean.out.json`),
-	JSON.stringify(x, null, "\t"),
-	{ encoding: "utf8" }
-);
+fs.writeFileSync(path.join(__dirname, "..", `depclean.out.json`), JSON.stringify(x, null, "\t"), { encoding: "utf8" });
 
 let depsToRemove = x.dependencies.join(" ");
 if (depsToRemove) execIn(`npm r --save ${depsToRemove}`, partDir);
@@ -50,11 +43,9 @@ if (depsToRemove) execIn(`npm r --save --dev ${depsToRemove}`, partDir);
 if (removeModules && fs.existsSync(path.join(partDir, "node_modules")))
 	fs.rmSync(path.join(partDir, "node_modules"), {
 		recursive: true,
-		force: true,
+		force: true
 	});
-let end = getLines(
-	execIn("npm ls --parseable --package-lock-only -a", partDir)
-);
+let end = getLines(execIn("npm ls --parseable --package-lock-only -a", partDir));
 console.log(`${part}: ${start} -> ${end} (diff: ${start - end})`);
 
 console.log("Installing required packages for bundle...");
diff --git a/scripts/first_setup.js b/scripts/first_setup.js
new file mode 100644
index 00000000..24088eee
--- /dev/null
+++ b/scripts/first_setup.js
@@ -0,0 +1,185 @@
+const path = require("path");
+const fs = require("fs");
+const { stdout, exit } = require("process");
+const readline = require("readline");
+
+const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
+const data = { env: [], config: { register: {} } };
+let rights = [];
+
+console.log("Welcome to Fosscord!");
+console.log("Please remember this is pre-release software!");
+console.log("We will guide you through some important setup steps.");
+console.log();
+
+async function main() {
+	printTitle("Step 1: Database setup");
+	console.log("1. PostgreSQL (recommended)");
+	console.log("2. MariaDB/MySQL");
+	console.log("3. SQLite (not recommended, but good for a simple test)");
+
+	while (!data.db) {
+		let answer = await ask("Please select a database type: ");
+		if (answer == "1") {
+			data.db = "postgres";
+		} else if (answer == "2") {
+			data.db = "mariadb";
+		} else if (answer == "3") {
+			data.db = "sqlite";
+		} else {
+			console.log("Invalid choice!");
+		}
+	}
+
+	printTitle("Step 2: Database credentials");
+	if (data.db != "sqlite") {
+		console.log("Please enter your database credentials.");
+		console.log("You can leave the password field empty if you don't want to set a password.");
+		console.log();
+		while (!data.db_host) {
+			data.db_host = await ask("Host: ");
+		}
+		while (!data.db_port) {
+			data.db_port = await ask("Port: ");
+		}
+		while (!data.db_user) {
+			data.db_user = await ask("Username: ");
+		}
+		while (!data.db_pass) {
+			data.db_pass = await ask("Password: ");
+		}
+		while (!data.db_name) {
+			data.db_name = await ask("Database name: ");
+		}
+	} else {
+		console.log("SQLite does not use credentials...");
+	}
+
+	printTitle("Step 3: Domain setup");
+	console.log("Please enter your domain.");
+	console.log("You can leave the port field empty if you don't want to set a port.");
+	console.log();
+
+	data.domain = await ask("Domain (default=localhost): ");
+	if (!data.domain) data.domain = "localhost";
+	else data.ssl = /y?/i.test(await ask("SSL/HTTPS (Y/n): ")).toLowerCase();
+
+	data.port = await ask("Port (default=3001): ");
+	if (!data.port) data.port = "3001";
+
+	if (data.db != "sqlite")
+		data.env.push(`DATABASE=${data.db}://${data.db_user}:${data.db_pass}@${data.db_host}:${data.db_port}/${data.db_name}`);
+	data.env.push(`PORT=${data.port}`);
+
+	printTitle("Step 4: Default rights");
+	console.log("Please enter the default rights for new users.");
+	console.log("Valid rights are: none, discord, full, custom.");
+	console.log();
+	let lines = fs.readFileSync(path.join(__dirname, "..", "src", "util", "util", "Rights.ts")).toString();
+	let lines2 = lines.split("\n");
+	let lines3 = lines2.filter((y) => y.includes(": BitFlag("));
+	let lines4 = lines3.map((x) => x.split("//")[0].trim());
+
+	let maxRights = 0n;
+	lines4.forEach((x) => {
+		maxRights += eval(`rights.${x.replace(":", " = ").replace(",", ";")}`);
+	});
+	discordRights = maxRights;
+	discordRights -= rights.SEND_BACKDATED_EVENTS;
+	discordRights -= rights.MANAGE_GUILD_DIRECTORY;
+	discordRights -= rights.CREDITABLE;
+	discordRights -= rights.BYPASS_RATE_LIMITS;
+	discordRights -= rights.ADD_MEMBERS;
+	discordRights -= rights.MANAGE_RATE_LIMITS;
+	discordRights -= rights.OPERATOR;
+
+	data.default_rights = await ask("Rights (default=none): ");
+	if (!data.default_rights || data.defaultRights == "none") data.config.register.defaultRights = "0";
+	else if (data.default_rights == "discord") data.config.register.defaultRights = discordRights.toString();
+	else if (data.default_rights == "full") data.config.register.defaultRights = maxRights.toString();
+	else if (data.default_rights == "custom") data.config.register.defaultRights = (await askRights()).toString();
+
+	if (data.domain != "localhost")
+		data.config = {
+			cdn: {
+				endpointPrivate: `http://localhost:${data.port}`,
+				endpointPublic: `${data.ssl ? "https" : "http"}://${data.domain}:${data.port}`
+			},
+			gateway: {
+				endpointPrivate: `ws://localhost:${data.port}`,
+				endpointPublic: `${data.ssl ? "wss" : "ws"}://${data.domain}:${data.port}`
+			},
+			...data.config
+		};
+	//save
+	fs.writeFileSync(".env", data.env.join("\n"));
+	fs.writeFileSync("initial.json", JSON.stringify(data.config, (space = 4)));
+	exit(0);
+}
+main();
+
+async function askRights() {
+	let w = 0;
+	let brights = { ...eval(`rights`) };
+	Object.keys(rights).forEach((x) => {
+		brights[x] = false;
+		let str = `[x] ${Object.keys(rights).length}: ${x}`;
+		if (str.length > w) w = str.length;
+	});
+
+	let resp = "";
+	let selectedRights = 0n;
+	while (resp != "q") {
+		selectedRights = 0n;
+		Object.keys(brights).forEach((x) => {
+			if (brights[x]) selectedRights += rights[x];
+		});
+		console.clear();
+		printTitle("Step 4: Default rights");
+		printTitle(`Current rights: ${selectedRights} (0b${selectedRights.toString(2)}, 0x${selectedRights.toString(16)})`);
+		let xpos = 0;
+		Object.keys(rights).forEach((x) => {
+			let str = `[${brights[x] ? "X" : " "}] ${Object.keys(rights).indexOf(x)}: ${x}`.padEnd(w + 1, " ");
+			if (xpos + str.length > stdout.columns) {
+				console.log();
+				xpos = 0;
+			}
+			stdout.write(str);
+			xpos += str.length;
+		});
+
+		console.log();
+		resp = await ask("Enter an option, or q to exit: ");
+		if (/\d{1,}/.test(resp) && resp < Object.keys(rights).length && resp > -1) {
+			brights[Object.keys(brights)[parseInt(resp)]] ^= true;
+		}
+	}
+	return selectedRights;
+}
+
+async function askRight(right) {
+	let answer = await ask(`${right}: `);
+	if (answer == "y") return true;
+	else if (answer == "n") return false;
+	else return askRight(right);
+}
+
+function printTitle(input) {
+	let width = stdout.columns / 2 - 1; //40
+	console.log();
+	console.log("-".repeat(width - input.length / 2), input, "-".repeat(width - input.length / 2));
+	console.log();
+}
+async function ask(question) {
+	return new Promise((resolve, reject) => {
+		return rl.question(question, (answer) => {
+			resolve(answer);
+		});
+	}).catch((err) => {
+		console.log(err);
+	});
+}
+
+function BitFlag(int) {
+	return 1n << BigInt(int);
+}
diff --git a/scripts/gen_index.js b/scripts/gen_index.js
index 71c64a9f..8a3c7eb8 100644
--- a/scripts/gen_index.js
+++ b/scripts/gen_index.js
@@ -1,34 +1,37 @@
 const path = require("path");
 const fs = require("fs");
-const { execIn, getLines, parts } = require('./utils');
+const { execIn, getLines } = require("./utils");
 
 if (!process.argv[2] || !fs.existsSync(process.argv[2])) {
-    console.log("Please pass a directory that exists!");
-    process.exit(1);
+	console.log("Please pass a directory that exists!");
+	process.exit(1);
 }
-console.log(`// ${process.argv[2]}/index.ts`)
-const recurse = process.argv.includes("--recursive")
+console.log(`// ${process.argv[2]}/index.ts`);
+const recurse = process.argv.includes("--recursive");
 
-const files = fs.readdirSync(process.argv[2]).filter(x => x.endsWith('.ts') && x != 'index.ts');
+const files = fs.readdirSync(process.argv[2]).filter((x) => x.endsWith(".ts") && x != "index.ts");
 
-let output = '';
+let output = "";
 
-files.forEach(x => output += `export * from "./${x.replaceAll('.ts','')}";\n`)
+files.forEach((x) => (output += `export * from "./${x.replaceAll(".ts", "")}";\n`));
 
-const dirs = fs.readdirSync(process.argv[2]).filter(x => {
-    try {
-        fs.readdirSync(path.join(process.argv[2], x));
-        return true; 
-    } catch (e) { 
-        return false; 
-    }
+const dirs = fs.readdirSync(process.argv[2]).filter((x) => {
+	try {
+		fs.readdirSync(path.join(process.argv[2], x));
+		return true;
+	} catch (e) {
+		return false;
+	}
+});
+dirs.forEach((x) => {
+	output += `export * from "./${x}/index";\n`;
 });
-dirs.forEach(x => {
-    output += `export * from "./${x}/index";\n`
-})
 console.log(output);
-fs.writeFileSync(path.join(process.argv[2], "index.ts"), output)
+fs.writeFileSync(path.join(process.argv[2], "index.ts"), output);
 
-dirs.forEach(x => {
-    if(recurse) console.log(execIn([process.argv[0], process.argv[1], `"${path.join(process.argv[2], x)}"`, "--recursive"].join(' '), process.cwd()))
-})
\ No newline at end of file
+dirs.forEach((x) => {
+	if (recurse)
+		console.log(
+			execIn([process.argv[0], process.argv[1], `"${path.join(process.argv[2], x)}"`, "--recursive"].join(" "), process.cwd())
+		);
+});
diff --git a/scripts/generate_schema.js b/scripts/generate_schema.js
index 6925df5d..e4bdd0c4 100644
--- a/scripts/generate_schema.js
+++ b/scripts/generate_schema.js
@@ -36,7 +36,7 @@ const Excluded = [
 	"UncheckedPropertiesSchema",
 	"PropertiesSchema",
 	"AsyncSchema",
-	"AnySchema",
+	"AnySchema"
 ];
 
 function modify(obj) {
@@ -48,13 +48,8 @@ function modify(obj) {
 }
 
 function main() {
-	const files = [
-		...walk(path.join(__dirname, "..", "src", "util", "schemas")),
-	];
-	const program = TJS.getProgramFromFiles(
-		files,
-		compilerOptions
-	);
+	const files = [...walk(path.join(__dirname, "..", "src", "util", "schemas"))];
+	const program = TJS.getProgramFromFiles(files, compilerOptions);
 	const generator = TJS.buildGenerator(program, settings);
 	if (!generator || !program) return;
 
diff --git a/scripts/migrate_db_engine.js b/scripts/migrate_db_engine.js
index 79e9d86f..b5b8008b 100644
--- a/scripts/migrate_db_engine.js
+++ b/scripts/migrate_db_engine.js
@@ -25,7 +25,7 @@ const {
 	Template,
 	User,
 	VoiceState,
-	Webhook,
+	Webhook
 } = require("../../dist/entities/index");
 
 async function main() {
@@ -54,7 +54,7 @@ async function main() {
 		VoiceState,
 		Webhook,
 		Message,
-		Attachment,
+		Attachment
 	];
 
 	const oldDB = await initDatabase();
@@ -69,7 +69,7 @@ async function main() {
 		database: isSqlite ? process.env.TO : undefined,
 		entities,
 		name: "new",
-		synchronize: true,
+		synchronize: true
 	});
 	let i = 0;
 
diff --git a/scripts/rights.js b/scripts/rights.js
index 20fd139c..5ae576ef 100644
--- a/scripts/rights.js
+++ b/scripts/rights.js
@@ -6,20 +6,20 @@ const { argv, stdout, exit } = require("process");
 
 const { execIn, getLines, parts } = require("./utils");
 
-let lines = fs.readFileSync(path.join(__dirname, "..", "src", "util", "util","Rights.ts")).toString()
+let lines = fs.readFileSync(path.join(__dirname, "..", "src", "util", "util", "Rights.ts")).toString();
 let lines2 = lines.split("\n");
-let lines3 = lines2.filter(y=>y.includes(": BitFlag("));
-let lines4 = lines3.map(x=>x.split("//")[0].trim())
+let lines3 = lines2.filter((y) => y.includes(": BitFlag("));
+let lines4 = lines3.map((x) => x.split("//")[0].trim());
 
 function BitFlag(int) {
-    return 1n << eval(`${int}n`);
+	return 1n << BigInt(int);
 }
 
-let rights = []
+let rights = [];
 let maxRights = 0n;
-lines4.forEach(x=>{
-    maxRights += eval(`rights.${x.replace(':'," = ").replace(",",";")}`)
-})
+lines4.forEach((x) => {
+	maxRights += eval(`rights.${x.replace(":", " = ").replace(",", ";")}`);
+});
 //max rights...
 console.log(`Maximum rights: ${maxRights}`);
 //discord rights...
@@ -31,4 +31,4 @@ discordRights -= rights.BYPASS_RATE_LIMITS;
 discordRights -= rights.ADD_MEMBERS;
 discordRights -= rights.MANAGE_RATE_LIMITS;
 discordRights -= rights.OPERATOR;
-console.log(`Discord-like rights: ${discordRights}`);
\ No newline at end of file
+console.log(`Discord-like rights: ${discordRights}`);
diff --git a/scripts/update_schemas.js b/scripts/update_schemas.js
index 361bedc1..151b52d2 100644
--- a/scripts/update_schemas.js
+++ b/scripts/update_schemas.js
@@ -6,4 +6,4 @@ const { argv, stdout, exit } = require("process");
 
 const { execIn, getLines, parts } = require("./utils");
 
-execIn("node scripts/generate_schema.js", path.join('.'));
\ No newline at end of file
+execIn("node scripts/generate_schema.js", path.join("."));
diff --git a/scripts/utils.js b/scripts/utils.js
index 84aaeed6..b679392b 100644
--- a/scripts/utils.js
+++ b/scripts/utils.js
@@ -4,6 +4,8 @@ const { env } = require("process");
 const { execSync } = require("child_process");
 const { argv, stdout, exit } = require("process");
 
+const projectRoot = path.resolve(path.join(__dirname, ".."));
+
 function copyRecursiveSync(src, dest) {
 	//if (verbose) console.log(`cpsync: ${src} -> ${dest}`);
 	let exists = fs.existsSync(src);
@@ -16,10 +18,7 @@ function copyRecursiveSync(src, dest) {
 	if (isDirectory) {
 		fs.mkdirSync(dest, { recursive: true });
 		fs.readdirSync(src).forEach(function (childItemName) {
-			copyRecursiveSync(
-				path.join(src, childItemName),
-				path.join(dest, childItemName)
-			);
+			copyRecursiveSync(path.join(src, childItemName), path.join(dest, childItemName));
 		});
 	} else {
 		fs.copyFileSync(src, dest);
@@ -44,8 +43,45 @@ function getLines(output) {
 	return output.split("\n").length;
 }
 
-module.exports = { 
+function getDirs(dir) {
+	return fs.readdirSync(dir).filter((x) => {
+		try {
+			fs.readdirSync(dir.join(dir, x));
+			return true;
+		} catch (e) {
+			return false;
+		}
+	});
+}
+
+function walk(dir) {
+	let results = [];
+	let list = fs.readdirSync(dir);
+	list.forEach(function (file) {
+		file = dir + "/" + file;
+		let stat = fs.statSync(file);
+		if (stat && stat.isDirectory()) {
+			/* Recurse into a subdirectory */
+			results = results.concat(walk(file));
+		} else {
+			results.push(file);
+		}
+	});
+	return results;
+}
+
+function sanitizeVarName(str) {
+	return str.replace("-", "_").replace(/[^\w\s]/gi, "");
+}
+
+module.exports = {
 	//consts
+	projectRoot,
 	//functions
-	copyRecursiveSync, execIn, getLines
+	copyRecursiveSync,
+	execIn,
+	getLines,
+	getDirs,
+	walk,
+	sanitizeVarName
 };
diff --git a/tests/cdn_endpoints.test.js b/tests/cdn_endpoints.test.js
index 5a543e54..5627bf40 100644
--- a/tests/cdn_endpoints.test.js
+++ b/tests/cdn_endpoints.test.js
@@ -11,17 +11,12 @@ if (!process.env.STORAGE_PROVIDER) process.env.STORAGE_PROVIDER = "file";
 if (process.env.STORAGE_PROVIDER === "file") {
 	if (process.env.STORAGE_LOCATION) {
 		if (!process.env.STORAGE_LOCATION.startsWith("/")) {
-			process.env.STORAGE_LOCATION = path.join(
-				__dirname,
-				"..",
-				process.env.STORAGE_LOCATION,
-				"/"
-			);
+			process.env.STORAGE_LOCATION = path.join(__dirname, "..", process.env.STORAGE_LOCATION, "/");
 		}
 	} else {
 		process.env.STORAGE_LOCATION = path.join(__dirname, "..", "files", "/");
 	}
-	if(!fs.existsSync(process.env.STORAGE_LOCATION)) fs.mkdirSync(process.env.STORAGE_LOCATION, {recursive:true});
+	if (!fs.existsSync(process.env.STORAGE_LOCATION)) fs.mkdirSync(process.env.STORAGE_LOCATION, { recursive: true });
 }
 const { CDNServer } = require("../dist/Server");
 const { Config } = require("@fosscord/util");
@@ -59,9 +54,7 @@ describe("/attachments", () => {
 		});
 		describe("with signature specified, without file specified", () => {
 			test("route should respond with 400", async () => {
-				const response = await request
-					.post("/attachments/123456789")
-					.set({ signature: Config.get().security.requestSignature });
+				const response = await request.post("/attachments/123456789").set({ signature: Config.get().security.requestSignature });
 				expect(response.statusCode).toBe(400);
 			});
 		});
@@ -72,9 +65,7 @@ describe("/attachments", () => {
 					.set({ signature: Config.get().security.requestSignature })
 					.attach("file", __dirname + "/antman.jpg");
 				expect(response.statusCode).toBe(200);
-				expect(response.headers["content-type"]).toEqual(
-					expect.stringContaining("json")
-				);
+				expect(response.headers["content-type"]).toEqual(expect.stringContaining("json"));
 				expect(response.body.url).toBeDefined();
 			});
 		});
@@ -86,11 +77,9 @@ describe("/attachments", () => {
 					.post("/attachments/123456789")
 					.set({ signature: Config.get().security.requestSignature })
 					.attach("file", __dirname + "/antman.jpg");
-				request
-					.get(response.body.url.replace("http://localhost:3003", ""))
-					.then((x) => {
-						expect(x.statusCode).toBe(200);
-					});
+				request.get(response.body.url.replace("http://localhost:3003", "")).then((x) => {
+					expect(x.statusCode).toBe(200);
+				});
 			});
 		});
 	});
@@ -101,13 +90,9 @@ describe("/attachments", () => {
 					.post("/attachments/123456789")
 					.set({ signature: Config.get().security.requestSignature })
 					.attach("file", __dirname + "/antman.jpg");
-				request
-					.delete(
-						response.body.url.replace("http://localhost:3003", "")
-					)
-					.then((x) => {
-						expect(x.body.success).toBeDefined();
-					});
+				request.delete(response.body.url.replace("http://localhost:3003", "")).then((x) => {
+					expect(x.body.success).toBeDefined();
+				});
 			});
 		});
 	});
@@ -123,9 +108,7 @@ describe("/avatars", () => {
 		});
 		describe("with signature specified, without file specified", () => {
 			test("route should respond with 400", async () => {
-				const response = await request
-					.post("/avatars/123456789")
-					.set({ signature: Config.get().security.requestSignature });
+				const response = await request.post("/avatars/123456789").set({ signature: Config.get().security.requestSignature });
 				expect(response.statusCode).toBe(400);
 			});
 		});
@@ -136,9 +119,7 @@ describe("/avatars", () => {
 					.set({ signature: Config.get().security.requestSignature })
 					.attach("file", __dirname + "/antman.jpg");
 				expect(response.statusCode).toBe(200);
-				expect(response.headers["content-type"]).toEqual(
-					expect.stringContaining("json")
-				);
+				expect(response.headers["content-type"]).toEqual(expect.stringContaining("json"));
 				expect(response.body.url).toBeDefined();
 			});
 		});
@@ -150,11 +131,9 @@ describe("/avatars", () => {
 					.post("/avatars/123456789")
 					.set({ signature: Config.get().security.requestSignature })
 					.attach("file", __dirname + "/antman.jpg");
-				request
-					.get(response.body.url.replace("http://localhost:3003", ""))
-					.then((x) => {
-						expect(x.statusCode).toBe(200);
-					});
+				request.get(response.body.url.replace("http://localhost:3003", "")).then((x) => {
+					expect(x.statusCode).toBe(200);
+				});
 			});
 		});
 	});
@@ -165,13 +144,9 @@ describe("/avatars", () => {
 					.post("/avatars/123456789")
 					.set({ signature: Config.get().security.requestSignature })
 					.attach("file", __dirname + "/antman.jpg");
-				request
-					.delete(
-						response.body.url.replace("http://localhost:3003", "")
-					)
-					.then((x) => {
-						expect(x.body.success).toBeDefined();
-					});
+				request.delete(response.body.url.replace("http://localhost:3003", "")).then((x) => {
+					expect(x.body.success).toBeDefined();
+				});
 			});
 		});
 	});
@@ -187,35 +162,25 @@ describe("/external", () => {
 		});
 		describe("with signature specified, without file specified", () => {
 			test("route should respond with 400", async () => {
-				const response = await request
-					.post("/external")
-					.set({ signature: Config.get().security.requestSignature });
+				const response = await request.post("/external").set({ signature: Config.get().security.requestSignature });
 				expect(response.statusCode).toBe(400);
 			});
 		});
 		describe("with signature specified, with file specified ", () => {
 			test("route should respond with Content-type: application/json, 200 and res.body.url", async () => {
-				const response = await request
-					.post("/external")
-					.set({ signature: Config.get().security.requestSignature })
-					.send({
-						url: "https://i.ytimg.com/vi_webp/TiXzhQr5AUc/mqdefault.webp",
-					});
+				const response = await request.post("/external").set({ signature: Config.get().security.requestSignature }).send({
+					url: "https://i.ytimg.com/vi_webp/TiXzhQr5AUc/mqdefault.webp"
+				});
 				expect(response.statusCode).toBe(200);
-				expect(response.headers["content-type"]).toEqual(
-					expect.stringContaining("json")
-				);
+				expect(response.headers["content-type"]).toEqual(expect.stringContaining("json"));
 				expect(response.body.id).toBeDefined();
 			});
 		});
 		describe("with signature specified, with falsy url specified ", () => {
 			test("route should respond with 400", async () => {
-				const response = await request
-					.post("/external")
-					.set({ signature: Config.get().security.requestSignature })
-					.send({
-						url: "notavalidurl.123",
-					});
+				const response = await request.post("/external").set({ signature: Config.get().security.requestSignature }).send({
+					url: "notavalidurl.123"
+				});
 				expect(response.statusCode).toBe(400);
 			});
 		});
@@ -223,12 +188,9 @@ describe("/external", () => {
 	describe("GET", () => {
 		describe("getting uploaded image by url returned by POST /avatars", () => {
 			test("route should respond with 200", async () => {
-				let response = await request
-					.post("/external")
-					.set({ signature: Config.get().security.requestSignature })
-					.send({
-						url: "https://i.ytimg.com/vi_webp/TiXzhQr5AUc/mqdefault.webp",
-					});
+				let response = await request.post("/external").set({ signature: Config.get().security.requestSignature }).send({
+					url: "https://i.ytimg.com/vi_webp/TiXzhQr5AUc/mqdefault.webp"
+				});
 				request.get(`external/${response.body.id}`).then((x) => {
 					expect(x.statusCode).toBe(200);
 				});
diff --git a/tests/routes.test.ts b/tests/routes.test.ts
index c915fab9..51c068b5 100644
--- a/tests/routes.test.ts
+++ b/tests/routes.test.ts
@@ -1,13 +1,13 @@
 // TODO: check every route based on route() parameters: https://github.com/fosscord/fosscord-server/issues/308
 // TODO: check every route with different database engine
 
-import getRouteDescriptions from "../jest/getRouteDescriptions";
-import { join } from "path";
-import fs from "fs";
+import { Channel, Event, events, Guild, User } from "@fosscord/util";
 import Ajv from "ajv";
 import addFormats from "ajv-formats";
+import fs from "fs";
 import fetch from "node-fetch";
-import { Event, User, events, Guild, Channel } from "@fosscord/util";
+import { join } from "path";
+import getRouteDescriptions from "../jest/getRouteDescriptions";
 
 const SchemaPath = join(__dirname, "..", "assets", "schemas.json");
 const schemas = JSON.parse(fs.readFileSync(SchemaPath, { encoding: "utf8" }));
diff --git a/tests/setupJest.js b/tests/setupJest.js
index 378d72d5..bb52525f 100644
--- a/tests/setupJest.js
+++ b/tests/setupJest.js
@@ -17,7 +17,7 @@ global.expect.extend({
 
 		return {
 			pass: time < target && !error,
-			message: () => error || `${func.name} took ${time}ms of maximum ${target}`,
+			message: () => error || `${func.name} took ${time}ms of maximum ${target}`
 		};
-	},
+	}
 });
diff --git a/tsconfig.json b/tsconfig.json
index b9e17f29..eb3399aa 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,85 +1,79 @@
-{

-	"include": ["src/**/*.ts"],

-	"exclude": [],

-	"compilerOptions": {

-

-		/* Basic Options */

-		"incremental": false /* Enable incremental compilation */,

-		"target": "ESNext" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,

-		"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,

-		"lib": [

-			"ESNext"

-		] /* Specify library files to be included in the compilation. */,

-		"allowJs": true /* Allow javascript files to be compiled. */,

-		"checkJs": true /* Report errors in .js files. */,

-		// "jsx": "preserve",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */

-		"declaration": false /* Generates corresponding '.d.ts' file. */,

-		"declarationMap": false /* Generates a sourcemap for each corresponding '.d.ts' file. */,

-		"sourceMap": true /* Generates corresponding '.map' file. */,

-		// "outFile": "./",                       /* Concatenate and emit output to single file. */

-		"outDir": "./dist/" /* Redirect output structure to the directory. */,

-		"rootDir": "./src/" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,

-		// "composite": true,                     /* Enable project compilation */

-		// "tsBuildInfoFile": "./",               /* Specify file to store incremental compilation information */

-		// "removeComments": true,                /* Do not emit comments to output. */

-		// "noEmit": true,                        /* Do not emit outputs. */

-		// "importHelpers": true,                 /* Import emit helpers from 'tslib'. */

-		// "downlevelIteration": true,            /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */

-		// "isolatedModules": true,               /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */

-

-		/* Strict Type-Checking Options */

-		"strict": true /* Enable all strict type-checking options. */,

-		"noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */,

-		"strictNullChecks": true /* Enable strict null checks. */,

-		// "strictFunctionTypes": true,           /* Enable strict checking of function types. */

-		// "strictBindCallApply": true,           /* Enable strict 'bind', 'call', and 'apply' methods on functions. */

-		"strictPropertyInitialization": false /* Enable strict checking of property initialization in classes. */,

-		// "noImplicitThis": true,                /* Raise error on 'this' expressions with an implied 'any' type. */

-		"alwaysStrict": true /* Parse in strict mode and emit "use strict" for each source file. */,

-

-		/* Additional Checks */

-		// "noUnusedLocals": true,                /* Report errors on unused locals. */

-		// "noUnusedParameters": true,            /* Report errors on unused parameters. */

-		// "noImplicitReturns": true,             /* Report error when not all code paths in function return a value. */

-		// "noFallthroughCasesInSwitch": true,    /* Report errors for fallthrough cases in switch statement. */

-

-		/* Module Resolution Options */

-		"moduleResolution": "node",            /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */

-		// "rootDirs": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. */

-		// "typeRoots": [],                       /* List of folders to include type definitions from. */

-		"types": [

-			"node"

-		] /* Type declaration files to be included in compilation. */,

-		// "allowSyntheticDefaultImports": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */

-		"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,

-		// "preserveSymlinks": true,              /* Do not resolve the real path of symlinks. */

-		// "allowUmdGlobalAccess": true,          /* Allow accessing UMD globals from modules. */

-

-		/* Source Map Options */

-		// "sourceRoot": "",                      /* Specify the location where debugger should locate TypeScript files instead of source locations. */

-		// "mapRoot": "",                         /* Specify the location where debugger should locate map files instead of generated locations. */

-		// "inlineSourceMap": true,               /* Emit a single file with source maps instead of having a separate file. */

-		// "inlineSources": true,                 /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */

-

-		/* Experimental Options */

-		// "experimentalDecorators": true,        /* Enables experimental support for ES7 decorators. */

-		// "emitDecoratorMetadata": true,         /* Enables experimental support for emitting type metadata for decorators. */

-

-		/* Advanced Options */

-		"skipLibCheck": true /* Skip type checking of declaration files. */,

-		"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */,

-		"emitDecoratorMetadata": true,

-		"experimentalDecorators": true,

-		"resolveJsonModule": true,

-		"baseUrl": "./src/",

-		"paths": {

-			"@fosscord/api": ["./api/index"],

-			"@fosscord/gateway": ["./gateway/index"],

-			"@fosscord/cdn": ["./cdn/index"],

-			"@fosscord/util": ["./util/index"]

-		},

-		"plugins": [{ "transform": "@ovos-media/ts-transform-paths" }],

-		"noEmitHelpers": true,

-		"importHelpers": true

-	}

-}

+{
+	"include": ["src/**/*.ts"],
+	"exclude": [],
+	"compilerOptions": {
+		/* Basic Options */
+		"incremental": false /* Enable incremental compilation */,
+		"target": "ESNext" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
+		"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
+		"lib": ["ESNext"] /* Specify library files to be included in the compilation. */,
+		"allowJs": true /* Allow javascript files to be compiled. */,
+		"checkJs": true /* Report errors in .js files. */,
+		// "jsx": "preserve",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
+		"declaration": false /* Generates corresponding '.d.ts' file. */,
+		"declarationMap": false /* Generates a sourcemap for each corresponding '.d.ts' file. */,
+		"sourceMap": true /* Generates corresponding '.map' file. */,
+		// "outFile": "./",                       /* Concatenate and emit output to single file. */
+		"outDir": "./dist/" /* Redirect output structure to the directory. */,
+		"rootDir": "./src/" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
+		// "composite": true,                     /* Enable project compilation */
+		// "tsBuildInfoFile": "./",               /* Specify file to store incremental compilation information */
+		// "removeComments": true,                /* Do not emit comments to output. */
+		// "noEmit": true,                        /* Do not emit outputs. */
+		// "importHelpers": true,                 /* Import emit helpers from 'tslib'. */
+		// "downlevelIteration": true,            /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
+		// "isolatedModules": true,               /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
+
+		/* Strict Type-Checking Options */
+		"strict": true /* Enable all strict type-checking options. */,
+		"noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */,
+		"strictNullChecks": true /* Enable strict null checks. */,
+		// "strictFunctionTypes": true,           /* Enable strict checking of function types. */
+		// "strictBindCallApply": true,           /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
+		"strictPropertyInitialization": false /* Enable strict checking of property initialization in classes. */,
+		// "noImplicitThis": true,                /* Raise error on 'this' expressions with an implied 'any' type. */
+		"alwaysStrict": true /* Parse in strict mode and emit "use strict" for each source file. */,
+
+		/* Additional Checks */
+		// "noUnusedLocals": true,                /* Report errors on unused locals. */
+		// "noUnusedParameters": true,            /* Report errors on unused parameters. */
+		// "noImplicitReturns": true,             /* Report error when not all code paths in function return a value. */
+		// "noFallthroughCasesInSwitch": true,    /* Report errors for fallthrough cases in switch statement. */
+
+		/* Module Resolution Options */
+		"moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
+		// "rootDirs": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. */
+		// "typeRoots": [],                       /* List of folders to include type definitions from. */
+		"types": ["node"] /* Type declaration files to be included in compilation. */,
+		// "allowSyntheticDefaultImports": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
+		"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
+		// "preserveSymlinks": true,              /* Do not resolve the real path of symlinks. */
+		// "allowUmdGlobalAccess": true,          /* Allow accessing UMD globals from modules. */
+
+		/* Source Map Options */
+		// "sourceRoot": "",                      /* Specify the location where debugger should locate TypeScript files instead of source locations. */
+		// "mapRoot": "",                         /* Specify the location where debugger should locate map files instead of generated locations. */
+		// "inlineSourceMap": true,               /* Emit a single file with source maps instead of having a separate file. */
+		// "inlineSources": true,                 /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
+
+		/* Experimental Options */
+		// "experimentalDecorators": true,        /* Enables experimental support for ES7 decorators. */
+		// "emitDecoratorMetadata": true,         /* Enables experimental support for emitting type metadata for decorators. */
+
+		/* Advanced Options */
+		"skipLibCheck": true /* Skip type checking of declaration files. */,
+		"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */,
+		"emitDecoratorMetadata": true,
+		"experimentalDecorators": true,
+		"resolveJsonModule": true,
+		"baseUrl": "./src/",
+		"paths": {
+			"@fosscord/api": ["./api/index"],
+			"@fosscord/gateway": ["./gateway/index"],
+			"@fosscord/cdn": ["./cdn/index"],
+			"@fosscord/util": ["./util/index"]
+		},
+		"noEmitHelpers": true,
+		"importHelpers": true
+	}
+}