summary refs log tree commit diff
diff options
context:
space:
mode:
authorFlam3rboy <34555296+Flam3rboy@users.noreply.github.com>2021-05-27 18:54:15 +0200
committerFlam3rboy <34555296+Flam3rboy@users.noreply.github.com>2021-05-27 18:54:15 +0200
commit8f66556f5acf149fadd2fe0ac9e03f5e6225026e (patch)
tree6a4f9a72970f192e34e61ecc509dc71a65997707
parent:bug: fix CDN (diff)
downloadserver-8f66556f5acf149fadd2fe0ac9e03f5e6225026e.tar.xz
:construction: WIP rewrite
-rw-r--r--.env.example1
-rw-r--r--.gitignore1
-rw-r--r--package-lock.json627
-rw-r--r--package.json4
-rw-r--r--src/Server.ts32
-rw-r--r--src/Snowflake.js145
-rw-r--r--src/Util.ts38
-rw-r--r--src/index.ts10
-rw-r--r--src/routes/attachments.ts13
-rw-r--r--src/routes/external.ts22
-rw-r--r--src/util/FileStorage.ts7
-rw-r--r--src/util/Storage.ts14
-rw-r--r--tsconfig.json1
13 files changed, 609 insertions, 306 deletions
diff --git a/.env.example b/.env.example
new file mode 100644
index 00000000..2a1176ff
--- /dev/null
+++ b/.env.example
@@ -0,0 +1 @@
+STORAGE_LOCATION=files/
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 234771f2..6054dfe8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
 .vscode/
 node_modules/
 .DS_Store
+.env
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index a2bdd928..9582bc40 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,9 +9,11 @@
 			"version": "1.0.0",
 			"license": "ISC",
 			"dependencies": {
+				"@fosscord/server-util": "^1.3.3",
 				"body-parser": "^1.19.0",
 				"btoa": "^1.2.1",
 				"cheerio": "^1.0.0-rc.5",
+				"dotenv": "^10.0.0",
 				"express": "^4.17.1",
 				"express-async-errors": "^3.1.1",
 				"lambert-db": "^1.2.3",
@@ -26,11 +28,31 @@
 				"@types/btoa": "^1.2.3",
 				"@types/express": "^4.17.11",
 				"@types/multer": "^1.4.5",
-				"@types/node": "^14.14.43",
+				"@types/node": "^14.17.0",
 				"@types/node-fetch": "^2.5.7",
 				"@types/uuid": "^8.3.0"
 			}
 		},
+		"node_modules/@fosscord/server-util": {
+			"version": "1.3.3",
+			"resolved": "https://registry.npmjs.org/@fosscord/server-util/-/server-util-1.3.3.tgz",
+			"integrity": "sha512-fiEQQ93kOLXSTQBOW6PB5Th6ZHH1ozMP1nWeTjdnmr32g7X8BWJkmDMXWfKuR2PNuNr0eNJG4j1lbhIqefDqUA==",
+			"dependencies": {
+				"@types/jsonwebtoken": "^8.5.0",
+				"@types/mongoose-autopopulate": "^0.10.1",
+				"@types/mongoose-lean-virtuals": "^0.5.1",
+				"@types/node": "^14.14.25",
+				"ajv": "^8.5.0",
+				"dot-prop": "^6.0.1",
+				"env-paths": "^2.2.1",
+				"jsonwebtoken": "^8.5.1",
+				"missing-native-js-functions": "^1.2.2",
+				"mongodb": "^3.6.8",
+				"mongoose": "^5.12.3",
+				"mongoose-autopopulate": "^0.12.3",
+				"typescript": "^4.1.3"
+			}
+		},
 		"node_modules/@types/body-parser": {
 			"version": "1.19.0",
 			"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz",
@@ -90,6 +112,14 @@
 				"@types/range-parser": "*"
 			}
 		},
+		"node_modules/@types/jsonwebtoken": {
+			"version": "8.5.1",
+			"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
+			"integrity": "sha512-rNAPdomlIUX0i0cg2+I+Q1wOUr531zHBQ+cV/28PJ39bSPKjahatZZ2LMuhiguETkCgLVzfruw/ZvNMNkKoSzw==",
+			"dependencies": {
+				"@types/node": "*"
+			}
+		},
 		"node_modules/@types/mime": {
 			"version": "2.0.3",
 			"resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz",
@@ -105,6 +135,31 @@
 				"@types/node": "*"
 			}
 		},
+		"node_modules/@types/mongoose": {
+			"version": "5.10.5",
+			"resolved": "https://registry.npmjs.org/@types/mongoose/-/mongoose-5.10.5.tgz",
+			"integrity": "sha512-37QMIA954T3n+HSksSNLlxZsqF8fMJu5S4dyPBod6gRxGtsXlQ9jUtL8BE8Seimv99u79eLXI3bggoCnSQ/fxQ==",
+			"dependencies": {
+				"@types/mongodb": "*",
+				"@types/node": "*"
+			}
+		},
+		"node_modules/@types/mongoose-autopopulate": {
+			"version": "0.10.1",
+			"resolved": "https://registry.npmjs.org/@types/mongoose-autopopulate/-/mongoose-autopopulate-0.10.1.tgz",
+			"integrity": "sha512-L67MAIE3WEoTtt7a7/spRYk+76lgp67FAP6I38Y9NcC1kQuzwqnukTaJzodfb8180wxHZM4qt68u6x6ptuDRaQ==",
+			"dependencies": {
+				"@types/mongoose": "*"
+			}
+		},
+		"node_modules/@types/mongoose-lean-virtuals": {
+			"version": "0.5.1",
+			"resolved": "https://registry.npmjs.org/@types/mongoose-lean-virtuals/-/mongoose-lean-virtuals-0.5.1.tgz",
+			"integrity": "sha512-bNk+QLjP5VZU4EsJag4xQsjLAa8CEm/SKZDyiC2kM208wIrGum6daD7j45Oqs50bWNGfqZYRuEhh8xZ17D7aEw==",
+			"dependencies": {
+				"@types/mongoose": "*"
+			}
+		},
 		"node_modules/@types/multer": {
 			"version": "1.4.5",
 			"resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.5.tgz",
@@ -115,9 +170,9 @@
 			}
 		},
 		"node_modules/@types/node": {
-			"version": "14.14.43",
-			"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.43.tgz",
-			"integrity": "sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ=="
+			"version": "14.17.0",
+			"resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.0.tgz",
+			"integrity": "sha512-w8VZUN/f7SSbvVReb9SWp6cJFevxb4/nkG65yLAya//98WgocKm5PLDAtSs5CtJJJM+kHmJjO/6mmYW4MHShZA=="
 		},
 		"node_modules/@types/node-fetch": {
 			"version": "2.5.7",
@@ -169,6 +224,21 @@
 				"node": ">= 0.6"
 			}
 		},
