summary refs log tree commit diff
diff options
context:
space:
mode:
authorFlam3rboy <34555296+Flam3rboy@users.noreply.github.com>2021-08-27 11:11:16 +0200
committerFlam3rboy <34555296+Flam3rboy@users.noreply.github.com>2021-08-27 11:11:16 +0200
commitc21c3428217d25c058a6fb9fe40bcfdc1cc1e1c1 (patch)
tree67f8265ba004ea5d576311f582c98d8a00676c2f
parent:construction: api (diff)
downloadserver-c21c3428217d25c058a6fb9fe40bcfdc1cc1e1c1.tar.xz
:construction: typeorm
-rw-r--r--gateway/src/opcodes/Identify.ts2
-rw-r--r--util/package-lock.json845
-rw-r--r--util/package.json1
-rw-r--r--util/patches/test-performance+1.1.3.patch381
-rw-r--r--util/src/entities/BaseClass.ts17
-rw-r--r--util/src/entities/Config.ts2
-rw-r--r--util/src/entities/ReadState.ts4
-rw-r--r--util/src/entities/Template.ts7
-rw-r--r--util/src/entities/User.ts4
-rw-r--r--util/src/entities/schema.json543
-rw-r--r--util/src/util/Config.ts19
-rw-r--r--util/src/util/Database.ts14
-rw-r--r--util/src/util/checkToken.ts7
-rw-r--r--util/src/util/index.ts10
-rw-r--r--util/src/util/toBigInt.ts4
-rw-r--r--util/tests/User.test.js31
-rw-r--r--util/tests/validate.test.js16
-rw-r--r--util/util/Config.ts290
18 files changed, 1465 insertions, 732 deletions
diff --git a/gateway/src/opcodes/Identify.ts b/gateway/src/opcodes/Identify.ts
index 464d584c..644d0984 100644
--- a/gateway/src/opcodes/Identify.ts
+++ b/gateway/src/opcodes/Identify.ts
@@ -106,7 +106,7 @@ export async function onIdentify(this: WebSocket, data: Payload) {
 		}),
 		guild_experiments: [], // TODO
 		geo_ordered_rtc_regions: [], // TODO
-		relationships: user.user_data.relationships,
+		relationships: user.data.relationships,
 		read_state: {
 			// TODO
 			entries: [],
diff --git a/util/package-lock.json b/util/package-lock.json
index 0ecdaea9..f30fcf47 100644
--- a/util/package-lock.json
+++ b/util/package-lock.json
@@ -16,6 +16,7 @@
 				"dot-prop": "^6.0.1",
 				"env-paths": "^2.2.1",
 				"jsonwebtoken": "^8.5.1",
+				"lambert-server": "^1.2.8",
 				"missing-native-js-functions": "^1.2.10",
 				"node-fetch": "^2.6.1",
 				"patch-package": "^6.4.7",
@@ -1256,6 +1257,18 @@
 			"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
 			"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
 		},
+		"node_modules/accepts": {
+			"version": "1.3.7",
+			"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
+			"integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
+			"dependencies": {
+				"mime-types": "~2.1.24",
+				"negotiator": "0.6.2"
+			},
+			"engines": {
+				"node": ">= 0.6"
+			}
+		},
 		"node_modules/agent-base": {
 			"version": "6.0.2",
 			"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
@@ -1413,6 +1426,11 @@
 			"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
 			"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
 		},
+		"node_modules/array-flatten": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+			"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+		},
 		"node_modules/asn1": {
 			"version": "0.2.4",
 			"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
@@ -1594,6 +1612,34 @@
 			"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
 			"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
 		},
+		"node_modules/body-parser": {
+			"version": "1.19.0",
+			"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
+			"integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
+			"dependencies": {
+				"bytes": "3.1.0",
+				"content-type": "~1.0.4",
+				"debug": "2.6.9",
+				"depd": "~1.1.2",
+				"http-errors": "1.7.2",
+				"iconv-lite": "0.4.24",
+				"on-finished": "~2.3.0",
+				"qs": "6.7.0",
+				"raw-body": "2.4.0",
+				"type-is": "~1.6.17"
+			},
+			"engines": {
+				"node": ">= 0.8"
+			}
+		},
+		"node_modules/body-parser/node_modules/qs": {
+			"version": "6.7.0",
+			"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+			"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
+			"engines": {
+				"node": ">=0.6"
+			}
+		},
 		"node_modules/brace-expansion": {
 			"version": "1.1.11",
 			"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -1719,6 +1765,14 @@
 			"resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz",
 			"integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg=="
 		},
+		"node_modules/bytes": {
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+			"integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
+			"engines": {
+				"node": ">= 0.8"
+			}
+		},
 		"node_modules/call-bind": {
 			"version": "1.0.2",
 			"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
@@ -1933,6 +1987,30 @@
 			"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
 			"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
 		},
+		"node_modules/content-disposition": {
+			"version": "0.5.3",
+			"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
+			"integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
+			"dependencies": {
+				"safe-buffer": "5.1.2"
+			},
+			"engines": {
+				"node": ">= 0.6"
+			}
+		},
+		"node_modules/content-disposition/node_modules/safe-buffer": {
+			"version": "5.1.2",
+			"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+			"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+		},
+		"node_modules/content-type": {
+			"version": "1.0.4",
+			"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+			"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
+			"engines": {
+				"node": ">= 0.6"
+			}
+		},
 		"node_modules/convert-source-map": {
 			"version": "1.8.0",
 			"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
@@ -1948,6 +2026,19 @@
 			"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
 			"dev": true
 		},
+		"node_modules/cookie": {
+			"version": "0.4.0",
+			"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
+			"integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==",
+			"engines": {
+				"node": ">= 0.6"
+			}
+		},
+		"node_modules/cookie-signature": {
+			"version": "1.0.6",
+			"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+			"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+		},
 		"node_modules/core-util-is": {
 			"version": "1.0.2",
 			"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
@@ -2066,6 +2157,19 @@
 				"node": ">=0.10"
 			}
 		},
+		"node_modules/depd": {
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+			"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
+			"engines": {
+				"node": ">= 0.6"
+			}
+		},
+		"node_modules/destroy": {
+			"version": "1.0.4",
+			"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+			"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
+		},
 		"node_modules/detect-libc": {
 			"version": "1.0.3",
 			"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
@@ -2134,6 +2238,11 @@
 				"safe-buffer": "^5.0.1"
 			}
 		},
+		"node_modules/ee-first": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+			"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+		},
 		"node_modules/electron-to-chromium": {
 			"version": "1.3.814",
 			"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.814.tgz",
@@ -2157,6 +2266,14 @@
 			"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
 			"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
 		},
+		"node_modules/encodeurl": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+			"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
+			"engines": {
+				"node": ">= 0.8"
+			}
+		},
 		"node_modules/env-paths": {
 			"version": "2.2.1",
 			"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
@@ -2225,6 +2342,11 @@
 				"node": ">=6"
 			}
 		},
+		"node_modules/escape-html": {
+			"version": "1.0.3",
+			"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+			"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+		},
 		"node_modules/escape-string-regexp": {
 			"version": "1.0.5",
 			"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
@@ -2255,6 +2377,14 @@
 				"node": ">=0.10.0"
 			}
 		},
+		"node_modules/etag": {
+			"version": "1.8.1",
+			"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+			"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
+			"engines": {
+				"node": ">= 0.6"
+			}
+		},
 		"node_modules/exit": {
 			"version": "0.1.2",
 			"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
@@ -2264,6 +2394,67 @@
 				"node": ">= 0.8.0"
 			}
 		},
+		"node_modules/express": {
+			"version": "4.17.1",
+			"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
+			"integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
+			"dependencies": {
+				"accepts": "~1.3.7",
+				"array-flatten": "1.1.1",
+				"body-parser": "1.19.0",
+				"content-disposition": "0.5.3",
+				"content-type": "~1.0.4",
+				"cookie": "0.4.0",
+				"cookie-signature": "1.0.6",
+				"debug": "2.6.9",
+				"depd": "~1.1.2",
+				"encodeurl": "~1.0.2",
+				"escape-html": "~1.0.3",
+				"etag": "~1.8.1",
+				"finalhandler": "~1.1.2",
+				"fresh": "0.5.2",
+				"merge-descriptors": "1.0.1",
+				"methods": "~1.1.2",
+				"on-finished": "~2.3.0",
+				"parseurl": "~1.3.3",
+				"path-to-regexp": "0.1.7",
+				"proxy-addr": "~2.0.5",
+				"qs": "6.7.0",
+				"range-parser": "~1.2.1",
+				"safe-buffer": "5.1.2",
+				"send": "0.17.1",
+				"serve-static": "1.14.1",
+				"setprototypeof": "1.1.1",
+				"statuses": "~1.5.0",
+				"type-is": "~1.6.18",
+				"utils-merge": "1.0.1",
+				"vary": "~1.1.2"
+			},
+			"engines": {
+				"node": ">= 0.10.0"
+			}
+		},
+		"node_modules/express-async-errors": {
+			"version": "3.1.1",
+			"resolved": "https://registry.npmjs.org/express-async-errors/-/express-async-errors-3.1.1.tgz",
+			"integrity": "sha512-h6aK1da4tpqWSbyCa3FxB/V6Ehd4EEB15zyQq9qe75OZBp0krinNKuH4rAY+S/U/2I36vdLAUFSjQJ+TFmODng==",
+			"peerDependencies": {
+				"express": "^4.16.2"
+			}
+		},
+		"node_modules/express/node_modules/qs": {
+			"version": "6.7.0",
+			"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+			"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
+			"engines": {
+				"node": ">=0.6"
+			}
+		},
+		"node_modules/express/node_modules/safe-buffer": {
+			"version": "5.1.2",
+			"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+			"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+		},
 		"node_modules/extend": {
 			"version": "3.0.2",
 			"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
@@ -2324,6 +2515,23 @@
 				"node": ">=8"
 			}
 		},
+		"node_modules/finalhandler": {
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+			"integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+			"dependencies": {
+				"debug": "2.6.9",
+				"encodeurl": "~1.0.2",
+				"escape-html": "~1.0.3",
+				"on-finished": "~2.3.0",
+				"parseurl": "~1.3.3",
+				"statuses": "~1.5.0",
+				"unpipe": "~1.0.0"
+			},
+			"engines": {
+				"node": ">= 0.8"
+			}
+		},
 		"node_modules/find-yarn-workspace-root": {
 			"version": "2.0.0",
 			"resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz",
@@ -2366,6 +2574,22 @@
 				"node": ">= 6"
 			}
 		},
