summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--api/__tests__/routes/auth/login.ts1
-rw-r--r--api/jest.config.ts4
-rw-r--r--api/package-lock.json1069
-rw-r--r--api/package.json6
-rw-r--r--api/scripts/setup_test.js1
-rw-r--r--api/src/middlewares/ErrorHandler.ts1
-rw-r--r--api/src/routes/auth/login.ts12
-rw-r--r--api/src/routes/auth/register.ts59
-rw-r--r--api/src/routes/guilds/#guild_id/channels.ts12
-rw-r--r--api/src/routes/guilds/#guild_id/templates.ts60
-rw-r--r--api/src/routes/guilds/templates/index.ts7
-rw-r--r--api/src/routes/invites/index.ts4
-rw-r--r--api/src/routes/users/#id/profile.ts2
-rw-r--r--api/src/routes/users/@me/relationships.ts36
-rw-r--r--api/src/util/Channel.ts2
-rw-r--r--api/src/util/User.ts16
-rw-r--r--api/tests/routes/auth/login.ts1
17 files changed, 1129 insertions, 164 deletions
diff --git a/api/__tests__/routes/auth/login.ts b/api/__tests__/routes/auth/login.ts
deleted file mode 100644
index 536e03ee..00000000
--- a/api/__tests__/routes/auth/login.ts
+++ /dev/null
@@ -1 +0,0 @@
-it("works", () => {});
diff --git a/api/jest.config.ts b/api/jest.config.ts
index 153a9b2b..50550d9d 100644
--- a/api/jest.config.ts
+++ b/api/jest.config.ts
@@ -145,9 +145,9 @@ export default {
 
 	// The glob patterns Jest uses to detect test files
 	testMatch: [
-		"**/__tests__/**/*.[jt]s?(x)",
+		"**/tests/**/*.[jt]s?(x)"
 		//   "**/?(*.)+(spec|test).[tj]s?(x)"
-	],
+	]
 
 	// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
 	// testPathIgnorePatterns: [
diff --git a/api/package-lock.json b/api/package-lock.json
index 3221969a..bff4e940 100644
--- a/api/package-lock.json
+++ b/api/package-lock.json
@@ -34,13 +34,15 @@
 				"mongoose-autopopulate": "^0.12.3",
 				"mongoose-long": "^0.3.2",
 				"multer": "^1.4.2",
-				"node-fetch": "^2.6.1"
+				"node-fetch": "^2.6.1",
+				"typeorm": "^0.2.37"
 			},
 			"devDependencies": {
 				"@types/amqplib": "^0.8.1",
 				"@types/bcrypt": "^5.0.0",
 				"@types/express": "^4.17.9",
 				"@types/i18next-node-fs-backend": "^2.1.0",
+				"@types/jest": "^27.0.1",
 				"@types/jsonwebtoken": "^8.5.0",
 				"@types/mongodb": "^3.6.9",
 				"@types/mongoose": "^5.10.5",
@@ -74,9 +76,9 @@
 				"jsonwebtoken": "^8.5.1",
 				"missing-native-js-functions": "^1.2.10",
 				"node-fetch": "^2.6.1",
+				"patch-package": "^6.4.7",
 				"reflect-metadata": "^0.1.13",
 				"sqlite3": "^5.0.2",
-				"ts-transform-json-schema": "^2.0.3",
 				"typeorm": "^0.2.37",
 				"typescript": "^4.3.5",
 				"typescript-json-schema": "^0.50.1"
@@ -1115,6 +1117,11 @@
 				"@sinonjs/commons": "^1.7.0"
 			}
 		},
+		"node_modules/@sqltools/formatter": {
+			"version": "1.2.3",
+			"resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.3.tgz",
+			"integrity": "sha512-O3uyB/JbkAEMZaP3YqyHH7TMnex7tWyCbCI4EfJdOCoN6HIhqdJBWTM6aCCiWQ/5f5wxjgU735QAIpJbjDvmzg=="
+		},
 		"node_modules/@tootallnate/once": {
 			"version": "1.1.2",
 			"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
@@ -1282,6 +1289,101 @@
 				"@types/istanbul-lib-report": "*"
 			}
 		},
+		"node_modules/@types/jest": {
+			"version": "27.0.1",
+			"resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.0.1.tgz",
+			"integrity": "sha512-HTLpVXHrY69556ozYkcq47TtQJXpcWAWfkoqz+ZGz2JnmZhzlRjprCIyFnetSy8gpDWwTTGBcRVv1J1I1vBrHw==",
+			"dev": true,
+			"dependencies": {
+				"jest-diff": "^27.0.0",
+				"pretty-format": "^27.0.0"
+			}
+		},
+		"node_modules/@types/jest/node_modules/@jest/types": {
+			"version": "27.0.6",
+			"resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz",
+			"integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==",
+			"dev": true,
+			"dependencies": {
+				"@types/istanbul-lib-coverage": "^2.0.0",
+				"@types/istanbul-reports": "^3.0.0",
+				"@types/node": "*",
+				"@types/yargs": "^16.0.0",
+				"chalk": "^4.0.0"
+			},
+			"engines": {
+				"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
+			}
+		},
+		"node_modules/@types/jest/node_modules/@types/yargs": {
+			"version": "16.0.4",
+			"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz",
+			"integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==",
+			"dev": true,
+			"dependencies": {
+				"@types/yargs-parser": "*"
+			}
+		},
+		"node_modules/@types/jest/node_modules/ansi-styles": {
+			"version": "5.2.0",
+			"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+			"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+			"dev": true,
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/chalk/ansi-styles?sponsor=1"
+			}
+		},
+		"node_modules/@types/jest/node_modules/diff-sequences": {
+			"version": "27.0.6",
+			"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz",
+			"integrity": "sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==",
+			"dev": true,
+			"engines": {
+				"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
+			}
+		},
+		"node_modules/@types/jest/node_modules/jest-diff": {
+			"version": "27.0.6",
+			"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.0.6.tgz",
+			"integrity": "sha512-Z1mqgkTCSYaFgwTlP/NUiRzdqgxmmhzHY1Tq17zL94morOHfHu3K4bgSgl+CR4GLhpV8VxkuOYuIWnQ9LnFqmg==",
+			"dev": true,
+			"dependencies": {
+				"chalk": "^4.0.0",
+				"diff-sequences": "^27.0.6",
+				"jest-get-type": "^27.0.6",
+				"pretty-format": "^27.0.6"
+			},
+			"engines": {
+				"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
+			}
+		},
+		"node_modules/@types/jest/node_modules/jest-get-type": {
+			"version": "27.0.6",
+			"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz",
+			"integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==",
+			"dev": true,
+			"engines": {
+				"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
+			}
+		},
+		"node_modules/@types/jest/node_modules/pretty-format": {
+			"version": "27.0.6",
+			"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz",
+			"integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==",
+			"dev": true,
+			"dependencies": {
+				"@jest/types": "^27.0.6",
+				"ansi-regex": "^5.0.0",
+				"ansi-styles": "^5.0.0",
+				"react-is": "^17.0.1"
+			},
+			"engines": {
+				"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
+			}
+		},
 		"node_modules/@types/jsonwebtoken": {
 			"version": "8.5.4",
 			"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.4.tgz",
@@ -1425,6 +1527,11 @@
 			"integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==",
 			"dev": true
 		},
+		"node_modules/@types/zen-observable": {
+			"version": "0.8.3",
+			"resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.3.tgz",
+			"integrity": "sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw=="
+		},
 		"node_modules/@zerollup/ts-helpers": {
 			"version": "1.7.18",
 			"resolved": "https://registry.npmjs.org/@zerollup/ts-helpers/-/ts-helpers-1.7.18.tgz",
@@ -1667,7 +1774,6 @@
 			"version": "5.0.0",
 			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
 			"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
-			"dev": true,
 			"engines": {
 				"node": ">=8"
 			}
@@ -1692,6 +1798,11 @@
 			"integrity": "sha1-vgiVmQl7dKXJxKhKDNvNtivYeu8=",
 			"dev": true
 		},
+		"node_modules/any-promise": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+			"integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8="
+		},
 		"node_modules/anymatch": {
 			"version": "3.1.2",
 			"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
@@ -1705,6 +1816,14 @@
 				"node": ">= 8"
 			}
 		},