+		"node_modules/ajv": {
+			"version": "8.5.0",
+			"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.5.0.tgz",
+			"integrity": "sha512-Y2l399Tt1AguU3BPRP9Fn4eN+Or+StUGWCUpbnFyXSo8NZ9S4uj+AG2pjs5apK+ZMOwYOz1+a+VKvKH7CudXgQ==",
+			"dependencies": {
+				"fast-deep-equal": "^3.1.1",
+				"json-schema-traverse": "^1.0.0",
+				"require-from-string": "^2.0.2",
+				"uri-js": "^4.2.2"
+			},
+			"funding": {
+				"type": "github",
+				"url": "https://github.com/sponsors/epoberezkin"
+			}
+		},
 		"node_modules/append-field": {
 			"version": "1.0.0",
 			"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
@@ -243,6 +313,11 @@
 				"node": ">= 0.4.0"
 			}
 		},
+		"node_modules/buffer-equal-constant-time": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+			"integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
+		},
 		"node_modules/buffer-from": {
 			"version": "1.1.1",
 			"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
@@ -508,6 +583,36 @@
 				"domhandler": "^4.0.0"
 			}
 		},
+		"node_modules/dot-prop": {
+			"version": "6.0.1",
+			"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz",
+			"integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==",
+			"dependencies": {
+				"is-obj": "^2.0.0"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/dotenv": {
+			"version": "10.0.0",
+			"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
+			"integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==",
+			"engines": {
+				"node": ">=10"
+			}
+		},
+		"node_modules/ecdsa-sig-formatter": {
+			"version": "1.0.11",
+			"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+			"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+			"dependencies": {
+				"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",
@@ -526,6 +631,14 @@
 			"resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
 			"integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w=="
 		},
+		"node_modules/env-paths": {
+			"version": "2.2.1",
+			"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
+			"integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
+			"engines": {
+				"node": ">=6"
+			}
+		},
 		"node_modules/escape-html": {
 			"version": "1.0.3",
 			"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@@ -584,6 +697,11 @@
 			"resolved": "https://registry.npmjs.org/express-async-errors/-/express-async-errors-3.1.1.tgz",
 			"integrity": "sha512-h6aK1da4tpqWSbyCa3FxB/V6Ehd4EEB15zyQq9qe75OZBp0krinNKuH4rAY+S/U/2I36vdLAUFSjQJ+TFmODng=="
 		},
+		"node_modules/fast-deep-equal": {
+			"version": "3.1.3",
+			"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+			"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
+		},
 		"node_modules/finalhandler": {
 			"version": "1.1.2",
 			"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
@@ -689,11 +807,69 @@
 				"node": ">= 0.10"
 			}
 		},
+		"node_modules/is-obj": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
+			"integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
+			"engines": {
+				"node": ">=8"
+			}
+		},
 		"node_modules/isarray": {
 			"version": "1.0.0",
 			"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
 			"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
 		},
+		"node_modules/json-schema-traverse": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+			"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
+		},
+		"node_modules/jsonwebtoken": {
+			"version": "8.5.1",
+			"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
+			"integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
+			"dependencies": {
+				"jws": "^3.2.2",
+				"lodash.includes": "^4.3.0",
+				"lodash.isboolean": "^3.0.3",
+				"lodash.isinteger": "^4.0.4",
+				"lodash.isnumber": "^3.0.3",
+				"lodash.isplainobject": "^4.0.6",
+				"lodash.isstring": "^4.0.1",
+				"lodash.once": "^4.0.0",
+				"ms": "^2.1.1",
+				"semver": "^5.6.0"
+			},
+			"engines": {
+				"node": ">=4",
+				"npm": ">=1.4.28"
+			}
+		},
+		"node_modules/jsonwebtoken/node_modules/ms": {
+			"version": "2.1.3",
+			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+			"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+		},
+		"node_modules/jwa": {
+			"version": "1.4.1",
+			"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
+			"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
+			"dependencies": {
+				"buffer-equal-constant-time": "1.0.1",
+				"ecdsa-sig-formatter": "1.0.11",
+				"safe-buffer": "^5.0.1"
+			}
+		},
+		"node_modules/jws": {
+			"version": "3.2.2",
+			"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
+			"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+			"dependencies": {
+				"jwa": "^1.4.1",
+				"safe-buffer": "^5.0.1"
+			}
+		},
 		"node_modules/kareem": {
 			"version": "2.3.2",
 			"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.2.tgz",
@@ -722,6 +898,41 @@
 				"missing-native-js-functions": "^1.1.8"
 			}
 		},