+		"node_modules/forwarded": {
+			"version": "0.2.0",
+			"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+			"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+			"engines": {
+				"node": ">= 0.6"
+			}
+		},
+		"node_modules/fresh": {
+			"version": "0.5.2",
+			"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+			"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
+			"engines": {
+				"node": ">= 0.6"
+			}
+		},
 		"node_modules/fs-extra": {
 			"version": "7.0.1",
 			"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
@@ -2706,6 +2930,14 @@
 			"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
 			"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
 		},
+		"node_modules/helmet": {
+			"version": "4.6.0",
+			"resolved": "https://registry.npmjs.org/helmet/-/helmet-4.6.0.tgz",
+			"integrity": "sha512-HVqALKZlR95ROkrnesdhbbZJFi/rIVSoNq6f3jA/9u6MIbTsPh3xZwihjeI5+DO/2sOV6HMHooXcEOuwskHpTg==",
+			"engines": {
+				"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",
@@ -2720,6 +2952,26 @@
 			"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
 			"dev": true
 		},
+		"node_modules/http-errors": {
+			"version": "1.7.2",
+			"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
+			"integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
+			"dependencies": {
+				"depd": "~1.1.2",
+				"inherits": "2.0.3",
+				"setprototypeof": "1.1.1",
+				"statuses": ">= 1.5.0 < 2",
+				"toidentifier": "1.0.0"
+			},
+			"engines": {
+				"node": ">= 0.6"
+			}
+		},
+		"node_modules/http-errors/node_modules/inherits": {
+			"version": "2.0.3",
+			"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+			"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+		},
 		"node_modules/http-proxy-agent": {
 			"version": "4.0.1",
 			"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
@@ -2899,6 +3151,14 @@
 				"node": ">= 0.4"
 			}
 		},
+		"node_modules/ipaddr.js": {
+			"version": "1.9.1",
+			"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+			"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+			"engines": {
+				"node": ">= 0.10"
+			}
+		},
 		"node_modules/is-bigint": {
 			"version": "1.0.4",
 			"resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
@@ -5837,6 +6097,19 @@
 				"node": ">=6"
 			}
 		},
+		"node_modules/lambert-server": {
+			"version": "1.2.8",
+			"resolved": "https://registry.npmjs.org/lambert-server/-/lambert-server-1.2.8.tgz",
+			"integrity": "sha512-vi/Ku/QudY+WIdGO9bc0qLfVhfuJFWXk1+etesPW1vW29sPbmevLL6IwfvCtw+/MyzRAJLOyCBfQ310a68+2QQ==",
+			"dependencies": {
+				"body-parser": "^1.19.0",
+				"chalk": "^4.1.1",
+				"express": "^4.17.1",
+				"express-async-errors": "^3.1.1",
+				"helmet": "^4.4.1",
+				"missing-native-js-functions": "^1.1.8"
+			}
+		},
 		"node_modules/leven": {
 			"version": "3.1.0",
 			"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
@@ -5937,6 +6210,14 @@
 				"tmpl": "1.0.x"
 			}
 		},
+		"node_modules/media-typer": {
+			"version": "0.3.0",
+			"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+			"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
+			"engines": {
+				"node": ">= 0.6"
+			}
+		},
 		"node_modules/memory-pager": {
 			"version": "1.5.0",
 			"resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
@@ -5944,12 +6225,25 @@
 			"optional": true,
 			"peer": true
 		},
+		"node_modules/merge-descriptors": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+			"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
+		},
 		"node_modules/merge-stream": {
 			"version": "2.0.0",
 			"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
 			"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
 			"dev": true
 		},
+		"node_modules/methods": {
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+			"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
+			"engines": {
+				"node": ">= 0.6"
+			}
+		},
 		"node_modules/micromatch": {
 			"version": "4.0.4",
 			"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
@@ -5962,11 +6256,21 @@
 				"node": ">=8.6"
 			}
 		},
+		"node_modules/mime": {
+			"version": "1.6.0",
+			"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+			"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+			"bin": {
+				"mime": "cli.js"
+			},
+			"engines": {
+				"node": ">=4"
+			}
+		},
 		"node_modules/mime-db": {
 			"version": "1.49.0",
 			"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz",
 			"integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==",
-			"devOptional": true,
 			"engines": {
 				"node": ">= 0.6"
 			}
@@ -5975,7 +6279,6 @@
 			"version": "2.1.32",
 			"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz",
 			"integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==",
-			"devOptional": true,
 			"dependencies": {
 				"mime-db": "1.49.0"
 			},
@@ -6131,6 +6434,14 @@
 			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
 			"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
 		},
+		"node_modules/negotiator": {
+			"version": "0.6.2",
+			"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
+			"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
+			"engines": {
+				"node": ">= 0.6"
+			}
+		},
 		"node_modules/nice-try": {
 			"version": "1.0.5",
 			"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
@@ -6477,6 +6788,17 @@
 				"url": "https://github.com/sponsors/ljharb"
 			}
 		},
+		"node_modules/on-finished": {
+			"version": "2.3.0",
+			"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+			"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+			"dependencies": {
+				"ee-first": "1.1.1"
+			},
+			"engines": {
+				"node": ">= 0.8"
+			}
+		},
 		"node_modules/once": {
 			"version": "1.4.0",
 			"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -6620,6 +6942,14 @@
 			"resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
 			"integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="
 		},
+		"node_modules/parseurl": {
+			"version": "1.3.3",
+			"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+			"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+			"engines": {
+				"node": ">= 0.8"
+			}
+		},
 		"node_modules/patch-package": {
 			"version": "6.4.7",
 			"resolved": "https://registry.npmjs.org/patch-package/-/patch-package-6.4.7.tgz",
@@ -6724,6 +7054,11 @@
 			"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
 			"dev": true
 		},
+		"node_modules/path-to-regexp": {
+			"version": "0.1.7",
+			"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+			"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+		},
 		"node_modules/performance-now": {
 			"version": "2.1.0",
 			"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
@@ -6841,6 +7176,18 @@
 				"node": ">= 6"
 			}
 		},
+		"node_modules/proxy-addr": {
+			"version": "2.0.7",
+			"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+			"integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+			"dependencies": {
+				"forwarded": "0.2.0",
+				"ipaddr.js": "1.9.1"
+			},
+			"engines": {
+				"node": ">= 0.10"
+			}
+		},
 		"node_modules/psl": {
 			"version": "1.8.0",
 			"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
@@ -6869,6 +7216,28 @@
 			"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
 			"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
 		},
+		"node_modules/range-parser": {
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+			"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+			"engines": {
+				"node": ">= 0.6"
+			}
+		},
+		"node_modules/raw-body": {
+			"version": "2.4.0",
+			"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
+			"integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
+			"dependencies": {
+				"bytes": "3.1.0",
+				"http-errors": "1.7.2",
+				"iconv-lite": "0.4.24",
+				"unpipe": "1.0.0"
+			},
+			"engines": {
+				"node": ">= 0.8"
+			}
+		},
 		"node_modules/rc": {
 			"version": "1.2.8",
 			"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
@@ -7082,11 +7451,58 @@
 				"semver": "bin/semver"
 			}
 		},
+		"node_modules/send": {
+			"version": "0.17.1",
+			"resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
+			"integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
+			"dependencies": {
+				"debug": "2.6.9",
+				"depd": "~1.1.2",
+				"destroy": "~1.0.4",
+				"encodeurl": "~1.0.2",
+				"escape-html": "~1.0.3",
+				"etag": "~1.8.1",
+				"fresh": "0.5.2",
+				"http-errors": "~1.7.2",
+				"mime": "1.6.0",
+				"ms": "2.1.1",
+				"on-finished": "~2.3.0",
+				"range-parser": "~1.2.1",
+				"statuses": "~1.5.0"
+			},
+			"engines": {
+				"node": ">= 0.8.0"
+			}
+		},
+		"node_modules/send/node_modules/ms": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+			"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+		},
+		"node_modules/serve-static": {
+			"version": "1.14.1",
+			"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
+			"integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
+			"dependencies": {
+				"encodeurl": "~1.0.2",
+				"escape-html": "~1.0.3",
+				"parseurl": "~1.3.3",
+				"send": "0.17.1"
+			},
+			"engines": {
+				"node": ">= 0.8.0"
+			}
+		},
 		"node_modules/set-blocking": {
 			"version": "2.0.0",
 			"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
 			"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
 		},
+		"node_modules/setprototypeof": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
+			"integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
+		},
 		"node_modules/sha.js": {
 			"version": "2.4.11",
 			"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
@@ -7240,6 +7656,14 @@
 				"node": ">=0.10.0"
 			}
 		},
+		"node_modules/statuses": {
+			"version": "1.5.0",
+			"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+			"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
+			"engines": {
+				"node": ">= 0.6"
+			}
+		},
 		"node_modules/string_decoder": {
 			"version": "0.10.31",
 			"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
@@ -7445,6 +7869,14 @@
 				"node": ">=8.0"
 			}
 		},
+		"node_modules/toidentifier": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
+			"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
+			"engines": {
+				"node": ">=0.6"
+			}
+		},
 		"node_modules/tough-cookie": {
 			"version": "2.5.0",
 			"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
@@ -7514,6 +7946,18 @@
 				"url": "https://github.com/sponsors/sindresorhus"
 			}
 		},
+		"node_modules/type-is": {
+			"version": "1.6.18",
+			"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+			"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+			"dependencies": {
+				"media-typer": "0.3.0",
+				"mime-types": "~2.1.24"
+			},
+			"engines": {
+				"node": ">= 0.6"
+			}
+		},
 		"node_modules/typedarray-to-buffer": {
 			"version": "3.1.5",
 			"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
@@ -7746,6 +8190,14 @@
 				"node": ">= 4.0.0"
 			}
 		},
+		"node_modules/unpipe": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+			"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
+			"engines": {
+				"node": ">= 0.8"
+			}
+		},
 		"node_modules/uri-js": {
 			"version": "4.4.1",
 			"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -7786,6 +8238,14 @@
 				"url": "https://github.com/sponsors/ljharb"
 			}
 		},
+		"node_modules/utils-merge": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+			"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
+			"engines": {
+				"node": ">= 0.4.0"
+			}
+		},
 		"node_modules/uuid": {
 			"version": "3.4.0",
 			"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
@@ -7827,6 +8287,14 @@
 				"node": ">= 0.10"
 			}
 		},