+		"node_modules/app-root-path": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz",
+			"integrity": "sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==",
+			"engines": {
+				"node": ">= 6.0.0"
+			}
+		},
 		"node_modules/append-field": {
 			"version": "1.0.0",
 			"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
@@ -2116,7 +2235,6 @@
 			"version": "1.5.1",
 			"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
 			"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
-			"dev": true,
 			"funding": [
 				{
 					"type": "github",
@@ -2927,6 +3045,111 @@
 				"node": ">=0.10.0"
 			}
 		},
+		"node_modules/cli-highlight": {
+			"version": "2.1.11",
+			"resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz",
+			"integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==",
+			"dependencies": {
+				"chalk": "^4.0.0",
+				"highlight.js": "^10.7.1",
+				"mz": "^2.4.0",
+				"parse5": "^5.1.1",
+				"parse5-htmlparser2-tree-adapter": "^6.0.0",
+				"yargs": "^16.0.0"
+			},
+			"bin": {
+				"highlight": "bin/highlight"
+			},
+			"engines": {
+				"node": ">=8.0.0",
+				"npm": ">=5.0.0"
+			}
+		},
+		"node_modules/cli-highlight/node_modules/cliui": {
+			"version": "7.0.4",
+			"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+			"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+			"dependencies": {
+				"string-width": "^4.2.0",
+				"strip-ansi": "^6.0.0",
+				"wrap-ansi": "^7.0.0"
+			}
+		},
+		"node_modules/cli-highlight/node_modules/is-fullwidth-code-point": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+			"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/cli-highlight/node_modules/parse5": {
+			"version": "5.1.1",
+			"resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
+			"integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug=="
+		},
+		"node_modules/cli-highlight/node_modules/string-width": {
+			"version": "4.2.2",
+			"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
+			"integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
+			"dependencies": {
+				"emoji-regex": "^8.0.0",
+				"is-fullwidth-code-point": "^3.0.0",
+				"strip-ansi": "^6.0.0"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/cli-highlight/node_modules/wrap-ansi": {
+			"version": "7.0.0",
+			"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+			"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+			"dependencies": {
+				"ansi-styles": "^4.0.0",
+				"string-width": "^4.1.0",
+				"strip-ansi": "^6.0.0"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+			}
+		},
+		"node_modules/cli-highlight/node_modules/y18n": {
+			"version": "5.0.8",
+			"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+			"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+			"engines": {
+				"node": ">=10"
+			}
+		},
+		"node_modules/cli-highlight/node_modules/yargs": {
+			"version": "16.2.0",
+			"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+			"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
+			"dependencies": {
+				"cliui": "^7.0.2",
+				"escalade": "^3.1.1",
+				"get-caller-file": "^2.0.5",
+				"require-directory": "^2.1.1",
+				"string-width": "^4.2.0",
+				"y18n": "^5.0.5",
+				"yargs-parser": "^20.2.2"
+			},
+			"engines": {
+				"node": ">=10"
+			}
+		},
+		"node_modules/cli-highlight/node_modules/yargs-parser": {
+			"version": "20.2.9",
+			"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+			"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
+			"engines": {
+				"node": ">=10"
+			}
+		},
 		"node_modules/cliui": {
 			"version": "6.0.0",
 			"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
@@ -4114,8 +4337,7 @@
 		"node_modules/emoji-regex": {
 			"version": "8.0.0",
 			"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-			"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
-			"dev": true
+			"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
 		},
 		"node_modules/encodeurl": {
 			"version": "1.0.2",
@@ -4169,7 +4391,6 @@
 			"version": "3.1.1",
 			"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
 			"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
-			"dev": true,
 			"engines": {
 				"node": ">=6"
 			}
@@ -4183,7 +4404,6 @@
 			"version": "1.0.5",
 			"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
 			"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
-			"dev": true,
 			"engines": {
 				"node": ">=0.8.0"
 			}
@@ -4693,6 +4913,14 @@
 				"bser": "2.1.1"
 			}
 		},
+		"node_modules/figlet": {
+			"version": "1.5.2",
+			"resolved": "https://registry.npmjs.org/figlet/-/figlet-1.5.2.tgz",
+			"integrity": "sha512-WOn21V8AhyE1QqVfPIVxe3tupJacq1xGkPTB4iagT6o+P2cAgEOOwIxMftr4+ZCTI6d551ij9j61DFr0nsP2uQ==",
+			"engines": {
+				"node": ">= 0.4.0"
+			}
+		},
 		"node_modules/fill-range": {
 			"version": "7.0.1",
 			"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -4908,7 +5136,6 @@
 			"version": "2.0.5",
 			"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
 			"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
-			"dev": true,
 			"engines": {
 				"node": "6.* || 8.* || >= 10.*"
 			}
@@ -5035,7 +5262,6 @@
 			"version": "2.0.0",
 			"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
 			"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
-			"dev": true,
 			"dependencies": {
 				"ansi-regex": "^2.0.0"
 			},
@@ -5047,7 +5273,6 @@
 			"version": "2.1.1",
 			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
 			"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
-			"dev": true,
 			"engines": {
 				"node": ">=0.10.0"
 			}
@@ -5174,6 +5399,14 @@
 				"node": ">=10.0.0"
 			}
 		},
+		"node_modules/highlight.js": {
+			"version": "10.7.3",
+			"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
+			"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==",
+			"engines": {
+				"node": "*"
+			}
+		},
 		"node_modules/hmac-drbg": {
 			"version": "1.0.1",
 			"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
@@ -5356,7 +5589,6 @@
 			"version": "1.2.1",
 			"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
 			"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
-			"dev": true,
 			"funding": [
 				{
 					"type": "github",
@@ -7394,6 +7626,16 @@
 			"integrity": "sha512-nU7mOEuaXiQIB/EgTIjYZJ7g8KqMm2D8l4qp+DqA4jxWOb/tnb1KEoqp+tlbdQIDIAiC1i7j7X/3yHDFXLxr9g==",
 			"dev": true
 		},
+		"node_modules/mz": {
+			"version": "2.7.0",
+			"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
+			"integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
+			"dependencies": {
+				"any-promise": "^1.0.0",
+				"object-assign": "^4.0.1",
+				"thenify-all": "^1.0.0"
+			}
+		},
 		"node_modules/nanoassert": {
 			"version": "1.1.0",
 			"resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-1.1.0.tgz",
@@ -8004,6 +8246,14 @@
 			"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
 			"dev": true
 		},
+		"node_modules/parent-require": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/parent-require/-/parent-require-1.0.0.tgz",
+			"integrity": "sha1-dGoWdjgIOoYLDu9nMssn7UbDKXc=",
+			"engines": {
+				"node": ">= 0.4.0"
+			}
+		},
 		"node_modules/parents": {
 			"version": "1.0.1",
 			"resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz",
@@ -8669,6 +8919,11 @@
 				"node": ">=8.10.0"
 			}
 		},
+		"node_modules/reflect-metadata": {
+			"version": "0.1.13",
+			"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
+			"integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg=="
+		},
 		"node_modules/regenerator-runtime": {
 			"version": "0.13.9",
 			"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
@@ -8720,7 +8975,6 @@
 			"version": "2.1.1",
 			"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
 			"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
-			"dev": true,
 			"engines": {
 				"node": ">=0.10.0"
 			}
@@ -9190,6 +9444,11 @@
 				"node": ">=6"
 			}
 		},
+		"node_modules/sax": {
+			"version": "1.2.4",
+			"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+			"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
+		},
 		"node_modules/saxes": {
 			"version": "5.0.1",
 			"resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz",
@@ -9315,7 +9574,6 @@
 			"version": "2.4.11",
 			"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
 			"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
-			"dev": true,
 			"dependencies": {
 				"inherits": "^2.0.1",
 				"safe-buffer": "^5.0.1"
@@ -10119,7 +10377,6 @@
 			"version": "6.0.0",
 			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
 			"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
-			"dev": true,
 			"dependencies": {
 				"ansi-regex": "^5.0.0"
 			},
@@ -10339,6 +10596,25 @@
 				"node": ">=8"
 			}
 		},
+		"node_modules/thenify": {
+			"version": "3.3.1",
+			"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
+			"integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
+			"dependencies": {
+				"any-promise": "^1.0.0"
+			}
+		},
+		"node_modules/thenify-all": {
+			"version": "1.6.0",
+			"resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
+			"integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=",
+			"dependencies": {
+				"thenify": ">= 3.1.0 < 4"
+			},
+			"engines": {
+				"node": ">=0.8"
+			}
+		},
 		"node_modules/throat": {
 			"version": "5.0.0",
 			"resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz",
@@ -10776,6 +11052,230 @@
 				"is-typedarray": "^1.0.0"
 			}
 		},