+		"node_modules/lodash.includes": {
+			"version": "4.3.0",
+			"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
+			"integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8="
+		},
+		"node_modules/lodash.isboolean": {
+			"version": "3.0.3",
+			"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
+			"integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
+		},
+		"node_modules/lodash.isinteger": {
+			"version": "4.0.4",
+			"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
+			"integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M="
+		},
+		"node_modules/lodash.isnumber": {
+			"version": "3.0.3",
+			"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
+			"integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
+		},
+		"node_modules/lodash.isplainobject": {
+			"version": "4.0.6",
+			"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+			"integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
+		},
+		"node_modules/lodash.isstring": {
+			"version": "4.0.1",
+			"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
+			"integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
+		},
+		"node_modules/lodash.once": {
+			"version": "4.1.1",
+			"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+			"integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
+		},
 		"node_modules/media-typer": {
 			"version": "0.3.0",
 			"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@@ -790,44 +1001,75 @@
 			"integrity": "sha512-LnlXy/PJF5oHkI7VAInYuwsR/uBcfyTDS9xcAAGHcv54Us3Ucb99gr3dZ2LOmcuHfHC92h0Wa3nk3VhqeXUWpw=="
 		},
 		"node_modules/mongodb": {
-			"version": "3.6.3",
-			"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.3.tgz",
-			"integrity": "sha512-rOZuR0QkodZiM+UbQE5kDsJykBqWi0CL4Ec2i1nrGrUI3KO11r6Fbxskqmq3JK2NH7aW4dcccBuUujAP0ERl5w==",
+			"version": "3.6.8",
+			"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.8.tgz",
+			"integrity": "sha512-sDjJvI73WjON1vapcbyBD3Ao9/VN3TKYY8/QX9EPbs22KaCSrQ5rXo5ZZd44tWJ3wl3FlnrFZ+KyUtNH6+1ZPQ==",
 			"dependencies": {
 				"bl": "^2.2.1",
 				"bson": "^1.1.4",
 				"denque": "^1.4.1",
-				"require_optional": "^1.0.1",
-				"safe-buffer": "^5.1.2",
-				"saslprep": "^1.0.0"
+				"optional-require": "^1.0.3",
+				"safe-buffer": "^5.1.2"
 			},
 			"engines": {
 				"node": ">=4"
 			},
 			"optionalDependencies": {
 				"saslprep": "^1.0.0"
+			},
+			"peerDependenciesMeta": {
+				"aws4": {
+					"optional": true
+				},
+				"bson-ext": {
+					"optional": true
+				},
+				"kerberos": {
+					"optional": true
+				},
+				"mongodb-client-encryption": {
+					"optional": true
+				},
+				"mongodb-extjson": {
+					"optional": true
+				},
+				"snappy": {
+					"optional": true
+				}
 			}
 		},
 		"node_modules/mongoose": {
-			"version": "5.11.9",
-			"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.11.9.tgz",
-			"integrity": "sha512-lmG6R64jtGGxqtn88BkkY+v470LUfGgyTKUyjswQ5c01GNgQvxA0kQd8h+tm0hZb639hKNRxL9ZBQlLleUpuIQ==",
+			"version": "5.12.11",
+			"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.12.11.tgz",
+			"integrity": "sha512-16TVqYhHQdZNR8RTis/8iiTPy+nJPq0UhKyBFTucLLU3PWcDLY2gAGv6aOk0LygTNhEfgNnENgUUHhjVqTuh8w==",
 			"dependencies": {
 				"@types/mongodb": "^3.5.27",
 				"bson": "^1.1.4",
 				"kareem": "2.3.2",
-				"mongodb": "3.6.3",
+				"mongodb": "3.6.8",
 				"mongoose-legacy-pluralize": "1.0.2",
-				"mpath": "0.8.1",
-				"mquery": "3.2.3",
+				"mpath": "0.8.3",
+				"mquery": "3.2.5",
 				"ms": "2.1.2",
 				"regexp-clone": "1.0.0",
 				"safe-buffer": "5.2.1",
-				"sift": "7.0.1",
+				"sift": "13.5.2",
 				"sliced": "1.0.1"
 			},
 			"engines": {
 				"node": ">=4.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/mongoose"
+			}
+		},
+		"node_modules/mongoose-autopopulate": {
+			"version": "0.12.3",
+			"resolved": "https://registry.npmjs.org/mongoose-autopopulate/-/mongoose-autopopulate-0.12.3.tgz",
+			"integrity": "sha512-yNmYsfi6OpS/GQ+48mkB0KQ199ExHmmPrt3wt3fyxPHPMtEBGts7yq3wBQR6VgKCPOQaKvCI1URbJCPOtrPeLw==",
+			"peerDependencies": {
+				"mongoose": "4.x || 5.x"
 			}
 		},
 		"node_modules/mongoose-legacy-pluralize": {
@@ -846,17 +1088,17 @@
 			"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
 		},
 		"node_modules/mpath": {
-			"version": "0.8.1",
-			"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.1.tgz",
-			"integrity": "sha512-norEinle9aFc05McBawVPwqgFZ7npkts9yu17ztIVLwPwO9rq0OTp89kGVTqvv5rNLMz96E5iWHpVORjI411vA==",
+			"version": "0.8.3",
+			"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.3.tgz",
+			"integrity": "sha512-eb9rRvhDltXVNL6Fxd2zM9D4vKBxjVVQNLNijlj7uoXUy19zNDsIif5zR+pWmPCWNKwAtqyo4JveQm4nfD5+eA==",
 			"engines": {
 				"node": ">=4.0.0"
 			}
 		},
 		"node_modules/mquery": {
-			"version": "3.2.3",
-			"resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.3.tgz",
-			"integrity": "sha512-cIfbP4TyMYX+SkaQ2MntD+F2XbqaBHUYWk3j+kqdDztPWok3tgyssOZxMHMtzbV1w9DaSlvEea0Iocuro41A4g==",
+			"version": "3.2.5",
+			"resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.5.tgz",
+			"integrity": "sha512-VjOKHHgU84wij7IUoZzFRU07IAxd5kWJaDmyUzQlbjHjyoeK5TNeeo8ZsFDtTYnSgpW6n/nMNIHvE3u8Lbrf4A==",
 			"dependencies": {
 				"bluebird": "3.5.1",
 				"debug": "3.1.0",
@@ -953,6 +1195,14 @@
 				"node": ">= 0.8"
 			}
 		},
+		"node_modules/optional-require": {
+			"version": "1.0.3",
+			"resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz",
+			"integrity": "sha512-RV2Zp2MY2aeYK5G+B/Sps8lW5NHAzE5QClbFP15j+PWmP+T9PxlJXBOOLoSAdgwFvS4t0aMR4vpedMkbHfh0nA==",
+			"engines": {
+				"node": ">=4"
+			}
+		},
 		"node_modules/parse5": {
 			"version": "6.0.1",
 			"resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
@@ -996,6 +1246,14 @@
 				"node": ">= 0.10"
 			}
 		},
+		"node_modules/punycode": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+			"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+			"engines": {
+				"node": ">=6"
+			}
+		},
 		"node_modules/qs": {
 			"version": "6.7.0",
 			"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
@@ -1045,19 +1303,10 @@
 			"resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz",
 			"integrity": "sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw=="
 		},
-		"node_modules/require_optional": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz",
-			"integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==",
-			"dependencies": {
-				"resolve-from": "^2.0.0",
-				"semver": "^5.1.0"
-			}
-		},
-		"node_modules/resolve-from": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz",
-			"integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=",
+		"node_modules/require-from-string": {
+			"version": "2.0.2",
+			"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+			"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
 			"engines": {
 				"node": ">=0.10.0"
 			}
@@ -1145,9 +1394,9 @@
 			"integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
 		},
 		"node_modules/sift": {
-			"version": "7.0.1",
-			"resolved": "https://registry.npmjs.org/sift/-/sift-7.0.1.tgz",
-			"integrity": "sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g=="
+			"version": "13.5.2",
+			"resolved": "https://registry.npmjs.org/sift/-/sift-13.5.2.tgz",
+			"integrity": "sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA=="
 		},
 		"node_modules/sliced": {
 			"version": "1.0.1",
@@ -1212,6 +1461,18 @@
 			"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
 			"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
 		},