+		"node_modules/vary": {
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+			"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
+			"engines": {
+				"node": ">= 0.8"
+			}
+		},
 		"node_modules/verror": {
 			"version": "1.10.0",
 			"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
@@ -9140,6 +9608,15 @@
 			"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
 			"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
 		},
+		"accepts": {
+			"version": "1.3.7",
+			"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
+			"integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
+			"requires": {
+				"mime-types": "~2.1.24",
+				"negotiator": "0.6.2"
+			}
+		},
 		"agent-base": {
 			"version": "6.0.2",
 			"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
@@ -9271,6 +9748,11 @@
 			"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
 			"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
 		},
+		"array-flatten": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+			"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+		},
 		"asn1": {
 			"version": "0.2.4",
 			"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
@@ -9427,6 +9909,30 @@
 			"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
 			"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
 		},
+		"body-parser": {
+			"version": "1.19.0",
+			"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
+			"integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
+			"requires": {
+				"bytes": "3.1.0",
+				"content-type": "~1.0.4",
+				"debug": "2.6.9",
+				"depd": "~1.1.2",
+				"http-errors": "1.7.2",
+				"iconv-lite": "0.4.24",
+				"on-finished": "~2.3.0",
+				"qs": "6.7.0",
+				"raw-body": "2.4.0",
+				"type-is": "~1.6.17"
+			},
+			"dependencies": {
+				"qs": {
+					"version": "6.7.0",
+					"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+					"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
+				}
+			}
+		},
 		"brace-expansion": {
 			"version": "1.1.11",
 			"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -9524,6 +10030,11 @@
 			"resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz",
 			"integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg=="
 		},
+		"bytes": {
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+			"integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
+		},
 		"call-bind": {
 			"version": "1.0.2",
 			"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
@@ -9695,6 +10206,26 @@
 			"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
 			"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
 		},
+		"content-disposition": {
+			"version": "0.5.3",
+			"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
+			"integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
+			"requires": {
+				"safe-buffer": "5.1.2"
+			},
+			"dependencies": {
+				"safe-buffer": {
+					"version": "5.1.2",
+					"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+					"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+				}
+			}
+		},
+		"content-type": {
+			"version": "1.0.4",
+			"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+			"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
+		},
 		"convert-source-map": {
 			"version": "1.8.0",
 			"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
@@ -9712,6 +10243,16 @@
 				}
 			}
 		},
+		"cookie": {
+			"version": "0.4.0",
+			"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
+			"integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
+		},
+		"cookie-signature": {
+			"version": "1.0.6",
+			"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+			"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+		},
 		"core-util-is": {
 			"version": "1.0.2",
 			"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
@@ -9809,6 +10350,16 @@
 			"optional": true,
 			"peer": true
 		},
+		"depd": {
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+			"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
+		},
+		"destroy": {
+			"version": "1.0.4",
+			"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+			"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
+		},
 		"detect-libc": {
 			"version": "1.0.3",
 			"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
@@ -9856,6 +10407,11 @@
 				"safe-buffer": "^5.0.1"
 			}
 		},
+		"ee-first": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+			"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+		},
 		"electron-to-chromium": {
 			"version": "1.3.814",
 			"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.814.tgz",
@@ -9873,6 +10429,11 @@
 			"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
 			"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
 		},
+		"encodeurl": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+			"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
+		},
 		"env-paths": {
 			"version": "2.2.1",
 			"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
@@ -9923,6 +10484,11 @@
 			"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
 			"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
 		},
+		"escape-html": {
+			"version": "1.0.3",
+			"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+			"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+		},
 		"escape-string-regexp": {
 			"version": "1.0.5",
 			"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
@@ -9940,12 +10506,72 @@
 			"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
 			"dev": true
 		},
+		"etag": {
+			"version": "1.8.1",
+			"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+			"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
+		},
 		"exit": {
 			"version": "0.1.2",
 			"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
 			"integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
 			"dev": true
 		},
+		"express": {
+			"version": "4.17.1",
+			"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
+			"integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
+			"requires": {
+				"accepts": "~1.3.7",
+				"array-flatten": "1.1.1",
+				"body-parser": "1.19.0",
+				"content-disposition": "0.5.3",
+				"content-type": "~1.0.4",
+				"cookie": "0.4.0",
+				"cookie-signature": "1.0.6",
+				"debug": "2.6.9",
+				"depd": "~1.1.2",
+				"encodeurl": "~1.0.2",
+				"escape-html": "~1.0.3",
+				"etag": "~1.8.1",
+				"finalhandler": "~1.1.2",
+				"fresh": "0.5.2",
+				"merge-descriptors": "1.0.1",
+				"methods": "~1.1.2",
+				"on-finished": "~2.3.0",
+				"parseurl": "~1.3.3",
+				"path-to-regexp": "0.1.7",
+				"proxy-addr": "~2.0.5",
+				"qs": "6.7.0",
+				"range-parser": "~1.2.1",
+				"safe-buffer": "5.1.2",
+				"send": "0.17.1",
+				"serve-static": "1.14.1",
+				"setprototypeof": "1.1.1",
+				"statuses": "~1.5.0",
+				"type-is": "~1.6.18",
+				"utils-merge": "1.0.1",
+				"vary": "~1.1.2"
+			},
+			"dependencies": {
+				"qs": {
+					"version": "6.7.0",
+					"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+					"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
+				},
+				"safe-buffer": {
+					"version": "5.1.2",
+					"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+					"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+				}
+			}
+		},
+		"express-async-errors": {
+			"version": "3.1.1",
+			"resolved": "https://registry.npmjs.org/express-async-errors/-/express-async-errors-3.1.1.tgz",
+			"integrity": "sha512-h6aK1da4tpqWSbyCa3FxB/V6Ehd4EEB15zyQq9qe75OZBp0krinNKuH4rAY+S/U/2I36vdLAUFSjQJ+TFmODng==",
+			"requires": {}
+		},
 		"extend": {
 			"version": "3.0.2",
 			"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
@@ -9997,6 +10623,20 @@
 				"to-regex-range": "^5.0.1"
 			}
 		},
+		"finalhandler": {
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+			"integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+			"requires": {
+				"debug": "2.6.9",
+				"encodeurl": "~1.0.2",
+				"escape-html": "~1.0.3",
+				"on-finished": "~2.3.0",
+				"parseurl": "~1.3.3",
+				"statuses": "~1.5.0",
+				"unpipe": "~1.0.0"
+			}
+		},
 		"find-yarn-workspace-root": {
 			"version": "2.0.0",
 			"resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz",
@@ -10033,6 +10673,16 @@
 				"mime-types": "^2.1.12"
 			}
 		},
+		"forwarded": {
+			"version": "0.2.0",
+			"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+			"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
+		},
+		"fresh": {
+			"version": "0.5.2",
+			"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+			"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
+		},
 		"fs-extra": {
 			"version": "7.0.1",
 			"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
@@ -10301,6 +10951,11 @@
 			"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
 			"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
 		},
+		"helmet": {
+			"version": "4.6.0",
+			"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",
@@ -10312,6 +10967,25 @@
 			"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
 			"dev": true
 		},
+		"http-errors": {
+			"version": "1.7.2",
+			"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
+			"integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
+			"requires": {
+				"depd": "~1.1.2",
+				"inherits": "2.0.3",
+				"setprototypeof": "1.1.1",
+				"statuses": ">= 1.5.0 < 2",
+				"toidentifier": "1.0.0"
+			},
+			"dependencies": {
+				"inherits": {
+					"version": "2.0.3",
+					"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+					"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+				}
+			}
+		},
 		"http-proxy-agent": {
 			"version": "4.0.1",
 			"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
@@ -10443,6 +11117,11 @@
 				"side-channel": "^1.0.4"
 			}
 		},
+		"ipaddr.js": {
+			"version": "1.9.1",
+			"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+			"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
+		},
 		"is-bigint": {
 			"version": "1.0.4",
 			"resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
@@ -12693,6 +13372,19 @@
 			"integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
 			"dev": true
 		},
+		"lambert-server": {
+			"version": "1.2.8",
+			"resolved": "https://registry.npmjs.org/lambert-server/-/lambert-server-1.2.8.tgz",
+			"integrity": "sha512-vi/Ku/QudY+WIdGO9bc0qLfVhfuJFWXk1+etesPW1vW29sPbmevLL6IwfvCtw+/MyzRAJLOyCBfQ310a68+2QQ==",
+			"requires": {
+				"body-parser": "^1.19.0",
+				"chalk": "^4.1.1",
+				"express": "^4.17.1",
+				"express-async-errors": "^3.1.1",
+				"helmet": "^4.4.1",
+				"missing-native-js-functions": "^1.1.8"
+			}
+		},
 		"leven": {
 			"version": "3.1.0",
 			"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
@@ -12786,6 +13478,11 @@
 				"tmpl": "1.0.x"
 			}
 		},
+		"media-typer": {
+			"version": "0.3.0",
+			"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+			"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+		},
 		"memory-pager": {
 			"version": "1.5.0",
 			"resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
@@ -12793,12 +13490,22 @@
 			"optional": true,
 			"peer": true
 		},
+		"merge-descriptors": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+			"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
+		},
 		"merge-stream": {
 			"version": "2.0.0",
 			"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
 			"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
 			"dev": true
 		},
+		"methods": {
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+			"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
+		},
 		"micromatch": {
 			"version": "4.0.4",
 			"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
@@ -12808,17 +13515,20 @@
 				"picomatch": "^2.2.3"
 			}
 		},
+		"mime": {
+			"version": "1.6.0",
+			"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+			"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
+		},
 		"mime-db": {
 			"version": "1.49.0",
 			"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz",
-			"integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==",
-			"devOptional": true
+			"integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA=="
 		},
 		"mime-types": {
 			"version": "2.1.32",
 			"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz",
 			"integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==",
-			"devOptional": true,
 			"requires": {
 				"mime-db": "1.49.0"
 			}
@@ -12930,6 +13640,11 @@
 				}
 			}
 		},
+		"negotiator": {
+			"version": "0.6.2",
+			"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
+			"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
+		},
 		"nice-try": {
 			"version": "1.0.5",
 			"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
@@ -13206,6 +13921,14 @@
 				"es-abstract": "^1.18.0-next.2"
 			}
 		},