+		"node_modules/typeorm": {
+			"version": "0.2.37",
+			"resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.2.37.tgz",
+			"integrity": "sha512-7rkW0yCgFC24I5T0f3S/twmLSuccPh1SQmxET/oDWn2sSDVzbyWdnItSdKy27CdJGTlKHYtUVeOcMYw5LRsXVw==",
+			"dependencies": {
+				"@sqltools/formatter": "^1.2.2",
+				"app-root-path": "^3.0.0",
+				"buffer": "^6.0.3",
+				"chalk": "^4.1.0",
+				"cli-highlight": "^2.1.11",
+				"debug": "^4.3.1",
+				"dotenv": "^8.2.0",
+				"glob": "^7.1.6",
+				"js-yaml": "^4.0.0",
+				"mkdirp": "^1.0.4",
+				"reflect-metadata": "^0.1.13",
+				"sha.js": "^2.4.11",
+				"tslib": "^2.1.0",
+				"xml2js": "^0.4.23",
+				"yargonaut": "^1.1.4",
+				"yargs": "^17.0.1",
+				"zen-observable-ts": "^1.0.0"
+			},
+			"bin": {
+				"typeorm": "cli.js"
+			},
+			"funding": {
+				"url": "https://opencollective.com/typeorm"
+			},
+			"peerDependencies": {
+				"@sap/hana-client": "*",
+				"better-sqlite3": "*",
+				"hdb-pool": "*",
+				"ioredis": "*",
+				"mongodb": "^3.6.0",
+				"mssql": "*",
+				"mysql2": "*",
+				"oracledb": "*",
+				"pg": "*",
+				"pg-native": "*",
+				"pg-query-stream": "*",
+				"redis": "*",
+				"sql.js": "*",
+				"sqlite3": "*",
+				"typeorm-aurora-data-api-driver": "*"
+			},
+			"peerDependenciesMeta": {
+				"@sap/hana-client": {
+					"optional": true
+				},
+				"better-sqlite3": {
+					"optional": true
+				},
+				"hdb-pool": {
+					"optional": true
+				},
+				"ioredis": {
+					"optional": true
+				},
+				"mongodb": {
+					"optional": true
+				},
+				"mssql": {
+					"optional": true
+				},
+				"mysql2": {
+					"optional": true
+				},
+				"oracledb": {
+					"optional": true
+				},
+				"pg": {
+					"optional": true
+				},
+				"pg-native": {
+					"optional": true
+				},
+				"pg-query-stream": {
+					"optional": true
+				},
+				"redis": {
+					"optional": true
+				},
+				"sql.js": {
+					"optional": true
+				},
+				"sqlite3": {
+					"optional": true
+				},
+				"typeorm-aurora-data-api-driver": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/typeorm/node_modules/argparse": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+			"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
+		},
+		"node_modules/typeorm/node_modules/buffer": {
+			"version": "6.0.3",
+			"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+			"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+			"funding": [
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/feross"
+				},
+				{
+					"type": "patreon",
+					"url": "https://www.patreon.com/feross"
+				},
+				{
+					"type": "consulting",
+					"url": "https://feross.org/support"
+				}
+			],
+			"dependencies": {
+				"base64-js": "^1.3.1",
+				"ieee754": "^1.2.1"
+			}
+		},
+		"node_modules/typeorm/node_modules/cliui": {
+			"version": "7.0.4",
+			"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+			"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+			"dependencies": {
+				"string-width": "^4.2.0",
+				"strip-ansi": "^6.0.0",
+				"wrap-ansi": "^7.0.0"
+			}
+		},
+		"node_modules/typeorm/node_modules/is-fullwidth-code-point": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+			"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/typeorm/node_modules/js-yaml": {
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+			"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+			"dependencies": {
+				"argparse": "^2.0.1"
+			},
+			"bin": {
+				"js-yaml": "bin/js-yaml.js"
+			}
+		},
+		"node_modules/typeorm/node_modules/mkdirp": {
+			"version": "1.0.4",
+			"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+			"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+			"bin": {
+				"mkdirp": "bin/cmd.js"
+			},
+			"engines": {
+				"node": ">=10"
+			}
+		},
+		"node_modules/typeorm/node_modules/string-width": {
+			"version": "4.2.2",
+			"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
+			"integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
+			"dependencies": {
+				"emoji-regex": "^8.0.0",
+				"is-fullwidth-code-point": "^3.0.0",
+				"strip-ansi": "^6.0.0"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/typeorm/node_modules/wrap-ansi": {
+			"version": "7.0.0",
+			"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+			"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+			"dependencies": {
+				"ansi-styles": "^4.0.0",
+				"string-width": "^4.1.0",
+				"strip-ansi": "^6.0.0"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+			}
+		},
+		"node_modules/typeorm/node_modules/y18n": {
+			"version": "5.0.8",
+			"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+			"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+			"engines": {
+				"node": ">=10"
+			}
+		},
+		"node_modules/typeorm/node_modules/yargs": {
+			"version": "17.1.1",
+			"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.1.1.tgz",
+			"integrity": "sha512-c2k48R0PwKIqKhPMWjeiF6y2xY/gPMUlro0sgxqXpbOIohWiLNXWslsootttv7E1e73QPAMQSg5FeySbVcpsPQ==",
+			"dependencies": {
+				"cliui": "^7.0.2",
+				"escalade": "^3.1.1",
+				"get-caller-file": "^2.0.5",
+				"require-directory": "^2.1.1",
+				"string-width": "^4.2.0",
+				"y18n": "^5.0.5",
+				"yargs-parser": "^20.2.2"
+			},
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/typeorm/node_modules/yargs-parser": {
+			"version": "20.2.9",
+			"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+			"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
+			"engines": {
+				"node": ">=10"
+			}
+		},
 		"node_modules/typescript": {
 			"version": "4.3.5",
 			"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
@@ -11274,6 +11774,26 @@
 			"integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==",
 			"dev": true
 		},
+		"node_modules/xml2js": {
+			"version": "0.4.23",
+			"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
+			"integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
+			"dependencies": {
+				"sax": ">=0.6.0",
+				"xmlbuilder": "~11.0.0"
+			},
+			"engines": {
+				"node": ">=4.0.0"
+			}
+		},
+		"node_modules/xmlbuilder": {
+			"version": "11.0.1",
+			"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
+			"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
+			"engines": {
+				"node": ">=4.0"
+			}
+		},
 		"node_modules/xmlchars": {
 			"version": "2.2.0",
 			"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
@@ -11299,6 +11819,66 @@
 			"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
 			"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
 		},
+		"node_modules/yargonaut": {
+			"version": "1.1.4",
+			"resolved": "https://registry.npmjs.org/yargonaut/-/yargonaut-1.1.4.tgz",
+			"integrity": "sha512-rHgFmbgXAAzl+1nngqOcwEljqHGG9uUZoPjsdZEs1w5JW9RXYzrSvH/u70C1JE5qFi0qjsdhnUX/dJRpWqitSA==",
+			"dependencies": {
+				"chalk": "^1.1.1",
+				"figlet": "^1.1.1",
+				"parent-require": "^1.0.0"
+			}
+		},
+		"node_modules/yargonaut/node_modules/ansi-regex": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+			"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/yargonaut/node_modules/ansi-styles": {
+			"version": "2.2.1",
+			"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+			"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/yargonaut/node_modules/chalk": {
+			"version": "1.1.3",
+			"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+			"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+			"dependencies": {
+				"ansi-styles": "^2.2.1",
+				"escape-string-regexp": "^1.0.2",
+				"has-ansi": "^2.0.0",
+				"strip-ansi": "^3.0.0",
+				"supports-color": "^2.0.0"
+			},
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/yargonaut/node_modules/strip-ansi": {
+			"version": "3.0.1",
+			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+			"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+			"dependencies": {
+				"ansi-regex": "^2.0.0"
+			},
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/yargonaut/node_modules/supports-color": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+			"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+			"engines": {
+				"node": ">=0.8.0"
+			}
+		},
 		"node_modules/yargs": {
 			"version": "15.4.1",
 			"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
@@ -11366,6 +11946,20 @@
 				"node": ">=6"
 			}
 		},
+		"node_modules/zen-observable": {
+			"version": "0.8.15",
+			"resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz",
+			"integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ=="
+		},
+		"node_modules/zen-observable-ts": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz",
+			"integrity": "sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA==",
+			"dependencies": {
+				"@types/zen-observable": "0.8.3",
+				"zen-observable": "0.8.15"
+			}
+		},
 		"node_modules/zip-stream": {
 			"version": "4.1.0",
 			"resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz",
@@ -11884,9 +12478,9 @@
 				"jsonwebtoken": "^8.5.1",
 				"missing-native-js-functions": "^1.2.10",
 				"node-fetch": "^2.6.1",
+				"patch-package": "^6.4.7",
 				"reflect-metadata": "^0.1.13",
 				"sqlite3": "^5.0.2",
-				"ts-transform-json-schema": "^2.0.3",
 				"typeorm": "^0.2.37",
 				"typescript": "^4.3.5",
 				"typescript-json-schema": "^0.50.1"
@@ -12227,6 +12821,11 @@
 				"@sinonjs/commons": "^1.7.0"
 			}
 		},