+		"node_modules/typescript": {
+			"version": "4.2.4",
+			"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz",
+			"integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==",
+			"bin": {
+				"tsc": "bin/tsc",
+				"tsserver": "bin/tsserver"
+			},
+			"engines": {
+				"node": ">=4.2.0"
+			}
+		},
 		"node_modules/unpipe": {
 			"version": "1.0.0",
 			"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
@@ -1220,6 +1481,14 @@
 				"node": ">= 0.8"
 			}
 		},
+		"node_modules/uri-js": {
+			"version": "4.4.1",
+			"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+			"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+			"dependencies": {
+				"punycode": "^2.1.0"
+			}
+		},
 		"node_modules/util-deprecate": {
 			"version": "1.0.2",
 			"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -1259,6 +1528,26 @@
 		}
 	},
 	"dependencies": {
+		"@fosscord/server-util": {
+			"version": "1.3.3",
+			"resolved": "https://registry.npmjs.org/@fosscord/server-util/-/server-util-1.3.3.tgz",
+			"integrity": "sha512-fiEQQ93kOLXSTQBOW6PB5Th6ZHH1ozMP1nWeTjdnmr32g7X8BWJkmDMXWfKuR2PNuNr0eNJG4j1lbhIqefDqUA==",
+			"requires": {
+				"@types/jsonwebtoken": "^8.5.0",
+				"@types/mongoose-autopopulate": "^0.10.1",
+				"@types/mongoose-lean-virtuals": "^0.5.1",
+				"@types/node": "^14.14.25",
+				"ajv": "^8.5.0",
+				"dot-prop": "^6.0.1",
+				"env-paths": "^2.2.1",
+				"jsonwebtoken": "^8.5.1",
+				"missing-native-js-functions": "^1.2.2",
+				"mongodb": "^3.6.8",
+				"mongoose": "^5.12.3",
+				"mongoose-autopopulate": "^0.12.3",
+				"typescript": "^4.1.3"
+			}
+		},
 		"@types/body-parser": {
 			"version": "1.19.0",
 			"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz",
@@ -1318,6 +1607,14 @@
 				"@types/range-parser": "*"
 			}
 		},
+		"@types/jsonwebtoken": {
+			"version": "8.5.1",
+			"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
+			"integrity": "sha512-rNAPdomlIUX0i0cg2+I+Q1wOUr531zHBQ+cV/28PJ39bSPKjahatZZ2LMuhiguETkCgLVzfruw/ZvNMNkKoSzw==",
+			"requires": {
+				"@types/node": "*"
+			}
+		},
 		"@types/mime": {
 			"version": "2.0.3",
 			"resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz",
@@ -1333,6 +1630,31 @@
 				"@types/node": "*"
 			}
 		},
+		"@types/mongoose": {
+			"version": "5.10.5",
+			"resolved": "https://registry.npmjs.org/@types/mongoose/-/mongoose-5.10.5.tgz",
+			"integrity": "sha512-37QMIA954T3n+HSksSNLlxZsqF8fMJu5S4dyPBod6gRxGtsXlQ9jUtL8BE8Seimv99u79eLXI3bggoCnSQ/fxQ==",
+			"requires": {
+				"@types/mongodb": "*",
+				"@types/node": "*"
+			}
+		},
+		"@types/mongoose-autopopulate": {
+			"version": "0.10.1",
+			"resolved": "https://registry.npmjs.org/@types/mongoose-autopopulate/-/mongoose-autopopulate-0.10.1.tgz",
+			"integrity": "sha512-L67MAIE3WEoTtt7a7/spRYk+76lgp67FAP6I38Y9NcC1kQuzwqnukTaJzodfb8180wxHZM4qt68u6x6ptuDRaQ==",
+			"requires": {
+				"@types/mongoose": "*"
+			}
+		},
+		"@types/mongoose-lean-virtuals": {
+			"version": "0.5.1",
+			"resolved": "https://registry.npmjs.org/@types/mongoose-lean-virtuals/-/mongoose-lean-virtuals-0.5.1.tgz",
+			"integrity": "sha512-bNk+QLjP5VZU4EsJag4xQsjLAa8CEm/SKZDyiC2kM208wIrGum6daD7j45Oqs50bWNGfqZYRuEhh8xZ17D7aEw==",
+			"requires": {
+				"@types/mongoose": "*"
+			}
+		},
 		"@types/multer": {
 			"version": "1.4.5",
 			"resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.5.tgz",
@@ -1343,9 +1665,9 @@
 			}
 		},
 		"@types/node": {
-			"version": "14.14.43",
-			"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.43.tgz",
-			"integrity": "sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ=="
+			"version": "14.17.0",
+			"resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.0.tgz",
+			"integrity": "sha512-w8VZUN/f7SSbvVReb9SWp6cJFevxb4/nkG65yLAya//98WgocKm5PLDAtSs5CtJJJM+kHmJjO/6mmYW4MHShZA=="
 		},
 		"@types/node-fetch": {
 			"version": "2.5.7",
@@ -1394,6 +1716,17 @@
 				"negotiator": "0.6.2"
 			}
 		},
+		"ajv": {
+			"version": "8.5.0",
+			"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.5.0.tgz",
+			"integrity": "sha512-Y2l399Tt1AguU3BPRP9Fn4eN+Or+StUGWCUpbnFyXSo8NZ9S4uj+AG2pjs5apK+ZMOwYOz1+a+VKvKH7CudXgQ==",
+			"requires": {
+				"fast-deep-equal": "^3.1.1",
+				"json-schema-traverse": "^1.0.0",
+				"require-from-string": "^2.0.2",
+				"uri-js": "^4.2.2"
+			}
+		},
 		"append-field": {
 			"version": "1.0.0",
 			"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
@@ -1456,6 +1789,11 @@
 			"resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
 			"integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g=="
 		},
+		"buffer-equal-constant-time": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+			"integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
+		},
 		"buffer-from": {
 			"version": "1.1.1",
 			"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
@@ -1683,6 +2021,27 @@
 				"domhandler": "^4.0.0"
 			}
 		},