+		"on-finished": {
+			"version": "2.3.0",
+			"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+			"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+			"requires": {
+				"ee-first": "1.1.1"
+			}
+		},
 		"once": {
 			"version": "1.4.0",
 			"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -13315,6 +14038,11 @@
 				}
 			}
 		},
+		"parseurl": {
+			"version": "1.3.3",
+			"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+			"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
+		},
 		"patch-package": {
 			"version": "6.4.7",
 			"resolved": "https://registry.npmjs.org/patch-package/-/patch-package-6.4.7.tgz",
@@ -13397,6 +14125,11 @@
 			"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
 			"dev": true
 		},
+		"path-to-regexp": {
+			"version": "0.1.7",
+			"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+			"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+		},
 		"performance-now": {
 			"version": "2.1.0",
 			"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
@@ -13489,6 +14222,15 @@
 				"sisteransi": "^1.0.5"
 			}
 		},
+		"proxy-addr": {
+			"version": "2.0.7",
+			"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+			"integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+			"requires": {
+				"forwarded": "0.2.0",
+				"ipaddr.js": "1.9.1"
+			}
+		},
 		"psl": {
 			"version": "1.8.0",
 			"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
@@ -13511,6 +14253,22 @@
 			"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
 			"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
 		},
+		"range-parser": {
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+			"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
+		},
+		"raw-body": {
+			"version": "2.4.0",
+			"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
+			"integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
+			"requires": {
+				"bytes": "3.1.0",
+				"http-errors": "1.7.2",
+				"iconv-lite": "0.4.24",
+				"unpipe": "1.0.0"
+			}
+		},
 		"rc": {
 			"version": "1.2.8",
 			"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
@@ -13675,11 +14433,54 @@
 			"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
 			"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
 		},
+		"send": {
+			"version": "0.17.1",
+			"resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
+			"integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
+			"requires": {
+				"debug": "2.6.9",
+				"depd": "~1.1.2",
+				"destroy": "~1.0.4",
+				"encodeurl": "~1.0.2",
+				"escape-html": "~1.0.3",
+				"etag": "~1.8.1",
+				"fresh": "0.5.2",
+				"http-errors": "~1.7.2",
+				"mime": "1.6.0",
+				"ms": "2.1.1",
+				"on-finished": "~2.3.0",
+				"range-parser": "~1.2.1",
+				"statuses": "~1.5.0"
+			},
+			"dependencies": {
+				"ms": {
+					"version": "2.1.1",
+					"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+					"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+				}
+			}
+		},
+		"serve-static": {
+			"version": "1.14.1",
+			"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
+			"integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
+			"requires": {
+				"encodeurl": "~1.0.2",
+				"escape-html": "~1.0.3",
+				"parseurl": "~1.3.3",
+				"send": "0.17.1"
+			}
+		},
 		"set-blocking": {
 			"version": "2.0.0",
 			"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
 			"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
 		},
+		"setprototypeof": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
+			"integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
+		},
 		"sha.js": {
 			"version": "2.4.11",
 			"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
@@ -13796,6 +14597,11 @@
 				"tweetnacl": "~0.14.0"
 			}
 		},
+		"statuses": {
+			"version": "1.5.0",
+			"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+			"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
+		},
 		"string_decoder": {
 			"version": "0.10.31",
 			"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
@@ -13954,6 +14760,11 @@
 				"is-number": "^7.0.0"
 			}
 		},
+		"toidentifier": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
+			"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
+		},
 		"tough-cookie": {
 			"version": "2.5.0",
 			"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
@@ -14005,6 +14816,15 @@
 			"integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
 			"dev": true
 		},
+		"type-is": {
+			"version": "1.6.18",
+			"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+			"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+			"requires": {
+				"media-typer": "0.3.0",
+				"mime-types": "~2.1.24"
+			}
+		},
 		"typedarray-to-buffer": {
 			"version": "3.1.5",
 			"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
@@ -14125,6 +14945,11 @@
 			"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
 			"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
 		},
+		"unpipe": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+			"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+		},
 		"uri-js": {
 			"version": "4.4.1",
 			"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -14162,6 +14987,11 @@
 				"object.getownpropertydescriptors": "^2.1.1"
 			}
 		},
+		"utils-merge": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+			"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
+		},
 		"uuid": {
 			"version": "3.4.0",
 			"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
@@ -14192,6 +15022,11 @@
 			"resolved": "https://registry.npmjs.org/validator/-/validator-13.6.0.tgz",
 			"integrity": "sha512-gVgKbdbHgtxpRyR8K0O6oFZPhhB5tT1jeEHZR0Znr9Svg03U0+r9DXWMrnRAB+HtCStDQKlaIZm42tVsVjqtjg=="
 		},