+		"@sqltools/formatter": {
+			"version": "1.2.3",
+			"resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.3.tgz",
+			"integrity": "sha512-O3uyB/JbkAEMZaP3YqyHH7TMnex7tWyCbCI4EfJdOCoN6HIhqdJBWTM6aCCiWQ/5f5wxjgU735QAIpJbjDvmzg=="
+		},
 		"@tootallnate/once": {
 			"version": "1.1.2",
 			"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
@@ -12391,6 +12990,82 @@
 				"@types/istanbul-lib-report": "*"
 			}
 		},
+		"@types/jest": {
+			"version": "27.0.1",
+			"resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.0.1.tgz",
+			"integrity": "sha512-HTLpVXHrY69556ozYkcq47TtQJXpcWAWfkoqz+ZGz2JnmZhzlRjprCIyFnetSy8gpDWwTTGBcRVv1J1I1vBrHw==",
+			"dev": true,
+			"requires": {
+				"jest-diff": "^27.0.0",
+				"pretty-format": "^27.0.0"
+			},
+			"dependencies": {
+				"@jest/types": {
+					"version": "27.0.6",
+					"resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz",
+					"integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==",
+					"dev": true,
+					"requires": {
+						"@types/istanbul-lib-coverage": "^2.0.0",
+						"@types/istanbul-reports": "^3.0.0",
+						"@types/node": "*",
+						"@types/yargs": "^16.0.0",
+						"chalk": "^4.0.0"
+					}
+				},
+				"@types/yargs": {
+					"version": "16.0.4",
+					"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz",
+					"integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==",
+					"dev": true,
+					"requires": {
+						"@types/yargs-parser": "*"
+					}
+				},
+				"ansi-styles": {
+					"version": "5.2.0",
+					"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+					"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+					"dev": true
+				},
+				"diff-sequences": {
+					"version": "27.0.6",
+					"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz",
+					"integrity": "sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==",
+					"dev": true
+				},
+				"jest-diff": {
+					"version": "27.0.6",
+					"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.0.6.tgz",
+					"integrity": "sha512-Z1mqgkTCSYaFgwTlP/NUiRzdqgxmmhzHY1Tq17zL94morOHfHu3K4bgSgl+CR4GLhpV8VxkuOYuIWnQ9LnFqmg==",
+					"dev": true,
+					"requires": {
+						"chalk": "^4.0.0",
+						"diff-sequences": "^27.0.6",
+						"jest-get-type": "^27.0.6",
+						"pretty-format": "^27.0.6"
+					}
+				},
+				"jest-get-type": {
+					"version": "27.0.6",
+					"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz",
+					"integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==",
+					"dev": true
+				},
+				"pretty-format": {
+					"version": "27.0.6",
+					"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz",
+					"integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==",
+					"dev": true,
+					"requires": {
+						"@jest/types": "^27.0.6",
+						"ansi-regex": "^5.0.0",
+						"ansi-styles": "^5.0.0",
+						"react-is": "^17.0.1"
+					}
+				}
+			}
+		},
 		"@types/jsonwebtoken": {
 			"version": "8.5.4",
 			"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.4.tgz",
@@ -12534,6 +13209,11 @@
 			"integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==",
 			"dev": true
 		},
+		"@types/zen-observable": {
+			"version": "0.8.3",
+			"resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.3.tgz",
+			"integrity": "sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw=="
+		},
 		"@zerollup/ts-helpers": {
 			"version": "1.7.18",
 			"resolved": "https://registry.npmjs.org/@zerollup/ts-helpers/-/ts-helpers-1.7.18.tgz",
@@ -12721,8 +13401,7 @@
 		"ansi-regex": {
 			"version": "5.0.0",
 			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
-			"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
-			"dev": true
+			"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
 		},
 		"ansi-styles": {
 			"version": "4.3.0",
@@ -12738,6 +13417,11 @@
 			"integrity": "sha1-vgiVmQl7dKXJxKhKDNvNtivYeu8=",
 			"dev": true
 		},
+		"any-promise": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+			"integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8="
+		},
 		"anymatch": {
 			"version": "3.1.2",
 			"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
@@ -12748,6 +13432,11 @@
 				"picomatch": "^2.0.4"
 			}
 		},
+		"app-root-path": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz",
+			"integrity": "sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw=="
+		},
 		"append-field": {
 			"version": "1.0.0",
 			"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
@@ -13102,8 +13791,7 @@
 		"base64-js": {
 			"version": "1.5.1",
 			"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
-			"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
-			"dev": true
+			"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
 		},
 		"bcrypt": {
 			"version": "5.0.1",
@@ -13797,6 +14485,85 @@
 				}
 			}
 		},
+		"cli-highlight": {
+			"version": "2.1.11",
+			"resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz",
+			"integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==",
+			"requires": {
+				"chalk": "^4.0.0",
+				"highlight.js": "^10.7.1",
+				"mz": "^2.4.0",
+				"parse5": "^5.1.1",
+				"parse5-htmlparser2-tree-adapter": "^6.0.0",
+				"yargs": "^16.0.0"
+			},
+			"dependencies": {
+				"cliui": {
+					"version": "7.0.4",
+					"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+					"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+					"requires": {
+						"string-width": "^4.2.0",
+						"strip-ansi": "^6.0.0",
+						"wrap-ansi": "^7.0.0"
+					}
+				},
+				"is-fullwidth-code-point": {
+					"version": "3.0.0",
+					"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+					"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
+				},
+				"parse5": {
+					"version": "5.1.1",
+					"resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
+					"integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug=="
+				},
+				"string-width": {
+					"version": "4.2.2",
+					"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
+					"integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
+					"requires": {
+						"emoji-regex": "^8.0.0",
+						"is-fullwidth-code-point": "^3.0.0",
+						"strip-ansi": "^6.0.0"
+					}
+				},
+				"wrap-ansi": {
+					"version": "7.0.0",
+					"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+					"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+					"requires": {
+						"ansi-styles": "^4.0.0",
+						"string-width": "^4.1.0",
+						"strip-ansi": "^6.0.0"
+					}
+				},
+				"y18n": {
+					"version": "5.0.8",
+					"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+					"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
+				},
+				"yargs": {
+					"version": "16.2.0",
+					"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+					"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
+					"requires": {
+						"cliui": "^7.0.2",
+						"escalade": "^3.1.1",
+						"get-caller-file": "^2.0.5",
+						"require-directory": "^2.1.1",
+						"string-width": "^4.2.0",
+						"y18n": "^5.0.5",
+						"yargs-parser": "^20.2.2"
+					}
+				},
+				"yargs-parser": {
+					"version": "20.2.9",
+					"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+					"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="
+				}
+			}
+		},
 		"cliui": {
 			"version": "6.0.0",
 			"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
@@ -14824,8 +15591,7 @@
 		"emoji-regex": {
 			"version": "8.0.0",
 			"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-			"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
-			"dev": true
+			"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
 		},
 		"encodeurl": {
 			"version": "1.0.2",
@@ -14869,8 +15635,7 @@
 		"escalade": {
 			"version": "3.1.1",
 			"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
-			"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
-			"dev": true
+			"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
 		},
 		"escape-html": {
 			"version": "1.0.3",
@@ -14880,8 +15645,7 @@
 		"escape-string-regexp": {
 			"version": "1.0.5",
 			"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-			"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
-			"dev": true
+			"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
 		},
 		"escodegen": {
 			"version": "2.0.0",
@@ -15298,6 +16062,11 @@
 				"bser": "2.1.1"
 			}
 		},
+		"figlet": {
+			"version": "1.5.2",
+			"resolved": "https://registry.npmjs.org/figlet/-/figlet-1.5.2.tgz",
+			"integrity": "sha512-WOn21V8AhyE1QqVfPIVxe3tupJacq1xGkPTB4iagT6o+P2cAgEOOwIxMftr4+ZCTI6d551ij9j61DFr0nsP2uQ=="
+		},
 		"fill-range": {
 			"version": "7.0.1",
 			"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -15470,8 +16239,7 @@
 		"get-caller-file": {
 			"version": "2.0.5",
 			"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
-			"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
-			"dev": true
+			"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
 		},
 		"get-package-type": {
 			"version": "0.1.0",
@@ -15562,7 +16330,6 @@
 			"version": "2.0.0",
 			"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
 			"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
-			"dev": true,
 			"requires": {
 				"ansi-regex": "^2.0.0"
 			},
@@ -15570,8 +16337,7 @@
 				"ansi-regex": {
 					"version": "2.1.1",
 					"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
-					"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
-					"dev": true
+					"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
 				}
 			}
 		},
@@ -15676,6 +16442,11 @@
 			"resolved": "https://registry.npmjs.org/helmet/-/helmet-4.6.0.tgz",
 			"integrity": "sha512-HVqALKZlR95ROkrnesdhbbZJFi/rIVSoNq6f3jA/9u6MIbTsPh3xZwihjeI5+DO/2sOV6HMHooXcEOuwskHpTg=="
 		},
+		"highlight.js": {
+			"version": "10.7.3",
+			"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
+			"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="
+		},
 		"hmac-drbg": {
 			"version": "1.0.1",
 			"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
@@ -15830,8 +16601,7 @@
 		"ieee754": {
 			"version": "1.2.1",
 			"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
-			"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
-			"dev": true
+			"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
 		},
 		"ignore": {
 			"version": "5.1.8",
@@ -17453,6 +18223,16 @@
 			"integrity": "sha512-nU7mOEuaXiQIB/EgTIjYZJ7g8KqMm2D8l4qp+DqA4jxWOb/tnb1KEoqp+tlbdQIDIAiC1i7j7X/3yHDFXLxr9g==",
 			"dev": true
 		},
+		"mz": {
+			"version": "2.7.0",
+			"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
+			"integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
+			"requires": {
+				"any-promise": "^1.0.0",
+				"object-assign": "^4.0.1",
+				"thenify-all": "^1.0.0"
+			}
+		},
 		"nanoassert": {
 			"version": "1.1.0",
 			"resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-1.1.0.tgz",
@@ -17936,6 +18716,11 @@
 			"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
 			"dev": true
 		},
+		"parent-require": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/parent-require/-/parent-require-1.0.0.tgz",
+			"integrity": "sha1-dGoWdjgIOoYLDu9nMssn7UbDKXc="
+		},
 		"parents": {
 			"version": "1.0.1",
 			"resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz",
@@ -18491,6 +19276,11 @@
 				"picomatch": "^2.2.1"
 			}
 		},