+		"dot-prop": {
+			"version": "6.0.1",
+			"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz",
+			"integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==",
+			"requires": {
+				"is-obj": "^2.0.0"
+			}
+		},
+		"dotenv": {
+			"version": "10.0.0",
+			"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
+			"integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q=="
+		},
+		"ecdsa-sig-formatter": {
+			"version": "1.0.11",
+			"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+			"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+			"requires": {
+				"safe-buffer": "^5.0.1"
+			}
+		},
 		"ee-first": {
 			"version": "1.1.1",
 			"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -1698,6 +2057,11 @@
 			"resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
 			"integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w=="
 		},
+		"env-paths": {
+			"version": "2.2.1",
+			"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
+			"integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="
+		},
 		"escape-html": {
 			"version": "1.0.3",
 			"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@@ -1750,6 +2114,11 @@
 			"resolved": "https://registry.npmjs.org/express-async-errors/-/express-async-errors-3.1.1.tgz",
 			"integrity": "sha512-h6aK1da4tpqWSbyCa3FxB/V6Ehd4EEB15zyQq9qe75OZBp0krinNKuH4rAY+S/U/2I36vdLAUFSjQJ+TFmODng=="
 		},
+		"fast-deep-equal": {
+			"version": "3.1.3",
+			"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+			"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
+		},
 		"finalhandler": {
 			"version": "1.1.2",
 			"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
@@ -1831,11 +2200,64 @@
 			"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
 			"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
 		},
+		"is-obj": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
+			"integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="
+		},
 		"isarray": {
 			"version": "1.0.0",
 			"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
 			"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
 		},
+		"json-schema-traverse": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+			"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
+		},
+		"jsonwebtoken": {
+			"version": "8.5.1",
+			"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
+			"integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
+			"requires": {
+				"jws": "^3.2.2",
+				"lodash.includes": "^4.3.0",
+				"lodash.isboolean": "^3.0.3",
+				"lodash.isinteger": "^4.0.4",
+				"lodash.isnumber": "^3.0.3",
+				"lodash.isplainobject": "^4.0.6",
+				"lodash.isstring": "^4.0.1",
+				"lodash.once": "^4.0.0",
+				"ms": "^2.1.1",
+				"semver": "^5.6.0"
+			},
+			"dependencies": {
+				"ms": {
+					"version": "2.1.3",
+					"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+					"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+				}
+			}
+		},
+		"jwa": {
+			"version": "1.4.1",
+			"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
+			"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
+			"requires": {
+				"buffer-equal-constant-time": "1.0.1",
+				"ecdsa-sig-formatter": "1.0.11",
+				"safe-buffer": "^5.0.1"
+			}
+		},
+		"jws": {
+			"version": "3.2.2",
+			"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
+			"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+			"requires": {
+				"jwa": "^1.4.1",
+				"safe-buffer": "^5.0.1"
+			}
+		},
 		"kareem": {
 			"version": "2.3.2",
 			"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.2.tgz",
@@ -1864,6 +2286,41 @@
 				"missing-native-js-functions": "^1.1.8"
 			}
 		},
+		"lodash.includes": {
+			"version": "4.3.0",
+			"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
+			"integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8="
+		},
+		"lodash.isboolean": {
+			"version": "3.0.3",
+			"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
+			"integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
+		},
+		"lodash.isinteger": {
+			"version": "4.0.4",
+			"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
+			"integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M="
+		},
+		"lodash.isnumber": {
+			"version": "3.0.3",
+			"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
+			"integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
+		},
+		"lodash.isplainobject": {
+			"version": "4.0.6",
+			"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+			"integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
+		},
+		"lodash.isstring": {
+			"version": "4.0.1",
+			"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
+			"integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
+		},
+		"lodash.once": {
+			"version": "4.1.1",
+			"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+			"integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
+		},
 		"media-typer": {
 			"version": "0.3.0",
 			"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@@ -1914,34 +2371,34 @@
 			"integrity": "sha512-LnlXy/PJF5oHkI7VAInYuwsR/uBcfyTDS9xcAAGHcv54Us3Ucb99gr3dZ2LOmcuHfHC92h0Wa3nk3VhqeXUWpw=="
 		},
 		"mongodb": {
-			"version": "3.6.3",
-			"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.3.tgz",
-			"integrity": "sha512-rOZuR0QkodZiM+UbQE5kDsJykBqWi0CL4Ec2i1nrGrUI3KO11r6Fbxskqmq3JK2NH7aW4dcccBuUujAP0ERl5w==",
+			"version": "3.6.8",
+			"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.8.tgz",
+			"integrity": "sha512-sDjJvI73WjON1vapcbyBD3Ao9/VN3TKYY8/QX9EPbs22KaCSrQ5rXo5ZZd44tWJ3wl3FlnrFZ+KyUtNH6+1ZPQ==",
 			"requires": {
 				"bl": "^2.2.1",
 				"bson": "^1.1.4",
 				"denque": "^1.4.1",
-				"require_optional": "^1.0.1",
+				"optional-require": "^1.0.3",
 				"safe-buffer": "^5.1.2",
 				"saslprep": "^1.0.0"
 			}
 		},
 		"mongoose": {
-			"version": "5.11.9",
-			"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.11.9.tgz",
-			"integrity": "sha512-lmG6R64jtGGxqtn88BkkY+v470LUfGgyTKUyjswQ5c01GNgQvxA0kQd8h+tm0hZb639hKNRxL9ZBQlLleUpuIQ==",
+			"version": "5.12.11",
+			"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.12.11.tgz",
+			"integrity": "sha512-16TVqYhHQdZNR8RTis/8iiTPy+nJPq0UhKyBFTucLLU3PWcDLY2gAGv6aOk0LygTNhEfgNnENgUUHhjVqTuh8w==",
 			"requires": {
 				"@types/mongodb": "^3.5.27",
 				"bson": "^1.1.4",
 				"kareem": "2.3.2",
-				"mongodb": "3.6.3",
+				"mongodb": "3.6.8",
 				"mongoose-legacy-pluralize": "1.0.2",
-				"mpath": "0.8.1",
-				"mquery": "3.2.3",
+				"mpath": "0.8.3",
+				"mquery": "3.2.5",
 				"ms": "2.1.2",
 				"regexp-clone": "1.0.0",
 				"safe-buffer": "5.2.1",
-				"sift": "7.0.1",
+				"sift": "13.5.2",
 				"sliced": "1.0.1"
 			},
 			"dependencies": {
@@ -1957,20 +2414,26 @@
 				}
 			}
 		},