+		"vary": {
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+			"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
+		},
 		"verror": {
 			"version": "1.10.0",
 			"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
diff --git a/util/package.json b/util/package.json
index a132a99c..fc474d68 100644
--- a/util/package.json
+++ b/util/package.json
@@ -44,6 +44,7 @@
 		"dot-prop": "^6.0.1",
 		"env-paths": "^2.2.1",
 		"jsonwebtoken": "^8.5.1",
+		"lambert-server": "^1.2.8",
 		"missing-native-js-functions": "^1.2.10",
 		"node-fetch": "^2.6.1",
 		"patch-package": "^6.4.7",
diff --git a/util/patches/test-performance+1.1.3.patch b/util/patches/test-performance+1.1.3.patch
deleted file mode 100644
index 23b4900b..00000000
--- a/util/patches/test-performance+1.1.3.patch
+++ /dev/null
@@ -1,381 +0,0 @@
-diff --git a/node_modules/test-performance/cjs/index.js b/node_modules/test-performance/cjs/index.js
-index 65d5904..04638a1 100644
---- a/node_modules/test-performance/cjs/index.js
-+++ b/node_modules/test-performance/cjs/index.js
-@@ -1,4 +1,4 @@
--'use strict';
-+"use strict";
- 
- /*! *****************************************************************************
- Copyright (c) Microsoft Corporation.
-@@ -15,50 +15,139 @@ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- PERFORMANCE OF THIS SOFTWARE.
- ***************************************************************************** */
- 
-+const { performance } = require("perf_hooks");
-+
- function __awaiter(thisArg, _arguments, P, generator) {
--    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
--    return new (P || (P = Promise))(function (resolve, reject) {
--        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
--        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
--        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
--        step((generator = generator.apply(thisArg, _arguments || [])).next());
--    });
-+	function adopt(value) {
-+		return value instanceof P
-+			? value
-+			: new P(function (resolve) {
-+					resolve(value);
-+			  });
-+	}
-+	return new (P || (P = Promise))(function (resolve, reject) {
-+		function fulfilled(value) {
-+			try {
-+				step(generator.next(value));
-+			} catch (e) {
-+				reject(e);
-+			}
-+		}
-+		function rejected(value) {
-+			try {
-+				step(generator["throw"](value));
-+			} catch (e) {
-+				reject(e);
-+			}
-+		}
-+		function step(result) {
-+			result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
-+		}
-+		step((generator = generator.apply(thisArg, _arguments || [])).next());
-+	});
- }
- 
- function __generator(thisArg, body) {
--    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
--    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
--    function verb(n) { return function (v) { return step([n, v]); }; }
--    function step(op) {
--        if (f) throw new TypeError("Generator is already executing.");
--        while (_) try {
--            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
--            if (y = 0, t) op = [op[0] & 2, t.value];
--            switch (op[0]) {
--                case 0: case 1: t = op; break;
--                case 4: _.label++; return { value: op[1], done: false };
--                case 5: _.label++; y = op[1]; op = [0]; continue;
--                case 7: op = _.ops.pop(); _.trys.pop(); continue;
--                default:
--                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
--                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
--                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
--                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
--                    if (t[2]) _.ops.pop();
--                    _.trys.pop(); continue;
--            }
--            op = body.call(thisArg, _);
--        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
--        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
--    }
-+	var _ = {
-+			label: 0,
-+			sent: function () {
-+				if (t[0] & 1) throw t[1];
-+				return t[1];
-+			},
-+			trys: [],
-+			ops: [],
-+		},
-+		f,
-+		y,
-+		t,
-+		g;
-+	return (
-+		(g = { next: verb(0), throw: verb(1), return: verb(2) }),
-+		typeof Symbol === "function" &&
-+			(g[Symbol.iterator] = function () {
-+				return this;
-+			}),
-+		g
-+	);
-+	function verb(n) {
-+		return function (v) {
-+			return step([n, v]);
-+		};
-+	}
-+	function step(op) {
-+		if (f) throw new TypeError("Generator is already executing.");
-+		while (_)
-+			try {
-+				if (
-+					((f = 1),
-+					y &&
-+						(t =
-+							op[0] & 2
-+								? y["return"]
-+								: op[0]
-+								? y["throw"] || ((t = y["return"]) && t.call(y), 0)
-+								: y.next) &&
-+						!(t = t.call(y, op[1])).done)
-+				)
-+					return t;
-+				if (((y = 0), t)) op = [op[0] & 2, t.value];
-+				switch (op[0]) {
-+					case 0:
-+					case 1:
-+						t = op;
-+						break;
-+					case 4:
-+						_.label++;
-+						return { value: op[1], done: false };
-+					case 5:
-+						_.label++;
-+						y = op[1];
-+						op = [0];
-+						continue;
-+					case 7:
-+						op = _.ops.pop();
-+						_.trys.pop();
-+						continue;
-+					default:
-+						if (!((t = _.trys), (t = t.length > 0 && t[t.length - 1])) && (op[0] === 6 || op[0] === 2)) {
-+							_ = 0;
-+							continue;
-+						}
-+						if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) {
-+							_.label = op[1];
-+							break;
-+						}
-+						if (op[0] === 6 && _.label < t[1]) {
-+							_.label = t[1];
-+							t = op;
-+							break;
-+						}
-+						if (t && _.label < t[2]) {
-+							_.label = t[2];
-+							_.ops.push(op);
-+							break;
-+						}
-+						if (t[2]) _.ops.pop();
-+						_.trys.pop();
-+						continue;
-+				}
-+				op = body.call(thisArg, _);
-+			} catch (e) {
-+				op = [6, e];
-+				y = 0;
-+			} finally {
-+				f = t = 0;
-+			}
-+		if (op[0] & 5) throw op[1];
-+		return { value: op[0] ? op[1] : void 0, done: true };
-+	}
- }
- 
- var baselineFunctions = {
--    standard: {
--        expectedMsRunTime: 12,
--        func: function (dummyParam) {
--        },
--    },
-+	standard: {
-+		expectedMsRunTime: 12,
-+		func: function (dummyParam) {},
-+	},
- };
- 
- /**
-@@ -66,28 +155,28 @@ var baselineFunctions = {
-  * to a baseline.
-  */
- function calculateExpectedPerformance(baselineExpected, baselineActual, target) {
--    var performanceRatio = baselineActual / baselineExpected;
--    return target / performanceRatio;
-+	var performanceRatio = baselineActual / baselineExpected;
-+	return target / performanceRatio;
- }
- 
- /**
-  * This runs a single performance test of a function
-  */
- function perfTest(func) {
--    return __awaiter(this, void 0, void 0, function () {
--        var start, end;
--        return __generator(this, function (_a) {
--            switch (_a.label) {
--                case 0:
--                    start = performance.now();
--                    return [4 /*yield*/, func()];
--                case 1:
--                    _a.sent();
--                    end = performance.now();
--                    return [2 /*return*/, end - start];
--            }
--        });
--    });
-+	return __awaiter(this, void 0, void 0, function () {
-+		var start, end;
-+		return __generator(this, function (_a) {
-+			switch (_a.label) {
-+				case 0:
-+					start = performance.now();
-+					return [4 /*yield*/, func()];
-+				case 1:
-+					_a.sent();
-+					end = performance.now();
-+					return [2 /*return*/, end - start];
-+			}
-+		});
-+	});
- }
- 
- var NUMBER_OF_TESTS = 10000;
-@@ -96,22 +185,31 @@ var NUMBER_OF_TESTS = 10000;
-  * the average in milliseconds.
-  */
- function getScore(func) {
--    return __awaiter(this, void 0, void 0, function () {
--        var tests, results;
--        var _this = this;
--        return __generator(this, function (_a) {
--            switch (_a.label) {
--                case 0:
--                    tests = new Array(NUMBER_OF_TESTS).fill(undefined).map(function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
--                        return [2 /*return*/, perfTest(func)];
--                    }); }); });
--                    return [4 /*yield*/, Promise.all(tests)];
--                case 1:
--                    results = _a.sent();
--                    return [2 /*return*/, results.reduce(function (acc, val) { return acc + val; }, 0) / NUMBER_OF_TESTS];
--            }
--        });
--    });
-+	return __awaiter(this, void 0, void 0, function () {
-+		var tests, results;
-+		var _this = this;
-+		return __generator(this, function (_a) {
-+			switch (_a.label) {
-+				case 0:
-+					tests = new Array(NUMBER_OF_TESTS).fill(undefined).map(function () {
-+						return __awaiter(_this, void 0, void 0, function () {
-+							return __generator(this, function (_a) {
-+								return [2 /*return*/, perfTest(func)];
-+							});
-+						});
-+					});
-+					return [4 /*yield*/, Promise.all(tests)];
-+				case 1:
-+					results = _a.sent();
-+					return [
-+						2 /*return*/,
-+						results.reduce(function (acc, val) {
-+							return acc + val;
-+						}, 0) / NUMBER_OF_TESTS,
-+					];
-+			}
-+		});
-+	});
- }
- 
- /**
-@@ -119,31 +217,38 @@ function getScore(func) {
-  * known baseline function.
-  */
- function runTests(baselineFunc, targetFunc) {
--    return __awaiter(this, void 0, void 0, function () {
--        var initialBaselineScore, initialTargetScore, midwayBaselineScore, endTargetScore, endBaselineScore, totalBaselineScore, totalTargetScore;
--        return __generator(this, function (_a) {
--            switch (_a.label) {
--                case 0: return [4 /*yield*/, getScore(baselineFunc)];
--                case 1:
--                    initialBaselineScore = _a.sent();
--                    return [4 /*yield*/, getScore(targetFunc)];
--                case 2:
--                    initialTargetScore = _a.sent();
--                    return [4 /*yield*/, getScore(baselineFunc)];
--                case 3:
--                    midwayBaselineScore = _a.sent();
--                    return [4 /*yield*/, getScore(targetFunc)];
--                case 4:
--                    endTargetScore = _a.sent();
--                    return [4 /*yield*/, getScore(baselineFunc)];
--                case 5:
--                    endBaselineScore = _a.sent();
--                    totalBaselineScore = (initialBaselineScore + midwayBaselineScore + endBaselineScore) / 3;
--                    totalTargetScore = (initialTargetScore + endTargetScore) / 2;
--                    return [2 /*return*/, [totalBaselineScore, totalTargetScore]];
--            }
--        });
--    });
-+	return __awaiter(this, void 0, void 0, function () {
-+		var initialBaselineScore,
-+			initialTargetScore,
-+			midwayBaselineScore,
-+			endTargetScore,
-+			endBaselineScore,
-+			totalBaselineScore,
-+			totalTargetScore;
-+		return __generator(this, function (_a) {
-+			switch (_a.label) {
-+				case 0:
-+					return [4 /*yield*/, getScore(baselineFunc)];
-+				case 1:
-+					initialBaselineScore = _a.sent();
-+					return [4 /*yield*/, getScore(targetFunc)];
-+				case 2:
-+					initialTargetScore = _a.sent();
-+					return [4 /*yield*/, getScore(baselineFunc)];
-+				case 3:
-+					midwayBaselineScore = _a.sent();
-+					return [4 /*yield*/, getScore(targetFunc)];
-+				case 4:
-+					endTargetScore = _a.sent();
-+					return [4 /*yield*/, getScore(baselineFunc)];
-+				case 5:
-+					endBaselineScore = _a.sent();
-+					totalBaselineScore = (initialBaselineScore + midwayBaselineScore + endBaselineScore) / 3;
-+					totalTargetScore = (initialTargetScore + endTargetScore) / 2;
-+					return [2 /*return*/, [totalBaselineScore, totalTargetScore]];
-+			}
-+		});
-+	});
- }
- 
- /**
-@@ -152,20 +257,22 @@ function runTests(baselineFunc, targetFunc) {
-  */
- var BASELINE_FUNCTION = baselineFunctions.standard;
- function getPerformanceScore(func) {
--    return __awaiter(this, void 0, void 0, function () {
--        var _a, baseline, target;
--        return __generator(this, function (_b) {
--            switch (_b.label) {
--                case 0:
--                    if (typeof func !== 'function')
--                        throw new Error(func + " is not a function");
--                    return [4 /*yield*/, runTests(BASELINE_FUNCTION.func, func)];
--                case 1:
--                    _a = _b.sent(), baseline = _a[0], target = _a[1];
--                    return [2 /*return*/, calculateExpectedPerformance(BASELINE_FUNCTION.expectedMsRunTime, baseline, target)];
--            }
--        });
--    });
-+	return __awaiter(this, void 0, void 0, function () {
-+		var _a, baseline, target;
-+		return __generator(this, function (_b) {
-+			switch (_b.label) {
-+				case 0:
-+					if (typeof func !== "function") throw new Error(func + " is not a function");
-+					return [4 /*yield*/, runTests(BASELINE_FUNCTION.func, func)];
-+				case 1:
-+					(_a = _b.sent()), (baseline = _a[0]), (target = _a[1]);
-+					return [
-+						2 /*return*/,
-+						calculateExpectedPerformance(BASELINE_FUNCTION.expectedMsRunTime, baseline, target),
-+					];
-+			}
-+		});
-+	});
- }
- 
- module.exports = getPerformanceScore;
diff --git a/util/src/entities/BaseClass.ts b/util/src/entities/BaseClass.ts
index 2d2457de..bb6ccea1 100644
--- a/util/src/entities/BaseClass.ts
+++ b/util/src/entities/BaseClass.ts
@@ -3,6 +3,10 @@ import { BaseEntity, BeforeInsert, BeforeUpdate, PrimaryColumn } from "typeorm";
 import { Snowflake } from "../util/Snowflake";
 import Ajv, { ValidateFunction } from "ajv";
 import schema from "./schema.json";