+		"reflect-metadata": {
+			"version": "0.1.13",
+			"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
+			"integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg=="
+		},
 		"regenerator-runtime": {
 			"version": "0.13.9",
 			"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
@@ -18532,8 +19322,7 @@
 		"require-directory": {
 			"version": "2.1.1",
 			"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
-			"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
-			"dev": true
+			"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
 		},
 		"require-from-string": {
 			"version": "2.0.2",
@@ -18884,6 +19673,11 @@
 				"sparse-bitfield": "^3.0.3"
 			}
 		},
+		"sax": {
+			"version": "1.2.4",
+			"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+			"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
+		},
 		"saxes": {
 			"version": "5.0.1",
 			"resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz",
@@ -18994,7 +19788,6 @@
 			"version": "2.4.11",
 			"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
 			"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
-			"dev": true,
 			"requires": {
 				"inherits": "^2.0.1",
 				"safe-buffer": "^5.0.1"
@@ -19699,7 +20492,6 @@
 			"version": "6.0.0",
 			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
 			"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
-			"dev": true,
 			"requires": {
 				"ansi-regex": "^5.0.0"
 			}
@@ -19864,6 +20656,22 @@
 				"minimatch": "^3.0.4"
 			}
 		},
+		"thenify": {
+			"version": "3.3.1",
+			"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
+			"integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
+			"requires": {
+				"any-promise": "^1.0.0"
+			}
+		},
+		"thenify-all": {
+			"version": "1.6.0",
+			"resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
+			"integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=",
+			"requires": {
+				"thenify": ">= 3.1.0 < 4"
+			}
+		},
 		"throat": {
 			"version": "5.0.0",
 			"resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz",
@@ -20207,6 +21015,118 @@
 				"is-typedarray": "^1.0.0"
 			}
 		},
+		"typeorm": {
+			"version": "0.2.37",
+			"resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.2.37.tgz",
+			"integrity": "sha512-7rkW0yCgFC24I5T0f3S/twmLSuccPh1SQmxET/oDWn2sSDVzbyWdnItSdKy27CdJGTlKHYtUVeOcMYw5LRsXVw==",
+			"requires": {
+				"@sqltools/formatter": "^1.2.2",
+				"app-root-path": "^3.0.0",
+				"buffer": "^6.0.3",
+				"chalk": "^4.1.0",
+				"cli-highlight": "^2.1.11",
+				"debug": "^4.3.1",
+				"dotenv": "^8.2.0",
+				"glob": "^7.1.6",
+				"js-yaml": "^4.0.0",
+				"mkdirp": "^1.0.4",
+				"reflect-metadata": "^0.1.13",
+				"sha.js": "^2.4.11",
+				"tslib": "^2.1.0",
+				"xml2js": "^0.4.23",
+				"yargonaut": "^1.1.4",
+				"yargs": "^17.0.1",
+				"zen-observable-ts": "^1.0.0"
+			},
+			"dependencies": {
+				"argparse": {
+					"version": "2.0.1",
+					"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+					"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
+				},
+				"buffer": {
+					"version": "6.0.3",
+					"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+					"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+					"requires": {
+						"base64-js": "^1.3.1",
+						"ieee754": "^1.2.1"
+					}
+				},
+				"cliui": {
+					"version": "7.0.4",
+					"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+					"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+					"requires": {
+						"string-width": "^4.2.0",
+						"strip-ansi": "^6.0.0",
+						"wrap-ansi": "^7.0.0"
+					}
+				},
+				"is-fullwidth-code-point": {
+					"version": "3.0.0",
+					"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+					"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
+				},
+				"js-yaml": {
+					"version": "4.1.0",
+					"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+					"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+					"requires": {
+						"argparse": "^2.0.1"
+					}
+				},
+				"mkdirp": {
+					"version": "1.0.4",
+					"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+					"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
+				},
+				"string-width": {
+					"version": "4.2.2",
+					"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
+					"integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
+					"requires": {
+						"emoji-regex": "^8.0.0",
+						"is-fullwidth-code-point": "^3.0.0",
+						"strip-ansi": "^6.0.0"
+					}
+				},
+				"wrap-ansi": {
+					"version": "7.0.0",
+					"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+					"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+					"requires": {
+						"ansi-styles": "^4.0.0",
+						"string-width": "^4.1.0",
+						"strip-ansi": "^6.0.0"
+					}
+				},
+				"y18n": {
+					"version": "5.0.8",
+					"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+					"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
+				},
+				"yargs": {
+					"version": "17.1.1",
+					"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.1.1.tgz",
+					"integrity": "sha512-c2k48R0PwKIqKhPMWjeiF6y2xY/gPMUlro0sgxqXpbOIohWiLNXWslsootttv7E1e73QPAMQSg5FeySbVcpsPQ==",
+					"requires": {
+						"cliui": "^7.0.2",
+						"escalade": "^3.1.1",
+						"get-caller-file": "^2.0.5",
+						"require-directory": "^2.1.1",
+						"string-width": "^4.2.0",
+						"y18n": "^5.0.5",
+						"yargs-parser": "^20.2.2"
+					}
+				},
+				"yargs-parser": {
+					"version": "20.2.9",
+					"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+					"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="
+				}
+			}
+		},
 		"typescript": {
 			"version": "4.3.5",
 			"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
@@ -20623,6 +21543,20 @@
 			"integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==",
 			"dev": true
 		},
+		"xml2js": {
+			"version": "0.4.23",
+			"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
+			"integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
+			"requires": {
+				"sax": ">=0.6.0",
+				"xmlbuilder": "~11.0.0"
+			}
+		},
+		"xmlbuilder": {
+			"version": "11.0.1",
+			"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
+			"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="
+		},
 		"xmlchars": {
 			"version": "2.2.0",
 			"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
@@ -20645,6 +21579,53 @@
 			"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
 			"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
 		},
+		"yargonaut": {
+			"version": "1.1.4",
+			"resolved": "https://registry.npmjs.org/yargonaut/-/yargonaut-1.1.4.tgz",
+			"integrity": "sha512-rHgFmbgXAAzl+1nngqOcwEljqHGG9uUZoPjsdZEs1w5JW9RXYzrSvH/u70C1JE5qFi0qjsdhnUX/dJRpWqitSA==",
+			"requires": {
+				"chalk": "^1.1.1",
+				"figlet": "^1.1.1",
+				"parent-require": "^1.0.0"
+			},
+			"dependencies": {
+				"ansi-regex": {
+					"version": "2.1.1",
+					"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+					"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+				},
+				"ansi-styles": {
+					"version": "2.2.1",
+					"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+					"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
+				},
+				"chalk": {
+					"version": "1.1.3",
+					"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+					"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+					"requires": {
+						"ansi-styles": "^2.2.1",
+						"escape-string-regexp": "^1.0.2",
+						"has-ansi": "^2.0.0",
+						"strip-ansi": "^3.0.0",
+						"supports-color": "^2.0.0"
+					}
+				},
+				"strip-ansi": {
+					"version": "3.0.1",
+					"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+					"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+					"requires": {
+						"ansi-regex": "^2.0.0"
+					}
+				},
+				"supports-color": {
+					"version": "2.0.0",
+					"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+					"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
+				}
+			}
+		},
 		"yargs": {
 			"version": "15.4.1",
 			"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
@@ -20699,6 +21680,20 @@
 			"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
 			"dev": true
 		},