+		"mongoose-autopopulate": {
+			"version": "0.12.3",
+			"resolved": "https://registry.npmjs.org/mongoose-autopopulate/-/mongoose-autopopulate-0.12.3.tgz",
+			"integrity": "sha512-yNmYsfi6OpS/GQ+48mkB0KQ199ExHmmPrt3wt3fyxPHPMtEBGts7yq3wBQR6VgKCPOQaKvCI1URbJCPOtrPeLw==",
+			"requires": {}
+		},
 		"mongoose-legacy-pluralize": {
 			"version": "1.0.2",
 			"resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz",
 			"integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ=="
 		},
 		"mpath": {
-			"version": "0.8.1",
-			"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.1.tgz",
-			"integrity": "sha512-norEinle9aFc05McBawVPwqgFZ7npkts9yu17ztIVLwPwO9rq0OTp89kGVTqvv5rNLMz96E5iWHpVORjI411vA=="
+			"version": "0.8.3",
+			"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.3.tgz",
+			"integrity": "sha512-eb9rRvhDltXVNL6Fxd2zM9D4vKBxjVVQNLNijlj7uoXUy19zNDsIif5zR+pWmPCWNKwAtqyo4JveQm4nfD5+eA=="
 		},
 		"mquery": {
-			"version": "3.2.3",
-			"resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.3.tgz",
-			"integrity": "sha512-cIfbP4TyMYX+SkaQ2MntD+F2XbqaBHUYWk3j+kqdDztPWok3tgyssOZxMHMtzbV1w9DaSlvEea0Iocuro41A4g==",
+			"version": "3.2.5",
+			"resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.5.tgz",
+			"integrity": "sha512-VjOKHHgU84wij7IUoZzFRU07IAxd5kWJaDmyUzQlbjHjyoeK5TNeeo8ZsFDtTYnSgpW6n/nMNIHvE3u8Lbrf4A==",
 			"requires": {
 				"bluebird": "3.5.1",
 				"debug": "3.1.0",
@@ -2050,6 +2513,11 @@
 				"ee-first": "1.1.1"
 			}
 		},
+		"optional-require": {
+			"version": "1.0.3",
+			"resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz",
+			"integrity": "sha512-RV2Zp2MY2aeYK5G+B/Sps8lW5NHAzE5QClbFP15j+PWmP+T9PxlJXBOOLoSAdgwFvS4t0aMR4vpedMkbHfh0nA=="
+		},
 		"parse5": {
 			"version": "6.0.1",
 			"resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
@@ -2087,6 +2555,11 @@
 				"ipaddr.js": "1.9.1"
 			}
 		},
+		"punycode": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+			"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+		},
 		"qs": {
 			"version": "6.7.0",
 			"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
@@ -2127,19 +2600,10 @@
 			"resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz",
 			"integrity": "sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw=="
 		},
-		"require_optional": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz",
-			"integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==",
-			"requires": {
-				"resolve-from": "^2.0.0",
-				"semver": "^5.1.0"
-			}
-		},
-		"resolve-from": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz",
-			"integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c="
+		"require-from-string": {
+			"version": "2.0.2",
+			"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+			"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="
 		},
 		"rethinkdb-ts": {
 			"version": "2.4.10",
@@ -2214,9 +2678,9 @@
 			"integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
 		},
 		"sift": {
-			"version": "7.0.1",
-			"resolved": "https://registry.npmjs.org/sift/-/sift-7.0.1.tgz",
-			"integrity": "sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g=="
+			"version": "13.5.2",
+			"resolved": "https://registry.npmjs.org/sift/-/sift-13.5.2.tgz",
+			"integrity": "sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA=="
 		},
 		"sliced": {
 			"version": "1.0.1",
@@ -2269,11 +2733,24 @@
 			"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
 			"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
 		},
+		"typescript": {
+			"version": "4.2.4",
+			"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz",
+			"integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg=="
+		},
 		"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",
+			"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+			"requires": {
+				"punycode": "^2.1.0"
+			}
+		},
 		"util-deprecate": {
 			"version": "1.0.2",
 			"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
diff --git a/package.json b/package.json
index 489b67dd..69707a51 100644
--- a/package.json
+++ b/package.json
@@ -20,9 +20,11 @@
 	},
 	"homepage": "https://github.com/discord-open-source/discord-cdn#readme",
 	"dependencies": {
+		"@fosscord/server-util": "^1.3.3",
 		"body-parser": "^1.19.0",
 		"btoa": "^1.2.1",
 		"cheerio": "^1.0.0-rc.5",
+		"dotenv": "^10.0.0",
 		"express": "^4.17.1",
 		"express-async-errors": "^3.1.1",
 		"lambert-db": "^1.2.3",
@@ -37,7 +39,7 @@
 		"@types/btoa": "^1.2.3",
 		"@types/express": "^4.17.11",
 		"@types/multer": "^1.4.5",
-		"@types/node": "^14.14.43",
+		"@types/node": "^14.17.0",
 		"@types/node-fetch": "^2.5.7",
 		"@types/uuid": "^8.3.0"
 	}
diff --git a/src/Server.ts b/src/Server.ts
index 3e8c9321..3ad794be 100644
--- a/src/Server.ts
+++ b/src/Server.ts
@@ -1,42 +1,28 @@
-import { MongoDatabase, Database } from "lambert-db";
 import { Server, ServerOptions } from "lambert-server";
+import { Config, db } from "@fosscord/server-util";
+import path from "path";
 