+import "missing-native-js-functions";
+
+// TODO use class-validator https://typeorm.io/#/validation with class annotators (isPhone/isEmail) combined with types from typescript-json-schema
+// btw. we don't use class-validator for everything, because we need to explicitly set the type instead of deriving it from typescript also it doesn't easily support nested objects
 
 const ajv = new Ajv({
 	removeAdditional: "all",
@@ -12,7 +16,6 @@ const ajv = new Ajv({
 	validateFormats: false,
 	allowUnionTypes: true,
 });
-// const validator = ajv.compile<BaseClass>(schema);
 
 export class BaseClass extends BaseEntity {
 	@PrimaryColumn()
@@ -43,10 +46,20 @@ export class BaseClass extends BaseEntity {
 
 		delete props.opts;
 
+		const properties = new Set(this.metadata.columns.map((x: any) => x.propertyName));
+		// will not include relational properties (e.g. @RelationId @ManyToMany)
+
 		for (const key in props) {
 			if (this.hasOwnProperty(key)) continue;
+			if (!properties.has(key)) continue;
+			// @ts-ignore
+			const setter = this[`set${key.capitalize()}`];
 
-			Object.defineProperty(this, key, { value: props[key] });
+			if (setter) {
+				setter.call(this, props[key]);
+			} else {
+				Object.defineProperty(this, key, { value: props[key] });
+			}
 		}
 	}
 
diff --git a/util/src/entities/Config.ts b/util/src/entities/Config.ts
index 60d84958..c9326be2 100644
--- a/util/src/entities/Config.ts
+++ b/util/src/entities/Config.ts
@@ -1,7 +1,7 @@
 import { Column, Entity, JoinColumn, ManyToOne } from "typeorm";
-import { Snowflake } from "../util";
 import { BaseClass } from "./BaseClass";
 import crypto from "crypto";
+import { Snowflake } from "../util/Snowflake";
 
 @Entity("config")
 export class ConfigEntity extends BaseClass {
diff --git a/util/src/entities/ReadState.ts b/util/src/entities/ReadState.ts
index 0310cb5f..70a38b84 100644
--- a/util/src/entities/ReadState.ts
+++ b/util/src/entities/ReadState.ts
@@ -4,6 +4,10 @@ import { Channel } from "./Channel";
 import { Message } from "./Message";
 import { User } from "./User";
 
+// for read receipts
+// notification cursor and public read receipt need to be forwards-only (the former to prevent re-pinging when marked as unread, and the latter to be acceptable as a legal acknowledgement in criminal proceedings), and private read marker needs to be advance-rewind capable
+// public read receipt ≥ notification cursor ≥ private fully read marker
+
 @Entity("read_states")
 export class ReadState extends BaseClass {
 	@RelationId((read_state: ReadState) => read_state.channel)
diff --git a/util/src/entities/Template.ts b/util/src/entities/Template.ts
index c8d2034c..1dfc3b1b 100644
--- a/util/src/entities/Template.ts
+++ b/util/src/entities/Template.ts
@@ -1,11 +1,11 @@
-import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
+import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn, RelationId } from "typeorm";
 import { BaseClass } from "./BaseClass";
 import { Guild } from "./Guild";
 import { User } from "./User";
 
 @Entity("templates")
 export class Template extends BaseClass {
-	@Column()
+	@PrimaryColumn()
 	code: string;
 
 	@Column()
@@ -36,4 +36,7 @@ export class Template extends BaseClass {
 	@JoinColumn({ name: "source_guild_id" })
 	@ManyToOne(() => Guild, (guild: Guild) => guild.id)
 	source_guild: Guild;
+
+	@Column("simple-json")
+	serialized_source_guild: Guild;
 }
diff --git a/util/src/entities/User.ts b/util/src/entities/User.ts
index bdf0d35f..03cb3af4 100644
--- a/util/src/entities/User.ts
+++ b/util/src/entities/User.ts
@@ -29,8 +29,8 @@ export class User extends BaseClass {
 	setDiscriminator(val: string) {
 		const number = Number(val);
 		if (isNaN(number)) throw new Error("invalid discriminator");
-		if (number > 0 && number < 10000) throw new Error("discriminator must be between 1 and 9999");
-		this.discriminator = val;
+		if (number <= 0 || number > 10000) throw new Error("discriminator must be between 1 and 9999");
+		this.discriminator = val.toString();
 	}
 
 	@Column()
diff --git a/util/src/entities/schema.json b/util/src/entities/schema.json
index ebf66e88..7f192690 100644
--- a/util/src/entities/schema.json
+++ b/util/src/entities/schema.json
@@ -1198,6 +1198,380 @@
             },
             "type": "object"
         },
+        "ConfigEntity": {
+            "properties": {
+                "construct": {
+                },
+                "id": {
+                    "type": "string"
+                },
+                "metadata": {
+                },
+                "opts": {
+                    "properties": {
+                        "id": {
+                            "type": "string"
+                        }
+                    },
+                    "type": "object"
+                },
+                "value": {
+                    "$ref": "#/definitions/ConfigValue"
+                }
+            },
+            "type": "object"
+        },
+        "ConfigValue": {
+            "properties": {
+                "cdn": {
+                    "properties": {
+                        "endpoint": {
+                            "type": [
+                                "null",
+                                "string"
+                            ]
+                        },
+                        "endpointClient": {
+                            "type": [
+                                "null",
+                                "string"
+                            ]
+                        }
+                    },
+                    "type": "object"
+                },
+                "gateway": {
+                    "properties": {
+                        "endpoint": {
+                            "type": [
+                                "null",
+                                "string"
+                            ]
+                        },
+                        "endpointClient": {
+                            "type": [
+                                "null",
+                                "string"
+                            ]
+                        }
+                    },
+                    "type": "object"
+                },
+                "general": {
+                    "properties": {
+                        "instance_id": {
+                            "type": "string"
+                        }
+                    },
+                    "type": "object"
+                },
+                "kafka": {
+                    "properties": {
+                        "brokers": {
+                            "anyOf": [
+                                {
+                                    "items": {
+                                        "$ref": "#/definitions/KafkaBroker"
+                                    },
+                                    "type": "array"
+                                },
+                                {
+                                    "type": "null"
+                                }
+                            ]
+                        }
+                    },
+                    "type": "object"
+                },
+                "limits": {
+                    "properties": {
+                        "channel": {
+                            "properties": {
+                                "maxPins": {
+                                    "type": "number"
+                                },
+                                "maxTopic": {
+                                    "type": "number"
+                                }
+                            },
+                            "type": "object"
+                        },
+                        "guild": {
+                            "properties": {
+                                "hideOfflineMember": {
+                                    "type": "number"
+                                },
+                                "maxChannels": {
+                                    "type": "number"
+                                },
+                                "maxChannelsInCategory": {
+                                    "type": "number"
+                                },
+                                "maxMembers": {
+                                    "type": "number"
+                                },
+                                "maxRoles": {
+                                    "type": "number"
+                                }
+                            },
+                            "type": "object"
+                        },
+                        "message": {
+                            "properties": {
+                                "maxAttachmentSize": {
+                                    "type": "number"
+                                },
+                                "maxBulkDelete": {
+                                    "type": "number"
+                                },
+                                "maxCharacters": {
+                                    "type": "number"
+                                },
+                                "maxReactions": {
+                                    "type": "number"
+                                },
+                                "maxTTSCharacters": {
+                                    "type": "number"
+                                }
+                            },
+                            "type": "object"
+                        },
+                        "rate": {
+                            "properties": {
+                                "error": {
+                                    "$ref": "#/definitions/RateLimitOptions"
+                                },
+                                "global": {
+                                    "$ref": "#/definitions/RateLimitOptions"
+                                },
+                                "ip": {
+                                    "$ref": "#/definitions/Omit<RateLimitOptions,\"bot_count\">"
+                                },
+                                "routes": {
+                                    "properties": {
+                                        "auth": {
+                                            "properties": {
+                                                "login": {
+                                                    "$ref": "#/definitions/RateLimitOptions"
+                                                },
+                                                "register": {
+                                                    "$ref": "#/definitions/RateLimitOptions"
+                                                }
+                                            },
+                                            "type": "object"
+                                        },
+                                        "channel": {
+                                            "$ref": "#/definitions/RateLimitOptions"
+                                        },
+                                        "guild": {
+                                            "$ref": "#/definitions/RateLimitOptions"
+                                        },
+                                        "webhook": {
+                                            "$ref": "#/definitions/RateLimitOptions"
+                                        }
+                                    },
+                                    "type": "object"
+                                }
+                            },
+                            "type": "object"
+                        },
+                        "user": {
+                            "properties": {
+                                "maxFriends": {
+                                    "type": "number"
+                                },
+                                "maxGuilds": {
+                                    "type": "number"
+                                },
+                                "maxUsername": {
+                                    "type": "number"
+                                }
+                            },
+                            "type": "object"
+                        }
+                    },
+                    "type": "object"
+                },
+                "login": {
+                    "properties": {
+                        "requireCaptcha": {
+                            "type": "boolean"
+                        }
+                    },
+                    "type": "object"
+                },
+                "permissions": {
+                    "properties": {
+                        "user": {
+                            "properties": {
+                                "createGuilds": {
+                                    "type": "boolean"
+                                }
+                            },
+                            "type": "object"
+                        }
+                    },
+                    "type": "object"
+                },
+                "rabbitmq": {
+                    "properties": {
+                        "host": {
+                            "type": [
+                                "null",
+                                "string"
+                            ]
+                        }
+                    },
+                    "type": "object"
+                },
+                "regions": {
+                    "properties": {
+                        "available": {
+                            "items": {
+                                "$ref": "#/definitions/Region"
+                            },
+                            "type": "array"
+                        },
+                        "default": {
+                            "type": "string"
+                        }
+                    },
+                    "type": "object"
+                },
+                "register": {
+                    "properties": {
+                        "allowMultipleAccounts": {
+                            "type": "boolean"
+                        },
+                        "allowNewRegistration": {
+                            "type": "boolean"
+                        },
+                        "blockProxies": {
+                            "type": "boolean"
+                        },
+                        "dateOfBirth": {
+                            "properties": {
+                                "minimum": {
+                                    "type": "number"
+                                },
+                                "necessary": {
+                                    "type": "boolean"
+                                }
+                            },
+                            "type": "object"
+                        },
+                        "email": {
+                            "properties": {
+                                "allowlist": {
+                                    "type": "boolean"
+                                },
+                                "blocklist": {
+                                    "type": "boolean"
+                                },
+                                "domains": {
+                                    "items": {
+                                        "type": "string"
+                                    },
+                                    "type": "array"
+                                },
+                                "necessary": {
+                                    "type": "boolean"
+                                }
+                            },
+                            "type": "object"
+                        },
+                        "password": {
+                            "properties": {
+                                "minLength": {
+                                    "type": "number"
+                                },
+                                "minNumbers": {
+                                    "type": "number"
+                                },
+                                "minSymbols": {
+                                    "type": "number"
+                                },
+                                "minUpperCase": {
+                                    "type": "number"
+                                }
+                            },
+                            "type": "object"
+                        },
+                        "requireCaptcha": {
+                            "type": "boolean"
+                        },
+                        "requireInvite": {
+                            "type": "boolean"
+                        }
+                    },
+                    "type": "object"
+                },
+                "security": {
+                    "properties": {
+                        "autoUpdate": {
+                            "type": [
+                                "number",
+                                "boolean"
+                            ]
+                        },
+                        "captcha": {
+                            "properties": {
+                                "enabled": {
+                                    "type": "boolean"
+                                },
+                                "secret": {
+                                    "type": [
+                                        "null",
+                                        "string"
+                                    ]
+                                },
+                                "service": {
+                                    "anyOf": [
+                                        {
+                                            "enum": [
+                                                "hcaptcha",
+                                                "recaptcha"
+                                            ],
+                                            "type": "string"
+                                        },
+                                        {
+                                            "type": "null"
+                                        }
+                                    ]
+                                },
+                                "sitekey": {
+                                    "type": [
+                                        "null",
+                                        "string"
+                                    ]
+                                }
+                            },
+                            "type": "object"
+                        },
+                        "forwadedFor": {
+                            "type": [
+                                "null",
+                                "string"
+                            ]
+                        },
+                        "ipdataApiKey": {
+                            "type": [
+                                "null",
+                                "string"
+                            ]
+                        },
+                        "jwtSecret": {
+                            "type": "string"
+                        },
+                        "requestSignature": {
+                            "type": "string"
+                        }
+                    },
+                    "type": "object"
+                }
+            },
+            "type": "object"
+        },
         "ConnectedAccount": {
             "properties": {
                 "access_token": {
@@ -1721,6 +2095,9 @@
                 "public_updates_channel": {
                     "$ref": "#/definitions/Channel"
                 },
+                "public_updates_channel_id": {
+                    "type": "string"
+                },
                 "region": {
                     "type": "string"
                 },
@@ -1760,6 +2137,9 @@
                 "vanity_url": {
                     "$ref": "#/definitions/Invite"
                 },
+                "vanity_url_code": {
+                    "type": "string"
+                },
                 "verification_level": {
                     "type": "number"
                 },
@@ -1809,6 +2189,9 @@
                 "widget_channel": {
                     "$ref": "#/definitions/Channel"
                 },
+                "widget_channel_id": {
+                    "type": "string"
+                },
                 "widget_enabled": {
                     "type": "boolean"
                 }
@@ -2520,12 +2903,12 @@
                 "target_user": {
                     "type": "string"
                 },
+                "target_user_id": {
+                    "type": "string"
+                },
                 "target_user_type": {
                     "type": "number"
                 },
-                "target_usser_id": {
-                    "type": "string"
-                },
                 "temporary": {
                     "type": "boolean"
                 },
@@ -2615,6 +2998,17 @@
             },
             "type": "object"
         },
+        "KafkaBroker": {
+            "properties": {
+                "ip": {
+                    "type": "string"
+                },
+                "port": {
+                    "type": "number"
+                }
+            },
+            "type": "object"
+        },
         "ListenEventOpts": {
             "properties": {
                 "acknowledge": {
@@ -3507,12 +3901,12 @@
                 "target_user": {
                     "type": "string"
                 },
+                "target_user_id": {
+                    "type": "string"
+                },
                 "target_user_type": {
                     "type": "number"
                 },
-                "target_usser_id": {
-                    "type": "string"
-                },
                 "temporary": {
                     "type": "boolean"
                 },
@@ -3843,6 +4237,23 @@
             },
             "type": "object"
         },
+        "Omit<RateLimitOptions,\"bot_count\">": {
+            "properties": {
+                "bot": {
+                    "type": "number"
+                },
+                "count": {
+                    "type": "number"
+                },
+                "onyIp": {
+                    "type": "boolean"
+                },
+                "window": {
+                    "type": "number"
+                }
+            },
+            "type": "object"
+        },
         "Omit<Relationship,\"nickname\">": {
             "properties": {
                 "assign": {
@@ -4322,6 +4733,23 @@
             },
             "type": "object"
         },
+        "RateLimitOptions": {
+            "properties": {
+                "bot": {
+                    "type": "number"
+                },
+                "count": {
+                    "type": "number"
+                },
+                "onyIp": {
+                    "type": "boolean"
+                },
+                "window": {
+                    "type": "number"
+                }
+            },
+            "type": "object"
+        },
         "Reaction": {
             "properties": {
                 "count": {
@@ -4355,6 +4783,9 @@
                 "last_message": {
                     "$ref": "#/definitions/Message"
                 },
+                "last_message_id": {
+                    "type": "string"
+                },
                 "last_pin_timestamp": {
                     "format": "date-time",
                     "type": "string"
@@ -4763,6 +5194,29 @@
         "Record<string,string|null>": {
             "type": "object"
         },
+        "Region": {
+            "properties": {
+                "custom": {
+                    "type": "boolean"
+                },
+                "deprecated": {
+                    "type": "boolean"
+                },
+                "id": {
+                    "type": "string"
+                },
+                "name": {
+                    "type": "string"
+                },
+                "optimal": {
+                    "type": "boolean"
+                },
+                "vip": {
+                    "type": "boolean"
+                }
+            },
+            "type": "object"
+        },
         "Relationship": {
             "properties": {
                 "construct": {
@@ -5053,6 +5507,9 @@
                 "creator": {
                     "$ref": "#/definitions/User"
                 },
+                "creator_id": {
+                    "type": "string"
+                },
                 "description": {
                     "type": "string"
                 },
@@ -5072,9 +5529,15 @@
                     },
                     "type": "object"
                 },
+                "serialized_source_guild": {
+                    "$ref": "#/definitions/Guild"
+                },
                 "source_guild": {
                     "$ref": "#/definitions/Guild"
                 },
+                "source_guild_id": {
+                    "type": "string"
+                },
                 "updated_at": {
                     "format": "date-time",
                     "type": "string"
@@ -5164,6 +5627,18 @@
                     "format": "date-time",
                     "type": "string"
                 },
+                "data": {
+                    "properties": {
+                        "hash": {
+                            "type": "string"
+                        },
+                        "valid_tokens_since": {
+                            "format": "date-time",
+                            "type": "string"
+                        }
+                    },
+                    "type": "object"
+                },
                 "deleted": {
                     "type": "boolean"
                 },
@@ -5179,15 +5654,27 @@
                 "email": {
                     "type": "string"
                 },
+                "fingerprints": {
+                    "items": {
+                        "type": "string"
+                    },
+                    "type": "array"
+                },
                 "flags": {
                     "type": "bigint"
                 },
-                "guilds": {
+                "guild_ids": {
                     "items": {
                         "type": "string"
                     },
                     "type": "array"
                 },
+                "guilds": {
+                    "items": {
+                        "$ref": "#/definitions/Guild"
+                    },
+                    "type": "array"
+                },
                 "id": {
                     "type": "string"
                 },
@@ -5240,24 +5727,6 @@
                 "system": {
                     "type": "boolean"
                 },
-                "user_data": {
-                    "properties": {
-                        "fingerprints": {
-                            "items": {
-                                "type": "string"
-                            },
-                            "type": "array"
-                        },
-                        "hash": {
-                            "type": "string"
-                        },
-                        "valid_tokens_since": {
-                            "format": "date-time",
-                            "type": "string"
-                        }
-                    },
-                    "type": "object"
-                },
                 "username": {
                     "type": "string"
                 },
@@ -5544,6 +6013,9 @@
                 "channel": {
                     "$ref": "#/definitions/Channel"
                 },
+                "channel_id": {
+                    "type": "string"
+                },
                 "construct": {
                 },
                 "deaf": {
@@ -5552,6 +6024,9 @@
                 "guild": {
                     "$ref": "#/definitions/Guild"
                 },
+                "guild_id": {
+                    "type": "string"
+                },
                 "id": {
                     "type": "string"
                 },
@@ -5588,6 +6063,9 @@
                 },
                 "user": {
                     "$ref": "#/definitions/User"
+                },
+                "user_id": {
+                    "type": "string"
                 }
             },
             "type": "object"
@@ -5634,17 +6112,26 @@
         "Webhook": {
             "properties": {
                 "application": {
+                    "$ref": "#/definitions/Application"
+                },
+                "application_id": {
                     "type": "string"
                 },
                 "avatar": {
                     "type": "string"
                 },
                 "channel": {
+                    "$ref": "#/definitions/Channel"
+                },
+                "channel_id": {
                     "type": "string"
                 },
                 "construct": {
                 },
                 "guild": {
+                    "$ref": "#/definitions/Guild"
+                },
+                "guild_id": {
                     "type": "string"
                 },
                 "id": {
@@ -5664,6 +6151,9 @@
                     "type": "object"
                 },
                 "source_guild": {
+                    "$ref": "#/definitions/Guild"
+                },
+                "source_guild_id": {
                     "type": "string"
                 },
                 "token": {
@@ -5673,6 +6163,9 @@
                     "$ref": "#/definitions/WebhookType"
                 },
                 "user": {
+                    "$ref": "#/definitions/User"
+                },
+                "user_id": {
                     "type": "string"
                 }
             },
diff --git a/util/src/util/Config.ts b/util/src/util/Config.ts
new file mode 100644
index 00000000..f8574f38
--- /dev/null
+++ b/util/src/util/Config.ts
@@ -0,0 +1,19 @@
+import "missing-native-js-functions";
+import { ConfigValue, ConfigEntity, DefaultConfigOptions } from "../entities/Config";
+
+var config: ConfigEntity;
+// TODO: use events to inform about config updates
+
+export const Config = {
+	init: async function init() {
+		config = new ConfigEntity({}, { id: "0" });
+		return this.set((config.value || {}).merge(DefaultConfigOptions));
+	},
+	get: function get() {
+		return config.value as ConfigValue;
+	},
+	set: function set(val: any) {
+		config.value = val.merge(config.value);
+		return config.save();
+	},
+};
diff --git a/util/src/util/Database.ts b/util/src/util/Database.ts
index 90ba9079..8bb8078e 100644
--- a/util/src/util/Database.ts
+++ b/util/src/util/Database.ts
@@ -1,11 +1,12 @@
 import "reflect-metadata";
-import { createConnection } from "typeorm";
+import { Connection, createConnection } from "typeorm";
 import * as Models from "../entities";
 
 // UUID extension option is only supported with postgres
 // We want to generate all id's with Snowflakes that's why we have our own BaseEntity class
 
 var promise: Promise<any>;
+var dbConnection: Connection | undefined;
 
 export function initDatabase() {
 	if (promise) return promise; // prevent initalizing multiple times
@@ -20,7 +21,16 @@ export function initDatabase() {
 		logging: false,
 	});
 
-	promise.then(() => console.log("[Database] connected"));
+	promise.then((connection) => {
+		dbConnection = connection;
+		console.log("[Database] connected");
+	});
 
 	return promise;
 }
+
+export { dbConnection };
+
+export function closeDatabase() {
+	dbConnection?.close();
+}
diff --git a/util/src/util/checkToken.ts b/util/src/util/checkToken.ts
index 58e537ea..1e203006 100644
--- a/util/src/util/checkToken.ts
+++ b/util/src/util/checkToken.ts
@@ -9,13 +9,10 @@ export function checkToken(token: string, jwtSecret: string): Promise<any> {
 		jwt.verify(token, jwtSecret, JWTOptions, async (err, decoded: any) => {
 			if (err || !decoded) return rej("Invalid Token");
 
-			const user = await User.findOne(
-				{ id: decoded.id },
-				{ select: ["user_data", "bot", "disabled", "deleted"] }
-			);
+			const user = await User.findOne({ id: decoded.id }, { select: ["data", "bot", "disabled", "deleted"] });
 			if (!user) return rej("Invalid Token");
 			// we need to round it to seconds as it saved as seconds in jwt iat and valid_tokens_since is stored in milliseconds
-			if (decoded.iat * 1000 < user.user_data.valid_tokens_since.setSeconds(0, 0)) return rej("Invalid Token");
+			if (decoded.iat * 1000 < user.data.valid_tokens_since.setSeconds(0, 0)) return rej("Invalid Token");
 			if (user.disabled) return rej("User disabled");
 			if (user.deleted) return rej("User not found");
 
diff --git a/util/src/util/index.ts b/util/src/util/index.ts
index 700ecfa5..16b98ca3 100644
--- a/util/src/util/index.ts
+++ b/util/src/util/index.ts
@@ -1,13 +1,13 @@
 export * from "./Database";
 
-export * from "./Regex";
-export * from "./String";
 export * from "./BitField";
+export * from "./Config";
+export * from "./checkToken";
+export * from "./Event";
 export * from "./Intents";
 export * from "./MessageFlags";
 export * from "./Permissions";
 export * from "./Snowflake";
-export * from "./toBigInt";
 export * from "./RabbitMQ";
-export * from "./Event";
-export * from "./checkToken";
+export * from "./Regex";
+export * from "./String";
diff --git a/util/src/util/toBigInt.ts b/util/src/util/toBigInt.ts
deleted file mode 100644
index b7985928..00000000
--- a/util/src/util/toBigInt.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export default function toBigInt(string: string): bigint {
-	return BigInt(string);
-}
-
diff --git a/util/tests/User.test.js b/util/tests/User.test.js
new file mode 100644
index 00000000..b87c753d
--- /dev/null
+++ b/util/tests/User.test.js
@@ -0,0 +1,31 @@
+const { initDatabase, closeDatabase } = require("../dist/util/Database");
+const { User } = require("../dist/entities/User");
+jest.setTimeout(10000);
+
+beforeAll((done) => {
+	initDatabase().then(() => {
+		new User().validate(); // warm up schema/model
+		done();
+	});
+});
+
+afterAll(() => {
+	closeDatabase();
+});
+
+describe("User", () => {
+	test("valid discriminator: 1", async () => {
+		new User({ discriminator: "1" }).validate();
+	});
+	test("invalid discriminator: test", async () => {
+		expect(() => {
+			new User({ discriminator: "test" }).validate();
+		}).toThrow();
+	});
+
+	test("invalid discriminator: 0", async () => {
+		expect(() => {
+			new User({ discriminator: "0" }).validate();
+		}).toThrow();
+	});
+});
diff --git a/util/tests/validate.test.js b/util/tests/validate.test.js
index c885a167..434422f8 100644
--- a/util/tests/validate.test.js
+++ b/util/tests/validate.test.js
@@ -1,4 +1,4 @@
-const { initDatabase } = require("../dist/util/Database");
+const { initDatabase, closeDatabase } = require("../dist/util/Database");
 const { User } = require("../dist/entities/User");
 jest.setTimeout(10000);
 
@@ -9,13 +9,15 @@ beforeAll((done) => {
 	});
 });
 
+afterAll(() => {
+	closeDatabase();
+});
+
 describe("Validate model class properties", () => {
-	describe("User", () => {
-		test("object instead of string", async () => {
-			expect(() => {
-				new User({ username: {} }).validate();
-			}).toThrow();
-		});
+	test("object instead of string", async () => {
+		expect(() => {
+			new User({}, { id: {} }).validate();
+		}).toThrow();
 	});
 
 	test("validation should be faster than 20ms", () => {
diff --git a/util/util/Config.ts b/util/util/Config.ts
deleted file mode 100644
index c65c4e44..00000000
--- a/util/util/Config.ts
+++ /dev/null
@@ -1,290 +0,0 @@
-import { Schema, model, Types, Document } from "mongoose";
-import "missing-native-js-functions";
-import { Snowflake } from "./Snowflake";
-import crypto from "crypto";
-
-var config: any;
-
-export default {
-	init: async function init(defaultOpts: any = DefaultOptions) {
-		config = await db.collection("config").findOneOrFail({});
-		return this.set((config || {}).merge(defaultOpts));
-	},
-	get: function get() {
-		return config as DefaultOptions;
-	},
-	set: function set(val: any) {
-		config = val.merge(config);
-		return db.collection("config").update({}, { $set: val }, { upsert: true });
-	},
-};
-
-export interface RateLimitOptions {
-	bot?: number;
-	count: number;
-	window: number;
-	onyIp?: boolean;
-}
-
-export interface Region {
-	id: string;
-	name: string;
-	vip: boolean;
-	custom: boolean;
-	deprecated: boolean;
-	optimal: boolean;
-}
-
-export interface KafkaBroker {
-	ip: string;
-	port: number;
-}
-
-export interface DefaultOptions {
-	gateway: {
-		endpointClient: string | null;
-		endpoint: string | null;
-	};
-	cdn: {
-		endpointClient: string | null;
-		endpoint: string | null;
-	};
-	general: {
-		instance_id: string;
-	};
-	permissions: {
-		user: {
-			createGuilds: boolean;
-		};
-	};
-	limits: {
-		user: {
-			maxGuilds: number;
-			maxUsername: number;
-			maxFriends: number;
-		};
-		guild: {
-			maxRoles: number;
-			maxMembers: number;
-			maxChannels: number;
-			maxChannelsInCategory: number;
-			hideOfflineMember: number;
-		};
-		message: {
-			maxCharacters: number;
-			maxTTSCharacters: number;
-			maxReactions: number;
-			maxAttachmentSize: number;
-			maxBulkDelete: number;
-		};
-		channel: {
-			maxPins: number;
-			maxTopic: number;
-		};
-		rate: {
-			ip: Omit<RateLimitOptions, "bot_count">;
-			global: RateLimitOptions;
-			error: RateLimitOptions;
-			routes: {
-				guild: RateLimitOptions;
-				webhook: RateLimitOptions;
-				channel: RateLimitOptions;
-				auth: {
-					login: RateLimitOptions;
-					register: RateLimitOptions;
-				};
-				// TODO: rate limit configuration for all routes
-			};
-		};
-	};
-	security: {
-		autoUpdate: boolean | number;
-		requestSignature: string;
-		jwtSecret: string;
-		forwadedFor: string | null; // header to get the real user ip address
-		captcha: {
-			enabled: boolean;
-			service: "recaptcha" | "hcaptcha" | null; // TODO: hcaptcha, custom
-			sitekey: string | null;
-			secret: string | null;
-		};
-		ipdataApiKey: string | null;
-	};
-	login: {
-		requireCaptcha: boolean;
-	};
-	register: {
-		email: {
-			necessary: boolean; // we have to use necessary instead of required as the cli tool uses json schema and can't use required
-			allowlist: boolean;
-			blocklist: boolean;
-			domains: string[];
-		};
-		dateOfBirth: {
-			necessary: boolean;
-			minimum: number; // in years
-		};
-		requireCaptcha: boolean;
-		requireInvite: boolean;
-		allowNewRegistration: boolean;
-		allowMultipleAccounts: boolean;
-		blockProxies: boolean;
-		password: {
-			minLength: number;
-			minNumbers: number;
-			minUpperCase: number;
-			minSymbols: number;
-		};
-	};
-	regions: {
-		default: string;
-		available: Region[];
-	};
-	rabbitmq: {
-		host: string | null;
-	};
-	kafka: {
-		brokers: KafkaBroker[] | null;
-	};
-}
-
-export const DefaultOptions: DefaultOptions = {
-	gateway: {
-		endpointClient: null,
-		endpoint: null,
-	},
-	cdn: {
-		endpointClient: null,
-		endpoint: null,
-	},
-	general: {
-		instance_id: Snowflake.generate(),
-	},
-	permissions: {
-		user: {
-			createGuilds: true,
-		},
-	},
-	limits: {
-		user: {
-			maxGuilds: 100,
-			maxUsername: 32,
-			maxFriends: 1000,
-		},
-		guild: {
-			maxRoles: 250,
-			maxMembers: 250000,
-			maxChannels: 500,
-			maxChannelsInCategory: 50,
-			hideOfflineMember: 1000,
-		},
-		message: {
-			maxCharacters: 2000,
-			maxTTSCharacters: 200,
-			maxReactions: 20,
-			maxAttachmentSize: 8388608,
-			maxBulkDelete: 100,
-		},
-		channel: {
-			maxPins: 50,
-			maxTopic: 1024,
-		},
-		rate: {
-			ip: {
-				count: 500,
-				window: 5,
-			},
-			global: {
-				count: 20,
-				window: 5,
-				bot: 250,
-			},
-			error: {
-				count: 10,
-				window: 5,
-			},
-			routes: {
-				guild: {
-					count: 5,
-					window: 5,
-				},
-				webhook: {
-					count: 5,
-					window: 20,
-				},
-				channel: {
-					count: 5,
-					window: 20,
-				},
-				auth: {
-					login: {
-						count: 5,
-						window: 60,
-					},
-					register: {
-						count: 2,
-						window: 60 * 60 * 12,
-					},
-				},
-			},
-		},
-	},
-	security: {
-		autoUpdate: true,
-		requestSignature: crypto.randomBytes(32).toString("base64"),
-		jwtSecret: crypto.randomBytes(256).toString("base64"),
-		forwadedFor: null,
-		// forwadedFor: "X-Forwarded-For" // nginx/reverse proxy
-		// forwadedFor: "CF-Connecting-IP" // cloudflare:
-		captcha: {
-			enabled: false,
-			service: null,
-			sitekey: null,
-			secret: null,
-		},
-		ipdataApiKey: "eca677b284b3bac29eb72f5e496aa9047f26543605efe99ff2ce35c9",
-	},
-	login: {
-		requireCaptcha: false,
-	},
-	register: {
-		email: {
-			necessary: true,
-			allowlist: false,
-			blocklist: true,
-			domains: [], // TODO: efficiently save domain blocklist in database
-			// domains: fs.readFileSync(__dirname + "/blockedEmailDomains.txt", { encoding: "utf8" }).split("\n"),
-		},
-		dateOfBirth: {
-			necessary: true,
-			minimum: 13,
-		},
-		requireInvite: false,
-		requireCaptcha: true,
-		allowNewRegistration: true,
-		allowMultipleAccounts: true,
-		blockProxies: true,
-		password: {
-			minLength: 8,
-			minNumbers: 2,
-			minUpperCase: 2,
-			minSymbols: 0,
-		},
-	},
-	regions: {
-		default: "fosscord",
-		available: [{ id: "fosscord", name: "Fosscord", vip: false, custom: false, deprecated: false, optimal: false }],
-	},
-	rabbitmq: {
-		host: null,
-	},
-	kafka: {
-		brokers: null,
-	},
-};
-
-export const ConfigSchema = new Schema({}, { strict: false });
-
-export interface DefaultOptionsDocument extends DefaultOptions, Document {}
-
-export const ConfigModel = model<DefaultOptionsDocument>("Config", ConfigSchema, "config");