+		"zen-observable": {
+			"version": "0.8.15",
+			"resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz",
+			"integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ=="
+		},
+		"zen-observable-ts": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz",
+			"integrity": "sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA==",
+			"requires": {
+				"@types/zen-observable": "0.8.3",
+				"zen-observable": "0.8.15"
+			}
+		},
 		"zip-stream": {
 			"version": "4.1.0",
 			"resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz",
diff --git a/api/package.json b/api/package.json
index 7b2de011..1310d577 100644
--- a/api/package.json
+++ b/api/package.json
@@ -5,7 +5,7 @@
 	"main": "dist/Server.js",
 	"types": "dist/Server.d.ts",
 	"scripts": {
-		"test": "jest",
+		"test": "npm run build && jest",
 		"test:watch": "jest --watch",
 		"start": "npm run build && node dist/start",
 		"build": "npx tsc -b .",
@@ -35,6 +35,7 @@
 		"@types/bcrypt": "^5.0.0",
 		"@types/express": "^4.17.9",
 		"@types/i18next-node-fs-backend": "^2.1.0",
+		"@types/jest": "^27.0.1",
 		"@types/jsonwebtoken": "^8.5.0",
 		"@types/mongodb": "^3.6.9",
 		"@types/mongoose": "^5.10.5",
@@ -79,6 +80,7 @@
 		"mongoose-autopopulate": "^0.12.3",
 		"mongoose-long": "^0.3.2",
 		"multer": "^1.4.2",
-		"node-fetch": "^2.6.1"
+		"node-fetch": "^2.6.1",
+		"typeorm": "^0.2.37"
 	}
 }
diff --git a/api/scripts/setup_test.js b/api/scripts/setup_test.js
new file mode 100644
index 00000000..4b692f7c
--- /dev/null
+++ b/api/scripts/setup_test.js
@@ -0,0 +1 @@
+// TODO: start api
diff --git a/api/src/middlewares/ErrorHandler.ts b/api/src/middlewares/ErrorHandler.ts
index d080e498..8e2cd923 100644
--- a/api/src/middlewares/ErrorHandler.ts
+++ b/api/src/middlewares/ErrorHandler.ts
@@ -2,6 +2,7 @@ import { NextFunction, Request, Response } from "express";
 import { HTTPError } from "lambert-server";
 import { FieldError } from "../util/instanceOf";
 