-const log = console.log;
-console.log = (content) => {
-	log(`[${new Date().toTimeString().split(" ")[0]}]`, content);
-};
-
-declare global {
-	namespace Express {
-		interface Request {
-			cdn: CDNServer;
-		}
-	}
-}
-
-export interface CDNServerOptions extends ServerOptions {
-	db: string;
-}
+export interface CDNServerOptions extends ServerOptions {}
 
 export class CDNServer extends Server {
-	db: Database;
 	public options: CDNServerOptions;
 
-	constructor(options: Partial<CDNServerOptions>) {
+	constructor(options?: Partial<CDNServerOptions>) {
 		super(options);
-
-		this.db = new MongoDatabase(options?.db);
 	}
 
 	async start() {
 		console.log("[Database] connecting ...");
-		await this.db.init();
+		// @ts-ignore
+		await (db as Promise<Connection>);
+		await Config.init();
 		console.log("[Database] connected");
+
+		await this.registerRoutes(path.join(__dirname, "routes"));
 		return super.start();
 	}
 
 	async stop() {
-		await this.db.destroy();
 		return super.stop();
 	}
 }
diff --git a/src/Snowflake.js b/src/Snowflake.js
deleted file mode 100644
index feb5eb41..00000000
--- a/src/Snowflake.js
+++ /dev/null
@@ -1,145 +0,0 @@
-// @ts-nocheck
-
-// github.com/discordjs/discord.js/blob/master/src/util/Snowflake.js
-"use strict";
-
-// Discord epoch (2015-01-01T00:00:00.000Z)
-const EPOCH = 1420070400000;
-let INCREMENT = 0;
-
-/**
- * A container for useful snowflake-related methods.
- */
-class SnowflakeUtil {
-	constructor() {
-		throw new Error(`The ${this.constructor.name} class may not be instantiated.`);
-	}
-
-	/**
-	 * A Twitter snowflake, except the epoch is 2015-01-01T00:00:00.000Z
-	 * ```
-	 * If we have a snowflake '266241948824764416' we can represent it as binary:
-	 *
-	 * 64                                          22     17     12          0
-	 *  000000111011000111100001101001000101000000  00001  00000  000000000000
-	 *       number of ms since Discord epoch       worker  pid    increment
-	 * ```
-	 * @typedef {string} Snowflake
-	 */
-
-	/**
-	 * Transforms a snowflake from a decimal string to a bit string.
-	 * @param  {Snowflake} num Snowflake to be transformed
-	 * @returns {string}
-	 * @private
-	 */
-	static idToBinary(num) {
-		let bin = "";
-		let high = parseInt(num.slice(0, -10)) || 0;
-		let low = parseInt(num.slice(-10));
-		while (low > 0 || high > 0) {
-			bin = String(low & 1) + bin;
-			low = Math.floor(low / 2);
-			if (high > 0) {
-				low += 5000000000 * (high % 2);
-				high = Math.floor(high / 2);
-			}
-		}
-		return bin;
-	}
-
-	/**
-	 * Transforms a snowflake from a bit string to a decimal string.
-	 * @param  {string} num Bit string to be transformed
-	 * @returns {Snowflake}
-	 * @private
-	 */
-	static binaryToID(num) {
-		let dec = "";
-
-		while (num.length > 50) {
-			const high = parseInt(num.slice(0, -32), 2);
-			const low = parseInt((high % 10).toString(2) + num.slice(-32), 2);
-
-			dec = (low % 10).toString() + dec;
-			num =
-				Math.floor(high / 10).toString(2) +
-				Math.floor(low / 10)
-					.toString(2)
-					.padStart(32, "0");
-		}
-
-		num = parseInt(num, 2);
-		while (num > 0) {
-			dec = (num % 10).toString() + dec;
-			num = Math.floor(num / 10);
-		}
-
-		return dec;
-	}
-
-	/**
-	 * Generates a Discord snowflake.
-	 * <info>This hardcodes the worker ID as 1 and the process ID as 0.</info>
-	 * @param {number|Date} [timestamp=Date.now()] Timestamp or date of the snowflake to generate
-	 * @returns {Snowflake} The generated snowflake
-	 */
-	static generate(timestamp = Date.now()) {
-		if (timestamp instanceof Date) timestamp = timestamp.getTime();
-		if (typeof timestamp !== "number" || isNaN(timestamp)) {
-			throw new TypeError(
-				`"timestamp" argument must be a number (received ${isNaN(timestamp) ? "NaN" : typeof timestamp})`
-			);
-		}
-		if (INCREMENT >= 4095) INCREMENT = 0;
-		const BINARY = `${(timestamp - EPOCH).toString(2).padStart(42, "0")}0000100000${(INCREMENT++)
-			.toString(2)
-			.padStart(12, "0")}`;
-		return SnowflakeUtil.binaryToID(BINARY);
-	}
-
-	/**
-	 * A deconstructed snowflake.
-	 * @typedef {Object} DeconstructedSnowflake
-	 * @property {number} timestamp Timestamp the snowflake was created
-	 * @property {Date} date Date the snowflake was created
-	 * @property {number} workerID Worker ID in the snowflake
-	 * @property {number} processID Process ID in the snowflake
-	 * @property {number} increment Increment in the snowflake
-	 * @property {string} binary Binary representation of the snowflake
-	 */
-
-	/**
-	 * Deconstructs a Discord snowflake.
-	 * @param {Snowflake} snowflake Snowflake to deconstruct
-	 * @returns {DeconstructedSnowflake} Deconstructed snowflake
-	 */
-	static deconstruct(snowflake) {
-		const BINARY = SnowflakeUtil.idToBinary(snowflake).toString(2).padStart(64, "0");
-		const res = {
-			timestamp: parseInt(BINARY.substring(0, 42), 2) + EPOCH,
-			workerID: parseInt(BINARY.substring(42, 47), 2),
-			processID: parseInt(BINARY.substring(47, 52), 2),
-			increment: parseInt(BINARY.substring(52, 64), 2),
-			binary: BINARY,
-		};
-		Object.defineProperty(res, "date", {
-			get: function get() {
-				return new Date(this.timestamp);
-			},
-			enumerable: true,
-		});
-		return res;
-	}
-
-	/**
-	 * Discord's epoch value (2015-01-01T00:00:00.000Z).
-	 * @type {number}
-	 * @readonly
-	 */
-	static get EPOCH() {
-		return EPOCH;
-	}
-}
-
-module.exports = SnowflakeUtil;
diff --git a/src/Util.ts b/src/Util.ts
deleted file mode 100644
index 291372c1..00000000
--- a/src/Util.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import fs from "fs/promises";
-import "missing-native-js-functions";
-
-export interface traverseDirectoryOptions {
-	dirname: string;
-	filter?: RegExp;
-	excludeDirs?: RegExp;
-	recursive?: boolean;
-}
-
-const DEFAULT_EXCLUDE_DIR = /^\./;
-const DEFAULT_FILTER = /^([^\.].*)\.js$/;
-
-export async function traverseDirectory<T>(
-	options: traverseDirectoryOptions,
-	action: (path: string) => T
-): Promise<T[]> {
-	if (!options.filter) options.filter = DEFAULT_FILTER;
-	if (!options.excludeDirs) options.excludeDirs = DEFAULT_EXCLUDE_DIR;
-
-	const routes = await fs.readdir(options.dirname);
-	const promises = <Promise<T | T[] | undefined>[]>routes.map(async (file) => {
-		const path = options.dirname + file;
-		const stat = await fs.lstat(path);
-		if (path.match(<RegExp>options.excludeDirs)) return;
-
-		if (stat.isFile() && path.match(<RegExp>options.filter)) {
-			return action(path);
-		} else if (options.recursive && stat.isDirectory()) {
-			return traverseDirectory({ ...options, dirname: path + "/" }, action);
-		}
-	});
-	const result = await Promise.all(promises);
-
-	const t = <(T | undefined)[]>result.flat();
-
-	return <T[]>t.filter((x) => x != undefined);
-}
diff --git a/src/index.ts b/src/index.ts
index 64fca7e5..cdf88fd9 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,6 +1,14 @@
 import { CDNServer } from "./Server";
+import dotenv from "dotenv";
+dotenv.config();
 
-const server = new CDNServer({ db: "" });
+if (process.env.STORAGE_LOCATION) {
+	if (!process.env.STORAGE_LOCATION.startsWith("/")) {
+		process.env.STORAGE_LOCATION = __dirname + "/../" + process.env.STORAGE_LOCATION;
+	}
+} else process.env.STORAGE_LOCATION = __dirname + "/../files/";
+
+const server = new CDNServer();
 server
 	.start()
 	.then(() => {
diff --git a/src/routes/attachments.ts b/src/routes/attachments.ts
index 9f016174..87368e48 100644
--- a/src/routes/attachments.ts
+++ b/src/routes/attachments.ts
@@ -1,6 +1,7 @@
 import { Router } from "express";
 import multer from "multer";
-import Snowflake from "../Snowflake";
+import { Snowflake } from "@fosscord/server-util";
+import { storage } from "../util/Storage";
 
 const multer_ = multer();
 const router = Router();
@@ -11,11 +12,11 @@ type Attachment = {
 	id: string;
 	type: string;
 };
-
 router.post("/:filename", multer_.single("attachment"), async (req, res) => {
 	const { buffer, mimetype } = req.file;
 	const { filename } = req.params;
-	const { db } = req.cdn;
+
+	// storage.set(filename, );
 
 	const File: Attachment = {
 		filename,
@@ -23,14 +24,9 @@ router.post("/:filename", multer_.single("attachment"), async (req, res) => {
 		id: Snowflake.generate(),
 		type: mimetype,
 	};
-
-	if (!(await db.data.attachments.push(File))) throw new Error("Error uploading file");
-
-	return res.status(201).send({ success: true, message: "attachment uploaded", id: File.id, filename });
 });
 
 router.get("/:hash/:filename", async (req, res) => {
-	const { db } = req.cdn;
 	const { hash, filename } = req.params;
 
 	const File: Attachment = await db.data.attachments({ id: hash, filename: filename }).get();
@@ -41,7 +37,6 @@ router.get("/:hash/:filename", async (req, res) => {
 
 router.delete("/:hash/:filename", async (req, res) => {
 	const { hash, filename } = req.params;
-	const { db } = req.cdn;
 
 	await db.data.attachments({ id: hash, filename: filename }).delete();
 	return res.send({ success: true, message: "attachment deleted" });
diff --git a/src/routes/external.ts b/src/routes/external.ts
index f75f6a66..045eb7da 100644
--- a/src/routes/external.ts
+++ b/src/routes/external.ts
@@ -2,8 +2,7 @@ import bodyParser from "body-parser";
 import { Router } from "express";
 import fetch from "node-fetch";
 import cheerio from "cheerio";
-import btoa from "btoa";
-import { URL } from "url";
+import crypto from "crypto";
 
 const router = Router();
 
@@ -30,25 +29,21 @@ const DEFAULT_FETCH_OPTIONS: any = {
 router.post("/", bodyParser.json(), async (req, res) => {
 	if (!req.body) throw new Error("Invalid Body (url missing) \nExample: url:https://discord.com");
 
-	const { db } = req.cdn;
 	const { url } = req.body;
 
-	const ID = btoa(url);
-
-	const cache = await db.data.crawler({ id: ID }).get();
-	if (cache) return res.send(cache);
+	const hash = crypto.createHash("md5").update(url).digest("hex");
 
 	try {
 		const request = await fetch(url, DEFAULT_FETCH_OPTIONS);
 
 		const text = await request.text();
-		const ツ: any = cheerio.load(text);
+		const $ = cheerio.load(text);
 
-		const ogTitle = ツ('meta[property="og:title"]').attr("content");
-		const ogDescription = ツ('meta[property="og:description"]').attr("content");
-		const ogImage = ツ('meta[property="og:image"]').attr("content");
-		const ogUrl = ツ('meta[property="og:url"]').attr("content");
-		const ogType = ツ('meta[property="og:type"]').attr("content");
+		const ogTitle = $('meta[property="og:title"]').attr("content");
+		const ogDescription = $('meta[property="og:description"]').attr("content");
+		const ogImage = $('meta[property="og:image"]').attr("content");
+		const ogUrl = $('meta[property="og:url"]').attr("content");
+		const ogType = $('meta[property="og:type"]').attr("content");
 
 		const filename = new URL(url).host.split(".")[0];
 
@@ -72,7 +67,6 @@ router.post("/", bodyParser.json(), async (req, res) => {
 });
 
 router.get("/:id/:filename", async (req, res) => {
-	const { db } = req.cdn;
 	const { id, filename } = req.params;
 	const { image, type } = await db.data.externals({ id: id }).get();
 	const imageBuffer = Buffer.from(image, "base64");
diff --git a/src/util/FileStorage.ts b/src/util/FileStorage.ts
new file mode 100644
index 00000000..01be0050
--- /dev/null
+++ b/src/util/FileStorage.ts
@@ -0,0 +1,7 @@
+import { Storage } from "./Storage";
+
+export class FileStorage implements Storage {
+	async get(path: string, prefix?: string) {}
+
+	async set(path: string, value: any) {}
+}
diff --git a/src/util/Storage.ts b/src/util/Storage.ts
new file mode 100644
index 00000000..ad00fbb7
--- /dev/null
+++ b/src/util/Storage.ts
@@ -0,0 +1,14 @@
+import { FileStorage } from "./FileStorage";
+
+export interface Storage {
+	set(hash: string, data: any, prefix?: string): Promise<void>;
+	get(hash: string, prefix?: string): Promise<any>;
+}
+
+var storage: Storage;
+
+if (process.env.STORAGE_PROVIDER === "file") {
+	storage = new FileStorage();
+}
+
+export { storage };
diff --git a/tsconfig.json b/tsconfig.json
index 1422446c..08e39435 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,4 +1,5 @@
 {
+	"include": ["src/**/*.ts"],
 	"compilerOptions": {
 		/* Visit https://aka.ms/tsconfig.json to read more about this file */