+// TODO: update with new body/typorm validation
 export function ErrorHandler(error: Error, req: Request, res: Response, next: NextFunction) {
 	if (!error) next();
 
diff --git a/api/src/routes/auth/login.ts b/api/src/routes/auth/login.ts
index 579a097e..c0acad4e 100644
--- a/api/src/routes/auth/login.ts
+++ b/api/src/routes/auth/login.ts
@@ -21,9 +21,6 @@ router.post(
 	async (req: Request, res: Response) => {
 		const { login, password, captcha_key, undelete } = req.body;
 		const email = adjustEmail(login);
-		const query: any[] = [{ phone: login }];
-		if (email) query.push({ email });
-
 		console.log(req.body, email);
 
 		const config = Config.get();
@@ -41,11 +38,10 @@ router.post(
 			// TODO: check captcha
 		}
 
-		const user = await User.findOneOrFail(
-			{ $or: query },
-			{ "data.hash": true, id: true, disabled: true, deleted: true, "settings.locale": true, "settings.theme": true }
-		).catch((e) => {
-			console.log(e, query);
+		const user = await User.findOneOrFail({
+			where: [{ phone: login }, { email: login }],
+			select: ["data", "id", "disabled", "deleted", "settings"]
+		}).catch((e) => {
 			throw FieldErrors({ login: { message: req.t("auth:login.INVALID_LOGIN"), code: "INVALID_LOGIN" } });
 		});
 
diff --git a/api/src/routes/auth/register.ts b/api/src/routes/auth/register.ts
index 1405e219..62b039d5 100644
--- a/api/src/routes/auth/register.ts
+++ b/api/src/routes/auth/register.ts
@@ -1,12 +1,12 @@
 import { Request, Response, Router } from "express";
-import { trimSpecial, User, Snowflake, User, Config } from "@fosscord/util";
+import { trimSpecial, User, Snowflake, Config } from "@fosscord/util";
 import bcrypt from "bcrypt";
 import { check, Email, EMAIL_REGEX, FieldErrors, Length } from "../../util/instanceOf";
 import "missing-native-js-functions";
 import { generateToken } from "./login";
 import { getIpAdress, IPAnalysis, isProxy } from "../../util/ipAddress";
 import { HTTPError } from "lambert-server";
-import RateLimit from "../../middlewares/RateLimit";
+import { In } from "typeorm";
 
 const router: Router = Router();
 
@@ -55,13 +55,13 @@ router.post(
 		// TODO: check password strength
 
 		// adjusted_email will be slightly modified version of the user supplied email -> e.g. protection against GMail Trick
-		let adjusted_email: string | null = adjustEmail(email);
+		let adjusted_email = adjustEmail(email);
 
 		// adjusted_password will be the hash of the password
-		let adjusted_password: string = "";
+		let adjusted_password = "";
 
 		// trim special uf8 control characters -> Backspace, Newline, ...
-		let adjusted_username: string = trimSpecial(username);
+		let adjusted_username = trimSpecial(username);
 
 		// discriminator will be randomly generated
 		let discriminator = "";
@@ -129,7 +129,7 @@ router.post(
 
 		if (!register.allowMultipleAccounts) {
 			// TODO: check if fingerprint was eligible generated
-			const exists = await User.findOneOrFail({ fingerprints: fingerprint }).catch((e) => {});
+			const exists = await User.findOne({ where: { fingerprints: In(fingerprint) } });
 
 			if (exists) {
 				throw FieldErrors({
@@ -164,12 +164,8 @@ router.post(
 		// TODO: is there any better way to generate a random discriminator only once, without checking if it already exists in the mongodb database?
 		for (let tries = 0; tries < 5; tries++) {
 			discriminator = Math.randomIntBetween(1, 9999).toString().padStart(4, "0");
-			try {
-				exists = await User.findOneOrFail({ discriminator, username: adjusted_username }, "id");
-			} catch (error) {
-				// doesn't exist -> break
-				break;
-			}
+			exists = await User.findOne({ where: { discriminator, username: adjusted_username }, select: ["id"] });
+			if (!exists) break;
 		}
 
 		if (exists) {
@@ -185,35 +181,26 @@ router.post(
 		// appearently discord doesn't save the date of birth and just calculate if nsfw is allowed
 		// if nsfw_allowed is null/undefined it'll require date_of_birth to set it to true/false
 
-		const user: User = {
+		const user = await new User({
 			id: Snowflake.generate(),
 			created_at: new Date(),
 			username: adjusted_username,
 			discriminator,
-			avatar: null,
-			accent_color: null,
-			banner: null,
+			avatar: undefined,
+			accent_color: undefined,
+			banner: undefined,
 			bot: false,
 			system: false,
 			desktop: false,
 			mobile: false,
 			premium: true,
 			premium_type: 2,
-			phone: null,
+			phone: undefined,
 			bio: "",
 			mfa_enabled: false,
 			verified: false,
 			disabled: false,
 			deleted: false,
-			presence: {
-				activities: [],
-				client_status: {
-					desktop: undefined,
-					mobile: undefined,
-					web: undefined
-				},
-				status: "offline"
-			},
 			email: adjusted_email,
 			nsfw_allowed: true, // TODO: depending on age
 			public_flags: 0n,
@@ -221,10 +208,7 @@ router.post(
 			guilds: [],
 			data: {
 				hash: adjusted_password,
-				valid_tokens_since: new Date(),
-				relationships: [],
-				connected_accounts: [],
-				fingerprints: []
+				valid_tokens_since: new Date()
 			},
 			settings: {
 				afk_timeout: 300,
@@ -234,10 +218,10 @@ router.post(
 				contact_sync_enabled: false,
 				convert_emoticons: false,
 				custom_status: {
-					emoji_id: null,
-					emoji_name: null,
-					expires_at: null,
-					text: null
+					emoji_id: undefined,
+					emoji_name: undefined,
+					expires_at: undefined,
+					text: undefined
 				},
 				default_guilds_restricted: false,
 				detect_platform_accounts: true,
@@ -265,16 +249,13 @@ router.post(
 				timezone_offset: 0
 				// timezone_offset: // TODO: timezone from request
 			}
-		};
-
-		// insert user into database
-		await new User(user).save();
+		}).save();
 
 		return res.json({ token: await generateToken(user.id) });
 	}
 );
 
-export function adjustEmail(email: string): string | null {
+export function adjustEmail(email: string): string | undefined {
 	// body parser already checked if it is a valid email
 	const parts = <RegExpMatchArray>email.match(EMAIL_REGEX);
 	// @ts-ignore
diff --git a/api/src/routes/guilds/#guild_id/channels.ts b/api/src/routes/guilds/#guild_id/channels.ts
index b53c9a5a..7b0e94b6 100644
--- a/api/src/routes/guilds/#guild_id/channels.ts
+++ b/api/src/routes/guilds/#guild_id/channels.ts
@@ -1,5 +1,5 @@
 import { Router, Response, Request } from "express";
-import { Channel, toObject, ChannelUpdateEvent, getPermission, emitEvent } from "@fosscord/util";
+import { Channel, ChannelUpdateEvent, getPermission, emitEvent } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { ChannelModifySchema } from "../../../schema/Channel";
 
@@ -48,15 +48,19 @@ router.patch(
 
 				if (x.parent_id) {
 					opts.parent_id = x.parent_id;
-					const parent_channel = await Channel.findOneOrFail({ id: x.parent_id, guild_id }, { permission_overwrites: true });
+					const parent_channel = await Channel.findOneOrFail({
+						where: { id: x.parent_id, guild_id },
+						select: ["permission_overwrites"]
+					});
 					if (x.lock_permissions) {
 						opts.permission_overwrites = parent_channel.permission_overwrites;
 					}
 				}
 
-				const channel = await Channel.findOneOrFailAndUpdate({ id: x.id, guild_id }, opts, { new: true });
+				await Channel.update({ guild_id, id: x.id }, opts);
+				const channel = await Channel.findOneOrFail({ guild_id, id: x.id });
 
-				await emitEvent({ event: "CHANNEL_UPDATE", data: channel), channel_id: x.id, guild_id } as ChannelUpdateEvent;
+				await emitEvent({ event: "CHANNEL_UPDATE", data: channel, channel_id: x.id, guild_id } as ChannelUpdateEvent);
 			})
 		]);
 
diff --git a/api/src/routes/guilds/#guild_id/templates.ts b/api/src/routes/guilds/#guild_id/templates.ts
index 13917dbd..e1d2f5fd 100644
--- a/api/src/routes/guilds/#guild_id/templates.ts
+++ b/api/src/routes/guilds/#guild_id/templates.ts
@@ -1,5 +1,5 @@
 import { Request, Response, Router } from "express";
-import { TemplateModel, Guild, getPermission, toObject, User, Snowflake } from "@fosscord/util";
+import { Guild, getPermission, Template } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { TemplateCreateSchema, TemplateModifySchema } from "../../../schema/Template";
 import { check } from "../../../util/instanceOf";
@@ -7,22 +7,22 @@ import { generateCode } from "../../../util/String";
 
 const router: Router = Router();
 
-const TemplateGuildProjection = {
-	name: true,
-	description: true,
-	region: true,
-	verification_level: true,
-	default_message_notifications: true,
-	explicit_content_filter: true,
-	preferred_locale: true,
-	afk_timeout: true,
-	roles: true,
-	channels: true,
-	afk_channel_id: true,
-	system_channel_id: true,
-	system_channel_flags: true,
-	icon_hash: true
-};
+const TemplateGuildProjection: (keyof Guild)[] = [
+	"name",
+	"description",
+	"region",
+	"verification_level",
+	"default_message_notifications",
+	"explicit_content_filter",
+	"preferred_locale",
+	"afk_timeout",
+	"roles",
+	"channels",
+	"afk_channel_id",
+	"system_channel_id",
+	"system_channel_flags",
+	"icon"
+];
 
 router.get("/", async (req: Request, res: Response) => {
 	const { guild_id } = req.params;
@@ -34,14 +34,14 @@ router.get("/", async (req: Request, res: Response) => {
 
 router.post("/", check(TemplateCreateSchema), async (req: Request, res: Response) => {
 	const { guild_id } = req.params;
-	const guild = await Guild.findOneOrFail({ id: guild_id }, TemplateGuildProjection);
+	const guild = await Guild.findOneOrFail({ where: { id: guild_id }, select: TemplateGuildProjection });
 	const perms = await getPermission(req.user_id, guild_id);
 	perms.hasThrow("MANAGE_GUILD");
 
 	const exists = await Template.findOneOrFail({ id: guild_id }).catch((e) => {});
 	if (exists) throw new HTTPError("Template already exists", 400);
 
-	const template = await new TemplateModel({
+	const template = await new Template({
 		...req.body,
 		code: generateCode(),
 		creator_id: req.user_id,
@@ -51,7 +51,7 @@ router.post("/", check(TemplateCreateSchema), async (req: Request, res: Response
 		serialized_source_guild: guild
 	}).save();
 
-	res.json(template)).send(;
+	res.json(template);
 });
 
 router.delete("/:code", async (req: Request, res: Response) => {
@@ -61,37 +61,39 @@ router.delete("/:code", async (req: Request, res: Response) => {
 	const perms = await getPermission(req.user_id, guild_id);
 	perms.hasThrow("MANAGE_GUILD");
 
-	const template = await Template.findOneOrFailAndDelete({
+	const template = await Template.delete({
 		code
 	});
 
-	res.send(template);
+	res.json(template);
 });
 
 router.put("/:code", async (req: Request, res: Response) => {
-	const guild_id = req.params.guild_id;
-	const { code } = req.params;
+	// synchronizes the template
+	const { code, guild_id } = req.params;
 
-	const guild = await Guild.findOneOrFail({ id: guild_id }, TemplateGuildProjection);
+	const guild = await Guild.findOneOrFail({ where: { id: guild_id }, select: TemplateGuildProjection });
 
 	const perms = await getPermission(req.user_id, guild_id);
 	perms.hasThrow("MANAGE_GUILD");
 
-	const template = await Template.findOneOrFailAndUpdate({ code }, { serialized_source_guild: guild }, { new: true });
+	const template = await new Template({ code, serialized_source_guild: guild }).save();
 
-	res.json(template)).send(;
+	res.json(template);
 });
 
 router.patch("/:code", check(TemplateModifySchema), async (req: Request, res: Response) => {
+	// updates the template description
 	const { guild_id } = req.params;
 	const { code } = req.params;
+	const { name, description } = req.body;
 
 	const perms = await getPermission(req.user_id, guild_id);
 	perms.hasThrow("MANAGE_GUILD");
 
-	const template = await Template.findOneOrFailAndUpdate({ code }, { name: req.body.name, description: req.body.description }, { new: true });
+	const template = await new Template({ code, name: name, description: description }).save();
 
-	res.json(template)).send(;
+	res.json(template);
 });
 
 export default router;
diff --git a/api/src/routes/guilds/templates/index.ts b/api/src/routes/guilds/templates/index.ts
index ad8b676b..b8c1012d 100644
--- a/api/src/routes/guilds/templates/index.ts
+++ b/api/src/routes/guilds/templates/index.ts
@@ -1,9 +1,8 @@
 import { Request, Response, Router } from "express";
 const router: Router = Router();
-import { TemplateModel, Guild, toObject, User, Role, Snowflake, Guild, Config } from "@fosscord/util";
+import { Template, Guild, Role, Snowflake, Config, User } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { GuildTemplateCreateSchema } from "../../../schema/Guild";
-import { getPublicUser } from "../../../util/User";
 import { check } from "../../../util/instanceOf";
 import { addMember } from "../../../util/Member";
 
@@ -12,7 +11,7 @@ router.get("/:code", async (req: Request, res: Response) => {
 
 	const template = await Template.findOneOrFail({ code: code });
 
-	res.json(template)).send(;
+	res.json(template);
 });
 
 router.post("/:code", check(GuildTemplateCreateSchema), async (req: Request, res: Response) => {
@@ -20,7 +19,7 @@ router.post("/:code", check(GuildTemplateCreateSchema), async (req: Request, res
 	const body = req.body as GuildTemplateCreateSchema;
 
 	const { maxGuilds } = Config.get().limits.user;
-	const user = await getPublicUser(req.user_id, { guilds: true });
+	const user = await User.getPublicUser(req.user_id, { guilds: true });
 
 	if (user.guilds.length >= maxGuilds) {
 		throw new HTTPError(`Maximum number of guilds reached ${maxGuilds}`, 403);
diff --git a/api/src/routes/invites/index.ts b/api/src/routes/invites/index.ts
index e871af86..a488c44b 100644
--- a/api/src/routes/invites/index.ts
+++ b/api/src/routes/invites/index.ts
@@ -1,5 +1,5 @@
 import { Router, Request, Response } from "express";
-import { getPermission, Guild, InviteModel, toObject } from "@fosscord/util";
+import { getPermission, Guild, Invite } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { addMember } from "../../util/Member";
 const router: Router = Router();
@@ -40,7 +40,7 @@ router.delete("/:code", async (req: Request, res: Response) => {
 
 	await Guild.update({ vanity_url_code: code }, { $unset: { vanity_url_code: 1 } }).catch((e) => {});
 
-	res.status(200).send({ invite: invite) };
+	res.json({ invite: invite });
 });
 
 export default router;
diff --git a/api/src/routes/users/#id/profile.ts b/api/src/routes/users/#id/profile.ts
index 46c96698..9b2e2d5e 100644
--- a/api/src/routes/users/#id/profile.ts
+++ b/api/src/routes/users/#id/profile.ts
@@ -7,7 +7,7 @@ router.get("/", async (req: Request, res: Response) => {
 	const user = await getPublicUser(req.params.id, { data: true });
 
 	res.json({
-		connected_accounts: user.data.connected_accounts,
+		connected_accounts: user.connected_accounts,
 		premium_guild_since: null, // TODO
 		premium_since: null, // TODO
 		user: {
diff --git a/api/src/routes/users/@me/relationships.ts b/api/src/routes/users/@me/relationships.ts
index 9b8d6199..8c7469ed 100644
--- a/api/src/routes/users/@me/relationships.ts
+++ b/api/src/routes/users/@me/relationships.ts
@@ -15,14 +15,14 @@ import { check, Length } from "../../../util/instanceOf";
 
 const router = Router();
 
-const userProjection = { "user_data.relationships": true, ...PublicUserProjection };
+const userProjection = { "data.relationships": true, ...PublicUserProjection };
 
 router.get("/", async (req: Request, res: Response) => {
-	const user = await User.findOneOrFail({ id: req.user_id }, { user_data: { relationships: true } }).populate({
-		path: "user_data.relationships.id",
+	const user = await User.findOneOrFail({ id: req.user_id }, { data: { relationships: true } }).populate({
+		path: "data.relationships.id",
 		model: User
 	});
-	return res.json(user.user_data.relationships);
+	return res.json(user.data.relationships);
 });
 
 async function addRelationship(req: Request, res: Response, friend: UserDocument, type: RelationshipType) {
@@ -30,8 +30,8 @@ async function addRelationship(req: Request, res: Response, friend: UserDocument
 	if (id === req.user_id) throw new HTTPError("You can't add yourself as a friend");
 
 	const user = await User.findOneOrFail({ id: req.user_id }, userProjection);
-	const newUserRelationships = [...user.user_data.relationships];
-	const newFriendRelationships = [...friend.user_data.relationships];
+	const newUserRelationships = [...user.data.relationships];
+	const newFriendRelationships = [...friend.data.relationships];
 
 	var relationship = newUserRelationships.find((x) => x.id === id);
 	const friendRequest = newFriendRelationships.find((x) => x.id === req.user_id);
@@ -48,7 +48,7 @@ async function addRelationship(req: Request, res: Response, friend: UserDocument
 		if (friendRequest && friendRequest.type !== RelationshipType.blocked) {
 			newFriendRelationships.remove(friendRequest);
 			await Promise.all([
-				User.update({ id: friend.id }, { "user_data.relationships": newFriendRelationships }),
+				User.update({ id: friend.id }, { "data.relationships": newFriendRelationships }),
 				emitEvent({
 					event: "RELATIONSHIP_REMOVE",
 					data: friendRequest,
@@ -58,12 +58,12 @@ async function addRelationship(req: Request, res: Response, friend: UserDocument
 		}
 
 		await Promise.all([
-			User.update({ id: req.user_id }, { "user_data.relationships": newUserRelationships }),
+			User.update({ id: req.user_id }, { "data.relationships": newUserRelationships }),
 			emitEvent({
 				event: "RELATIONSHIP_ADD",
 				data: {
 					...relationship,
-					user: { ...friend, user_data: undefined }
+					user: { ...friend, data: undefined }
 				},
 				user_id: req.user_id
 			} as RelationshipAddEvent)
@@ -91,13 +91,13 @@ async function addRelationship(req: Request, res: Response, friend: UserDocument
 	} else newUserRelationships.push(outgoing_relationship);
 
 	await Promise.all([
-		User.update({ id: req.user_id }, { "user_data.relationships": newUserRelationships }),
-		User.update({ id: friend.id }, { "user_data.relationships": newFriendRelationships }),
+		User.update({ id: req.user_id }, { "data.relationships": newUserRelationships }),
+		User.update({ id: friend.id }, { "data.relationships": newFriendRelationships }),
 		emitEvent({
 			event: "RELATIONSHIP_ADD",
 			data: {
 				...outgoing_relationship,
-				user: { ...friend, user_data: undefined }
+				user: { ...friend, data: undefined }
 			},
 			user_id: req.user_id
 		} as RelationshipAddEvent),
@@ -106,7 +106,7 @@ async function addRelationship(req: Request, res: Response, friend: UserDocument
 			data: {
 				...incoming_relationship,
 				should_notify: true,
-				user: { ...user, user_data: undefined }
+				user: { ...user, data: undefined }
 			},
 			user_id: id
 		} as RelationshipAddEvent)
@@ -138,11 +138,11 @@ router.delete("/:id", async (req: Request, res: Response) => {
 	const friend = await User.findOneOrFail({ id }, userProjection);
 	if (!friend) throw new HTTPError("User not found", 404);
 
-	const relationship = user.user_data.relationships.find((x) => x.id === id);
-	const friendRequest = friend.user_data.relationships.find((x) => x.id === req.user_id);
+	const relationship = user.data.relationships.find((x) => x.id === id);
+	const friendRequest = friend.data.relationships.find((x) => x.id === req.user_id);
 	if (relationship?.type === RelationshipType.blocked) {
 		// unblock user
-		user.user_data.relationships.remove(relationship);
+		user.data.relationships.remove(relationship);
 
 		await Promise.all([
 			user.save(),
@@ -153,8 +153,8 @@ router.delete("/:id", async (req: Request, res: Response) => {
 	if (!relationship || !friendRequest) throw new HTTPError("You are not friends with the user", 404);
 	if (friendRequest.type === RelationshipType.blocked) throw new HTTPError("The user blocked you");
 
-	user.user_data.relationships.remove(relationship);
-	friend.user_data.relationships.remove(friendRequest);
+	user.data.relationships.remove(relationship);
+	friend.data.relationships.remove(friendRequest);
 
 	await Promise.all([
 		user.save(),
diff --git a/api/src/util/Channel.ts b/api/src/util/Channel.ts
index a618d2df..f518aefd 100644
--- a/api/src/util/Channel.ts
+++ b/api/src/util/Channel.ts
@@ -57,7 +57,7 @@ export async function createChannel(
 		recipient_ids: null
 	}).save();
 
-	await emitEvent({ event: "CHANNEL_CREATE", data: channel), guild_id: channel.guild_id } as ChannelCreateEvent;
+	await emitEvent({ event: "CHANNEL_CREATE", data: channel, guild_id: channel.guild_id } as ChannelCreateEvent);
 
 	return channel;
 }
diff --git a/api/src/util/User.ts b/api/src/util/User.ts
deleted file mode 100644
index 4d9065c4..00000000
--- a/api/src/util/User.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { toObject, User, PublicUserProjection } from "@fosscord/util";
-import { HTTPError } from "lambert-server";
-
-export { PublicUserProjection };
-
-export async function getPublicUser(user_id: string, additional_fields?: any) {
-	const user = await User.findOneOrFail(
-		{ id: user_id },
-		{
-			...PublicUserProjection,
-			...additional_fields
-		}
-	);
-	if (!user) throw new HTTPError("User not found", 404);
-	return user;
-}
diff --git a/api/tests/routes/auth/login.ts b/api/tests/routes/auth/login.ts
new file mode 100644
index 00000000..e1938b36
--- /dev/null
+++ b/api/tests/routes/auth/login.ts
@@ -0,0 +1 @@
+test("works", () => {});