summary refs log tree commit diff
diff options
context:
space:
mode:
authorFlam3rboy <34555296+Flam3rboy@users.noreply.github.com>2021-08-13 13:03:18 +0200
committerFlam3rboy <34555296+Flam3rboy@users.noreply.github.com>2021-08-13 13:03:18 +0200
commitebff2f42417e0e579d59d296f5150024f8c850ee (patch)
tree707b264d239859853411adb5142b64727debd51b
parentFix naming (diff)
parentabstract Event emission (diff)
downloadserver-ebff2f42417e0e579d59d296f5150024f8c850ee.tar.xz
Merge branch 'master' into pr/darkhpp/261-2
-rw-r--r--.docker/env1
-rw-r--r--.github/FUNDING.yml (renamed from api/.github/FUNDING.yml)0
-rw-r--r--.github/workflows/release.yml (renamed from api/.github/workflows/release.yml)39
-rw-r--r--.gitignore5
-rw-r--r--.vscode/launch.json17
-rw-r--r--api/.github/ISSUE_TEMPLATE/-feature--.md20
-rw-r--r--api/.github/workflows/codeql-analysis.yml71
-rw-r--r--api/.github/workflows/docker-publish.yml47
-rw-r--r--api/package-lock.json27
-rw-r--r--api/package.json4
-rw-r--r--api/src/Server.ts8
-rw-r--r--api/src/index.ts2
-rw-r--r--api/src/middlewares/Authentication.ts21
-rw-r--r--api/src/middlewares/ErrorHandler.ts2
-rw-r--r--api/src/middlewares/RateLimit.ts21
-rw-r--r--api/src/routes/auth/login.ts2
-rw-r--r--api/src/routes/auth/register.ts2
-rw-r--r--api/src/routes/channels/#channel_id/index.ts3
-rw-r--r--api/src/routes/channels/#channel_id/invites.ts3
-rw-r--r--api/src/routes/channels/#channel_id/messages/#message_id/ack.ts4
-rw-r--r--api/src/routes/channels/#channel_id/messages/#message_id/index.ts4
-rw-r--r--api/src/routes/channels/#channel_id/messages/#message_id/reactions.ts4
-rw-r--r--api/src/routes/channels/#channel_id/messages/bulk-delete.ts4
-rw-r--r--api/src/routes/channels/#channel_id/messages/index.ts2
-rw-r--r--api/src/routes/channels/#channel_id/permissions.ts12
-rw-r--r--api/src/routes/channels/#channel_id/pins.ts4
-rw-r--r--api/src/routes/channels/#channel_id/typing.ts3
-rw-r--r--api/src/routes/channels/#channel_id/webhooks.ts2
-rw-r--r--api/src/routes/gateway.ts2
-rw-r--r--api/src/routes/guilds/#guild_id/bans.ts4
-rw-r--r--api/src/routes/guilds/#guild_id/channels.ts9
-rw-r--r--api/src/routes/guilds/#guild_id/delete.ts4
-rw-r--r--api/src/routes/guilds/#guild_id/index.ts5
-rw-r--r--api/src/routes/guilds/#guild_id/invites.ts2
-rw-r--r--api/src/routes/guilds/#guild_id/members/#member_id/index.ts6
-rw-r--r--api/src/routes/guilds/#guild_id/members/#member_id/nick.ts2
-rw-r--r--api/src/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts2
-rw-r--r--api/src/routes/guilds/#guild_id/members/index.ts2
-rw-r--r--api/src/routes/guilds/#guild_id/regions.ts4
-rw-r--r--api/src/routes/guilds/#guild_id/roles.ts7
-rw-r--r--api/src/routes/guilds/#guild_id/templates.ts2
-rw-r--r--api/src/routes/guilds/#guild_id/vanity-url.ts2
-rw-r--r--api/src/routes/guilds/#guild_id/welcome_screen.ts4
-rw-r--r--api/src/routes/guilds/#guild_id/widget.json.ts2
-rw-r--r--api/src/routes/guilds/#guild_id/widget.png.ts2
-rw-r--r--api/src/routes/guilds/#guild_id/widget.ts2
-rw-r--r--api/src/routes/guilds/index.ts2
-rw-r--r--api/src/routes/guilds/templates/index.ts2
-rw-r--r--api/src/routes/invites/index.ts2
-rw-r--r--api/src/routes/users/@me/channels.ts7
-rw-r--r--api/src/routes/users/@me/delete.ts2
-rw-r--r--api/src/routes/users/@me/disable.ts2
-rw-r--r--api/src/routes/users/@me/guilds.ts14
-rw-r--r--api/src/routes/users/@me/index.ts2
-rw-r--r--api/src/routes/users/@me/relationships.ts7
-rw-r--r--api/src/schema/Channel.ts2
-rw-r--r--api/src/schema/Guild.ts2
-rw-r--r--api/src/schema/Message.ts2
-rw-r--r--api/src/test/test.ts2
-rw-r--r--api/src/util/Channel.ts8
-rw-r--r--api/src/util/Config.ts4
-rw-r--r--api/src/util/Event.ts26
-rw-r--r--api/src/util/Member.ts7
-rw-r--r--api/src/util/Message.ts16
-rw-r--r--api/src/util/User.ts2
-rw-r--r--api/src/util/cdn.ts2
-rw-r--r--api/src/util/ipAddress.ts2
-rw-r--r--api/src/util/passwordStrength.ts2
-rw-r--r--bundle/package-lock.json2750
-rw-r--r--bundle/package.json42
-rw-r--r--bundle/src/Server.ts33
-rw-r--r--bundle/src/start.ts74
-rw-r--r--bundle/tsconfig.json (renamed from rtc/tsconfig.json)4
-rw-r--r--cdn/package.json4
-rw-r--r--cdn/src/Server.ts24
-rw-r--r--cdn/src/routes/attachments.ts2
-rw-r--r--cdn/src/routes/avatars.ts2
-rw-r--r--cdn/src/routes/external.ts2
-rw-r--r--docker-compose.yml24
-rw-r--r--gateway/.github/workflows/docker-publish.yml47
-rw-r--r--gateway/package.json6
-rw-r--r--gateway/src/Server.ts5
-rw-r--r--gateway/src/events/Connection.ts1
-rw-r--r--gateway/src/listener/listener.ts309
-rw-r--r--gateway/src/opcodes/Identify.ts2
-rw-r--r--gateway/src/opcodes/LazyRequest.ts10
-rw-r--r--gateway/src/schema/Activity.ts2
-rw-r--r--gateway/src/util/Config.ts4
-rw-r--r--gateway/src/util/WebSocket.ts4
-rw-r--r--rtc/package-lock.json1268
-rw-r--r--rtc/package.json48
-rw-r--r--rtc/src/index.ts10
-rw-r--r--rtc/src/models/Activity.ts132
-rw-r--r--rtc/src/models/Application.ts67
-rw-r--r--rtc/src/models/AuditLog.ts220
-rw-r--r--rtc/src/models/Ban.ts32
-rw-r--r--rtc/src/models/Channel.ts109
-rw-r--r--rtc/src/models/Emoji.ts29
-rw-r--r--rtc/src/models/Event.ts540
-rw-r--r--rtc/src/models/Guild.ts161
-rw-r--r--rtc/src/models/Interaction.ts32
-rw-r--r--rtc/src/models/Invite.ts95
-rw-r--r--rtc/src/models/Member.ts109
-rw-r--r--rtc/src/models/Message.ts368
-rw-r--r--rtc/src/models/RateLimit.ts25
-rw-r--r--rtc/src/models/ReadState.ts26
-rw-r--r--rtc/src/models/Role.ts42
-rw-r--r--rtc/src/models/Status.ts13
-rw-r--r--rtc/src/models/Team.ts17
-rw-r--r--rtc/src/models/Template.ts51
-rw-r--r--rtc/src/models/User.ts252
-rw-r--r--rtc/src/models/VoiceState.ts34
-rw-r--r--rtc/src/models/Webhook.ts84
-rw-r--r--rtc/src/models/index.ts89
-rw-r--r--rtc/src/util/BitField.ts143
-rw-r--r--rtc/src/util/Config.ts284
-rw-r--r--rtc/src/util/Constants.ts28
-rw-r--r--rtc/src/util/Database.ts151
-rw-r--r--rtc/src/util/Intents.ts21
-rw-r--r--rtc/src/util/MessageFlags.ts14
-rw-r--r--rtc/src/util/MongoBigInt.ts82
-rw-r--r--rtc/src/util/Permissions.ts262
-rw-r--r--rtc/src/util/RabbitMQ.ts18
-rw-r--r--rtc/src/util/Regex.ts3
-rw-r--r--rtc/src/util/Snowflake.ts127
-rw-r--r--rtc/src/util/String.ts7
-rw-r--r--rtc/src/util/UserFlags.ts22
-rw-r--r--rtc/src/util/checkToken.ts24
-rw-r--r--rtc/src/util/index.ts9
-rw-r--r--rtc/src/util/toBigInt.ts3
-rw-r--r--util/package.json11
-rw-r--r--util/src/models/index.ts3
-rw-r--r--util/src/util/Config.ts3
-rw-r--r--util/src/util/Database.ts3
-rw-r--r--util/src/util/Event.ts94
-rw-r--r--util/src/util/index.ts1
-rw-r--r--webrtc/package.json1
-rw-r--r--webrtc/src/Server.ts5
138 files changed, 3310 insertions, 5727 deletions
diff --git a/.docker/env b/.docker/env
new file mode 100644
index 00000000..595b7ba2
--- /dev/null
+++ b/.docker/env
@@ -0,0 +1 @@
+MONGO_URL=mongodb://db:27017/fosscord?readPreference=secondaryPreferred
diff --git a/api/.github/FUNDING.yml b/.github/FUNDING.yml
index f76b9015..f76b9015 100644
--- a/api/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
diff --git a/api/.github/workflows/release.yml b/.github/workflows/release.yml
index 3ef40aeb..b0a31780 100644
--- a/api/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -15,13 +15,13 @@ jobs:
         include:
           - os: windows
             build: npm run bundle:windows
-            artifact: fosscord-api-windows.exe
+            artifact: fosscord-server-windows.exe
           - os: macos
             build: npm run bundle:macos
-            artifact: fosscord-api-macos.app.tgz
+            artifact: fosscord-server-macos.app.tgz
           - os: ubuntu
             build: npm run bundle:linux
-            artifact: fosscord-api-linux.tgz
+            artifact: fosscord-server-linux.tgz
     runs-on: ${{ matrix.os }}-latest
     steps:
       - uses: actions/checkout@v2
@@ -29,6 +29,8 @@ jobs:
         with:
           node-version: 14
       - run: npm install
+        env:
+          MONGOMS_VERSION: 4.4.3
       - run: npm run build
       - run: ${{ matrix.build }}
       - uses: actions/upload-artifact@v2
@@ -46,43 +48,52 @@ jobs:
         uses: Saionaro/extract-package-version@v1.0.6
       - uses: actions/download-artifact@v2
         with:
-          name: fosscord-api-windows-${{ github.sha }}.exe
+          name: fosscord-server-windows.exe
       - uses: actions/download-artifact@v2
         with:
-          name: fosscord-api-macos-${{ github.sha }}.app.tgz
+          name: fosscord-server-macos.app.tgz
       - uses: actions/download-artifact@v2
         with:
-          name: fosscord-api-linux-${{ github.sha }}.tgz
+          name: fosscord-server-linux.tgz
       - uses: actions/create-release@v1
         id: create-release
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         with:
           tag_name: v${{ steps.extract_version.outputs.version }}
-          release_name: Release ${{ steps.extract_version.outputs.version }}
+          release_name: Server v${{ steps.extract_version.outputs.version }}
           draft: false
           prerelease: true # TODO: change this to false
+          body: >
+            ## Download
+
+            - [Windows](https://github.com/fosscord/fosscord-server/releases/download/v${{ steps.extract_version.outputs.version }}/fosscord-server-windows.exe)
+
+            - [MacOS](https://github.com/fosscord/fosscord-server/releases/download/v${{ steps.extract_version.outputs.version }}/fosscord-server-macos.app.tgz)
+
+            - [Linux](https://github.com/fosscord/fosscord-server/releases/download/v${{ steps.extract_version.outputs.version }}/fosscord-server-linux.tgz)
+
       - uses: actions/upload-release-asset@v1
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         with:
           upload_url: ${{ steps.create-release.outputs.upload_url }}
-          asset_path: fosscord-api-windows-${{ github.sha }}.exe
-          asset_name: fosscord-api-windows.exe
+          asset_path: fosscord-server-windows.exe
+          asset_name: fosscord-server-windows.exe
           asset_content_type: application/vnd.microsoft.portable-executable
       - uses: actions/upload-release-asset@v1
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         with:
           upload_url: ${{ steps.create-release.outputs.upload_url }}
-          asset_path: fosscord-api-macos-${{ github.sha }}.app.tgz
-          asset_name: fosscord-api-macos.app.tgz
+          asset_path: fosscord-server-macos.app.tgz
+          asset_name: fosscord-server-macos.app.tgz
           asset_content_type: application/gzip
       - uses: actions/upload-release-asset@v1
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         with:
           upload_url: ${{ steps.create-release.outputs.upload_url }}
-          asset_path: fosscord-api-linux-${{ github.sha }}.tgz
-          asset_name: fosscord-api-linux.tgz
-          asset_content_type: application/gzip
+          asset_path: fosscord-server-linux.tgz
+          asset_name: fosscord-server-linux.tgz
+          asset_content_type: application/gzip
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index c2658d7d..c2636bf1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,4 @@
-node_modules/
+.DS_STORE
+db/
+dist/
+node_modules
diff --git a/.vscode/launch.json b/.vscode/launch.json
deleted file mode 100644
index 07fd32ac..00000000
--- a/.vscode/launch.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-	// Use IntelliSense to learn about possible attributes.
-	// Hover to view descriptions of existing attributes.
-	// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
-	"version": "0.2.0",
-	"configurations": [
-		{
-			"sourceMaps": true,
-			"type": "node",
-			"request": "launch",
-			"name": "Launch Server",
-			"program": "${workspaceFolder}/dist/index.js",
-			"preLaunchTask": "tsc: build - tsconfig.json",
-			"outFiles": ["${workspaceFolder}/dist/**/*.js"]
-		}
-	]
-}
diff --git a/api/.github/ISSUE_TEMPLATE/-feature--.md b/api/.github/ISSUE_TEMPLATE/-feature--.md
deleted file mode 100644
index cefcf6b6..00000000
--- a/api/.github/ISSUE_TEMPLATE/-feature--.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-name: "[Feature] "
-about: Suggest an idea for this project
-title: ''
-labels: enhancement
-assignees: ''
-
----
-
-**Is your feature request related to a problem? Please describe.**
-A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
-
-**Describe the solution you'd like**
-A clear and concise description of what you want to happen.
-
-**Describe alternatives you've considered**
-A clear and concise description of any alternative solutions or features you've considered.
-
-**Additional context**
-Add any other context or screenshots about the feature request here.
diff --git a/api/.github/workflows/codeql-analysis.yml b/api/.github/workflows/codeql-analysis.yml
deleted file mode 100644
index 3a3a8e92..00000000
--- a/api/.github/workflows/codeql-analysis.yml
+++ /dev/null
@@ -1,71 +0,0 @@
-# For most projects, this workflow file will not need changing; you simply need
-# to commit it to your repository.
-#
-# You may wish to alter this file to override the set of languages analyzed,
-# or to provide custom queries or build logic.
-#
-# ******** NOTE ********
-# We have attempted to detect the languages in your repository. Please check
-# the `language` matrix defined below to confirm you have the correct set of
-# supported CodeQL languages.
-#
-name: "CodeQL"
-
-on:
-  push:
-    branches: [ master ]
-  pull_request:
-    # The branches below must be a subset of the branches above
-    branches: [ master ]
-  schedule:
-    - cron: '25 10 * * 5'
-
-jobs:
-  analyze:
-    name: Analyze
-    runs-on: ubuntu-latest
-    permissions:
-      actions: read
-      contents: read
-      security-events: write
-
-    strategy:
-      fail-fast: false
-      matrix:
-        language: [ 'javascript' ]
-        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
-        # Learn more:
-        # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
-
-    steps:
-    - name: Checkout repository
-      uses: actions/checkout@v2
-
-    # Initializes the CodeQL tools for scanning.
-    - name: Initialize CodeQL
-      uses: github/codeql-action/init@v1
-      with:
-        languages: ${{ matrix.language }}
-        # If you wish to specify custom queries, you can do so here or in a config file.
-        # By default, queries listed here will override any specified in a config file.
-        # Prefix the list here with "+" to use these queries and those in the config file.
-        # queries: ./path/to/local/query, your-org/your-repo/queries@main
-
-    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
-    # If this step fails, then you should remove it and run the build manually (see below)
-    - name: Autobuild
-      uses: github/codeql-action/autobuild@v1
-
-    # ℹ️ Command-line programs to run using the OS shell.
-    # 📚 https://git.io/JvXDl
-
-    # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
-    #    and modify them (or add more) to build your code if your project
-    #    uses a compiled language
-
-    #- run: |
-    #   make bootstrap
-    #   make release
-
-    - name: Perform CodeQL Analysis
-      uses: github/codeql-action/analyze@v1
diff --git a/api/.github/workflows/docker-publish.yml b/api/.github/workflows/docker-publish.yml
deleted file mode 100644
index 46d9d04d..00000000
--- a/api/.github/workflows/docker-publish.yml
+++ /dev/null
@@ -1,47 +0,0 @@
-name: docker-publish
-
-on:
-  push:
-    branches:
-      - 'master'
-
-jobs:
-  docker:
-    runs-on: ubuntu-latest
-    steps:
-      -
-        name: Checkout
-        uses: actions/checkout@v2
-      -
-        name: Set up Docker Buildx
-        uses: docker/setup-buildx-action@v1
-      -
-        name: Cache Docker layers
-        uses: actions/cache@v2
-        with:
-          path: /tmp/.buildx-cache
-          key: ${{ runner.os }}-buildx-${{ github.sha }}
-          restore-keys: |
-            ${{ runner.os }}-buildx-
-      -
-        name: Login to DockerHub
-        uses: docker/login-action@v1
-        with:
-          username: ${{ secrets.DOCKERHUB_USERNAME }}
-          password: ${{ secrets.DOCKERHUB_TOKEN }}
-      -
-        name: Build and push
-        uses: docker/build-push-action@v2
-        with:
-          context: .
-          push: true
-          tags: ${{ secrets.DOCKERHUB_TAGS }}
-          cache-from: type=local,src=/tmp/.buildx-cache
-          cache-to: type=local,dest=/tmp/.buildx-cache-new
-      -
-        # Hackfix to cleanup cache; replace after buildx 0.6 and BuildKit 0.9 are released
-        # https://github.com/docker/build-push-action/pull/406#issuecomment-879184394
-        name: Move cache fix
-        run: |
-          rm -rf /tmp/.buildx-cache
-          mv /tmp/.buildx-cache-new /tmp/.buildx-cache
diff --git a/api/package-lock.json b/api/package-lock.json
index e4cf20be..c030e642 100644
--- a/api/package-lock.json
+++ b/api/package-lock.json
@@ -6,9 +6,10 @@
 	"packages": {
 		"": {
 			"version": "1.0.0",
+			"hasInstallScript": true,
 			"license": "ISC",
 			"dependencies": {
-				"@fosscord/server-util": "file:../util",
+				"@fosscord/util": "file:../util",
 				"@types/jest": "^26.0.22",
 				"@types/json-schema": "^7.0.7",
 				"ajv": "^8.4.0",
@@ -705,6 +706,10 @@
 			"resolved": "../util",
 			"link": true
 		},
+		"node_modules/@fosscord/util": {
+			"resolved": "../util",
+			"link": true
+		},
 		"node_modules/@istanbuljs/load-nyc-config": {
 			"version": "1.1.0",
 			"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@@ -12031,6 +12036,26 @@
 				"typescript": "^4.1.3"
 			}
 		},
+		"@fosscord/util": {
+			"version": "file:../util",
+			"requires": {
+				"@types/amqplib": "^0.8.1",
+				"@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",
+				"amqplib": "^0.8.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.9",
+				"mongoose": "^5.13.7",
+				"mongoose-autopopulate": "^0.12.3",
+				"typescript": "^4.1.3"
+			}
+		},
 		"@istanbuljs/load-nyc-config": {
 			"version": "1.1.0",
 			"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
diff --git a/api/package.json b/api/package.json
index 8a0bbdd1..c9dd6b1f 100644
--- a/api/package.json
+++ b/api/package.json
@@ -5,6 +5,8 @@
 	"main": "dist/Server.js",
 	"types": "dist/Server.d.ts",
 	"scripts": {
+		"link": "npm run build && npm link",
+		"postinstall": "npm run --prefix ../util/ link && npm link @fosscord/util && npm run link",
 		"test": "jest",
 		"test:watch": "jest --watch",
 		"start": "npm run build && node dist/start",
@@ -33,7 +35,7 @@
 	},
 	"homepage": "https://github.com/fosscord/fosscord-api#readme",
 	"dependencies": {
-		"@fosscord/server-util": "file:../util",
+		"@fosscord/util": "file:../util",
 		"@types/jest": "^26.0.22",
 		"@types/json-schema": "^7.0.7",
 		"ajv": "^8.4.0",
diff --git a/api/src/Server.ts b/api/src/Server.ts
index 7299425a..a60c5e4d 100644
--- a/api/src/Server.ts
+++ b/api/src/Server.ts
@@ -3,7 +3,7 @@ import fs from "fs";
 import { Connection } from "mongoose";
 import { Server, ServerOptions } from "lambert-server";
 import { Authentication, CORS } from "./middlewares/";
-import { Config, db, RabbitMQ } from "@fosscord/server-util";
+import { Config, db, initEvent, RabbitMQ } from "@fosscord/util";
 import i18next from "i18next";
 import i18nextMiddleware, { I18next } from "i18next-http-middleware";
 import i18nextBackend from "i18next-node-fs-backend";
@@ -56,9 +56,8 @@ export class FosscordServer extends Server {
 		// @ts-ignore
 		await (db as Promise<Connection>);
 		await this.setupSchema();
-		console.log("[Database] connected");
 		await Config.init();
-		await RabbitMQ.init();
+		await initEvent();
 
 		this.app.use(CORS);
 		this.app.use(Authentication);
@@ -93,11 +92,12 @@ export class FosscordServer extends Server {
 		app.use("/api/v9", api);
 		app.use("/api", api); // allow unversioned requests
 
-		api.get("*", (req: Request, res: Response) => {
+		api.get("*", (req: Request, res: Response, next) => {
 			res.status(404).json({
 				message: "404: Not Found",
 				code: 0
 			});
+			next();
 		});
 
 		this.app = app;
diff --git a/api/src/index.ts b/api/src/index.ts
index 554c296f..6037e31f 100644
--- a/api/src/index.ts
+++ b/api/src/index.ts
@@ -7,9 +7,7 @@ export * from "./schema/Invite";
 export * from "./schema/Message";
 export * from "./util/Config";
 export * from "./util/Constants";
-export * from "./util/Event";
 export * from "./util/instanceOf";
-export * from "./util/Event";
 export * from "./util/instanceOf";
 export * from "./util/Member";
 export * from "./util/RandomInviteID";
diff --git a/api/src/middlewares/Authentication.ts b/api/src/middlewares/Authentication.ts
index 01b7ef57..00cd9ea7 100644
--- a/api/src/middlewares/Authentication.ts
+++ b/api/src/middlewares/Authentication.ts
@@ -1,15 +1,15 @@
 import { NextFunction, Request, Response } from "express";
 import { HTTPError } from "lambert-server";
-import { checkToken, Config } from "@fosscord/server-util";
+import { checkToken, Config } from "@fosscord/util";
 
 export const NO_AUTHORIZATION_ROUTES = [
-	/^\/api(\/v\d+)?\/auth\/login/,
-	/^\/api(\/v\d+)?\/auth\/register/,
-	/^\/api(\/v\d+)?\/webhooks\//,
-	/^\/api(\/v\d+)?\/ping/,
-	/^\/api(\/v\d+)?\/gateway/,
-	/^\/api(\/v\d+)?\/experiments/,
-	/^\/api(\/v\d+)?\/guilds\/\d+\/widget\.(json|png)/
+	"/auth/login",
+	"/auth/register",
+	"/webhooks/",
+	"/ping",
+	"/gateway",
+	"/experiments"
+	// /^\/api(\/v\d+)?\/guilds\/\d+\/widget\.(json|png)/
 ];
 
 export const API_PREFIX = /^\/api(\/v\d+)?/;
@@ -24,13 +24,14 @@ declare global {
 		}
 	}
 }
+// TODO wenn client offen ist, wird http://localhost:8080/api/v9/users/@me/guild-events blockiert?
 
 export async function Authentication(req: Request, res: Response, next: NextFunction) {
 	if (req.method === "OPTIONS") return res.sendStatus(204);
 	if (!req.url.startsWith("/api")) return next();
 	const apiPath = req.url.replace(API_PREFIX, "");
-	if (apiPath.startsWith("/invites") && req.method === "GET") return next();
-	if (NO_AUTHORIZATION_ROUTES.some((x) => x.test(req.url))) return next();
+	if (apiPath.startsWith("/invites") && req.method === "GET") return next(); // @ts-ignore
+	if (NO_AUTHORIZATION_ROUTES.some((x) => apiPath.startsWith(x) || x.test?.(req.url))) return next();
 	if (!req.headers.authorization) return next(new HTTPError("Missing Authorization Header", 401));
 
 	try {
diff --git a/api/src/middlewares/ErrorHandler.ts b/api/src/middlewares/ErrorHandler.ts
index 2e6b1d8b..04d56026 100644
--- a/api/src/middlewares/ErrorHandler.ts
+++ b/api/src/middlewares/ErrorHandler.ts
@@ -25,8 +25,6 @@ export function ErrorHandler(error: Error, req: Request, res: Response, next: Ne
 		if (httpcode > 511) httpcode = 400;
 
 		res.status(httpcode).json({ code: code, message, errors });
-
-		return;
 	} catch (error) {
 		console.error(error);
 		return res.status(500).json({ code: 500, message: "Internal Server Error" });
diff --git a/api/src/middlewares/RateLimit.ts b/api/src/middlewares/RateLimit.ts
index c8fdeba2..a1bb0c44 100644
--- a/api/src/middlewares/RateLimit.ts
+++ b/api/src/middlewares/RateLimit.ts
@@ -1,16 +1,17 @@
-import { db, MongooseCache, Bucket, Config } from "@fosscord/server-util";
+// @ts-nocheck
+import { db, Bucket, Config } from "@fosscord/util";
 import { NextFunction, Request, Response, Router } from "express";
 import { getIpAdress } from "../util/ipAddress";
 import { API_PREFIX_TRAILING_SLASH } from "./Authentication";
 
-const Cache = new MongooseCache(
-	db.collection("ratelimits"),
-	[
-		// TODO: uncomment $match and fix error: not receiving change events
-		// { $match: { blocked: true } }
-	],
-	{ onlyEvents: false, array: true }
-);
+// const Cache = new MongooseCache(
+// 	db.collection("ratelimits"),
+// 	[
+// 		// TODO: uncomment $match and fix error: not receiving change events
+// 		// { $match: { blocked: true } }
+// 	],
+// 	{ onlyEvents: false, array: true }
+// );
 
 // Docs: https://discord.com/developers/docs/topics/rate-limits
 
@@ -31,6 +32,7 @@ TODO: use config values
 
 */
 
+// TODO: FIX with new event handling
 export default function RateLimit(opts: {
 	bucket?: string;
 	window: number;
@@ -44,6 +46,7 @@ export default function RateLimit(opts: {
 	success?: boolean;
 	onlyIp?: boolean;
 }): any {
+	return (req, res, next) => next();
 	Cache.init(); // will only initalize it once
 
 	return async (req: Request, res: Response, next: NextFunction): Promise<any> => {
diff --git a/api/src/routes/auth/login.ts b/api/src/routes/auth/login.ts
index c3661608..f55d5351 100644
--- a/api/src/routes/auth/login.ts
+++ b/api/src/routes/auth/login.ts
@@ -2,7 +2,7 @@ import { Request, Response, Router } from "express";
 import { check, FieldErrors, Length } from "../../util/instanceOf";
 import bcrypt from "bcrypt";
 import jwt from "jsonwebtoken";
-import { Config, UserModel } from "@fosscord/server-util";
+import { Config, UserModel } from "@fosscord/util";
 import { adjustEmail } from "./register";
 import RateLimit from "../../middlewares/RateLimit";
 
diff --git a/api/src/routes/auth/register.ts b/api/src/routes/auth/register.ts
index 66a1fc8d..fecde874 100644
--- a/api/src/routes/auth/register.ts
+++ b/api/src/routes/auth/register.ts
@@ -1,5 +1,5 @@
 import { Request, Response, Router } from "express";
-import { trimSpecial, User, Snowflake, UserModel, Config } from "@fosscord/server-util";
+import { trimSpecial, User, Snowflake, UserModel, Config } from "@fosscord/util";
 import bcrypt from "bcrypt";
 import { check, Email, EMAIL_REGEX, FieldErrors, Length } from "../../util/instanceOf";
 import "missing-native-js-functions";
diff --git a/api/src/routes/channels/#channel_id/index.ts b/api/src/routes/channels/#channel_id/index.ts
index 81e5054e..3bfa80be 100644
--- a/api/src/routes/channels/#channel_id/index.ts
+++ b/api/src/routes/channels/#channel_id/index.ts
@@ -1,8 +1,7 @@
-import { ChannelDeleteEvent, ChannelModel, ChannelUpdateEvent, getPermission, GuildUpdateEvent, toObject } from "@fosscord/server-util";
+import { ChannelDeleteEvent, ChannelModel, ChannelUpdateEvent, emitEvent, getPermission, GuildUpdateEvent, toObject } from "@fosscord/util";
 import { Router, Response, Request } from "express";
 import { HTTPError } from "lambert-server";
 import { ChannelModifySchema } from "../../../schema/Channel";
-import { emitEvent } from "../../../util/Event";
 import { check } from "../../../util/instanceOf";
 const router: Router = Router();
 // TODO: delete channel
diff --git a/api/src/routes/channels/#channel_id/invites.ts b/api/src/routes/channels/#channel_id/invites.ts
index c9db4dd2..438f8c51 100644
--- a/api/src/routes/channels/#channel_id/invites.ts
+++ b/api/src/routes/channels/#channel_id/invites.ts
@@ -3,11 +3,10 @@ import { HTTPError } from "lambert-server";
 
 import { check } from "../../../util/instanceOf";
 import { random } from "../../../util/RandomInviteID";
-import { emitEvent } from "../../../util/Event";
 
 import { InviteCreateSchema } from "../../../schema/Invite";
 
-import { getPermission, ChannelModel, InviteModel, InviteCreateEvent, toObject } from "@fosscord/server-util";
+import { getPermission, ChannelModel, InviteModel, InviteCreateEvent, toObject, emitEvent } from "@fosscord/util";
 
 const router: Router = Router();
 
diff --git a/api/src/routes/channels/#channel_id/messages/#message_id/ack.ts b/api/src/routes/channels/#channel_id/messages/#message_id/ack.ts
index f4d9e696..bbc779dd 100644
--- a/api/src/routes/channels/#channel_id/messages/#message_id/ack.ts
+++ b/api/src/routes/channels/#channel_id/messages/#message_id/ack.ts
@@ -1,6 +1,6 @@
-import { getPermission, MessageAckEvent, ReadStateModel } from "@fosscord/server-util";
+import { emitEvent, getPermission, MessageAckEvent, ReadStateModel } from "@fosscord/util";
 import { Request, Response, Router } from "express";
-import { emitEvent } from "../../../../../util/Event";
+
 import { check } from "../../../../../util/instanceOf";
 
 const router = Router();
diff --git a/api/src/routes/channels/#channel_id/messages/#message_id/index.ts b/api/src/routes/channels/#channel_id/messages/#message_id/index.ts
index a7c23d2f..3c58d034 100644
--- a/api/src/routes/channels/#channel_id/messages/#message_id/index.ts
+++ b/api/src/routes/channels/#channel_id/messages/#message_id/index.ts
@@ -1,8 +1,8 @@
-import { ChannelModel, getPermission, MessageDeleteEvent, MessageModel, MessageUpdateEvent, toObject } from "@fosscord/server-util";
+import { ChannelModel, emitEvent, getPermission, MessageDeleteEvent, MessageModel, MessageUpdateEvent, toObject } from "@fosscord/util";
 import { Router, Response, Request } from "express";
 import { HTTPError } from "lambert-server";
 import { MessageCreateSchema } from "../../../../../schema/Message";
-import { emitEvent } from "../../../../../util/Event";
+
 import { check } from "../../../../../util/instanceOf";
 import { handleMessage, postHandleMessage } from "../../../../../util/Message";
 
diff --git a/api/src/routes/channels/#channel_id/messages/#message_id/reactions.ts b/api/src/routes/channels/#channel_id/messages/#message_id/reactions.ts
index 168a870f..34d2ce3a 100644
--- a/api/src/routes/channels/#channel_id/messages/#message_id/reactions.ts
+++ b/api/src/routes/channels/#channel_id/messages/#message_id/reactions.ts
@@ -1,5 +1,6 @@
 import {
 	ChannelModel,
+	emitEvent,
 	EmojiModel,
 	getPermission,
 	MemberModel,
@@ -12,10 +13,9 @@ import {
 	PublicUserProjection,
 	toObject,
 	UserModel
-} from "@fosscord/server-util";
+} from "@fosscord/util";
 import { Router, Response, Request } from "express";
 import { HTTPError } from "lambert-server";
-import { emitEvent } from "../../../../../util/Event";
 
 const router = Router();
 // TODO: check if emoji is really an unicode emoji or a prperly encoded external emoji
diff --git a/api/src/routes/channels/#channel_id/messages/bulk-delete.ts b/api/src/routes/channels/#channel_id/messages/bulk-delete.ts
index e53cd597..8132462f 100644
--- a/api/src/routes/channels/#channel_id/messages/bulk-delete.ts
+++ b/api/src/routes/channels/#channel_id/messages/bulk-delete.ts
@@ -1,7 +1,7 @@
 import { Router, Response, Request } from "express";
-import { ChannelModel, Config, getPermission, MessageDeleteBulkEvent, MessageModel } from "@fosscord/server-util";
+import { ChannelModel, Config, emitEvent, getPermission, MessageDeleteBulkEvent, MessageModel } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
-import { emitEvent } from "../../../../util/Event";
+
 import { check } from "../../../../util/instanceOf";
 
 const router: Router = Router();
diff --git a/api/src/routes/channels/#channel_id/messages/index.ts b/api/src/routes/channels/#channel_id/messages/index.ts
index fea4d6a4..6ae6491f 100644
--- a/api/src/routes/channels/#channel_id/messages/index.ts
+++ b/api/src/routes/channels/#channel_id/messages/index.ts
@@ -1,5 +1,5 @@
 import { Router, Response, Request } from "express";
-import { Attachment, ChannelModel, ChannelType, getPermission, MessageDocument, MessageModel, toObject } from "@fosscord/server-util";
+import { Attachment, ChannelModel, ChannelType, getPermission, MessageDocument, MessageModel, toObject } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { MessageCreateSchema } from "../../../../schema/Message";
 import { check, instanceOf, Length } from "../../../../util/instanceOf";
diff --git a/api/src/routes/channels/#channel_id/permissions.ts b/api/src/routes/channels/#channel_id/permissions.ts
index 12364293..4cbc7522 100644
--- a/api/src/routes/channels/#channel_id/permissions.ts
+++ b/api/src/routes/channels/#channel_id/permissions.ts
@@ -1,7 +1,15 @@
-import { ChannelModel, ChannelPermissionOverwrite, ChannelUpdateEvent, getPermission, MemberModel, RoleModel } from "@fosscord/server-util";
+import {
+	ChannelModel,
+	ChannelPermissionOverwrite,
+	ChannelUpdateEvent,
+	emitEvent,
+	getPermission,
+	MemberModel,
+	RoleModel
+} from "@fosscord/util";
 import { Router, Response, Request } from "express";
 import { HTTPError } from "lambert-server";
-import { emitEvent } from "../../../util/Event";
+
 import { check } from "../../../util/instanceOf";
 const router: Router = Router();
 
diff --git a/api/src/routes/channels/#channel_id/pins.ts b/api/src/routes/channels/#channel_id/pins.ts
index 65d6b975..18a5861b 100644
--- a/api/src/routes/channels/#channel_id/pins.ts
+++ b/api/src/routes/channels/#channel_id/pins.ts
@@ -2,14 +2,14 @@ import {
 	ChannelModel,
 	ChannelPinsUpdateEvent,
 	Config,
+	emitEvent,
 	getPermission,
 	MessageModel,
 	MessageUpdateEvent,
 	toObject
-} from "@fosscord/server-util";
+} from "@fosscord/util";
 import { Router, Request, Response } from "express";
 import { HTTPError } from "lambert-server";
-import { emitEvent } from "../../../util/Event";
 
 const router: Router = Router();
 
diff --git a/api/src/routes/channels/#channel_id/typing.ts b/api/src/routes/channels/#channel_id/typing.ts
index de549883..21d453d8 100644
--- a/api/src/routes/channels/#channel_id/typing.ts
+++ b/api/src/routes/channels/#channel_id/typing.ts
@@ -1,8 +1,7 @@
-import { ChannelModel, MemberModel, toObject, TypingStartEvent } from "@fosscord/server-util";
+import { ChannelModel, emitEvent, MemberModel, toObject, TypingStartEvent } from "@fosscord/util";
 import { Router, Request, Response } from "express";
 
 import { HTTPError } from "lambert-server";
-import { emitEvent } from "../../../util/Event";
 
 const router: Router = Router();
 
diff --git a/api/src/routes/channels/#channel_id/webhooks.ts b/api/src/routes/channels/#channel_id/webhooks.ts
index 6c1aea2a..7852f8f3 100644
--- a/api/src/routes/channels/#channel_id/webhooks.ts
+++ b/api/src/routes/channels/#channel_id/webhooks.ts
@@ -1,6 +1,6 @@
 import { Router, Response, Request } from "express";
 import { check, Length } from "../../../util/instanceOf";
-import { ChannelModel, getPermission, trimSpecial } from "@fosscord/server-util";
+import { ChannelModel, getPermission, trimSpecial } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { isTextChannel } from "./messages/index";
 
diff --git a/api/src/routes/gateway.ts b/api/src/routes/gateway.ts
index f2bc5b34..3120718e 100644
--- a/api/src/routes/gateway.ts
+++ b/api/src/routes/gateway.ts
@@ -1,4 +1,4 @@
-import { Config } from "@fosscord/server-util";
+import { Config } from "@fosscord/util";
 import { Router, Response, Request } from "express";
 
 const router = Router();
diff --git a/api/src/routes/guilds/#guild_id/bans.ts b/api/src/routes/guilds/#guild_id/bans.ts
index d9752f61..bb3eac03 100644
--- a/api/src/routes/guilds/#guild_id/bans.ts
+++ b/api/src/routes/guilds/#guild_id/bans.ts
@@ -1,9 +1,9 @@
 import { Request, Response, Router } from "express";
-import { BanModel, getPermission, GuildBanAddEvent, GuildBanRemoveEvent, GuildModel, toObject } from "@fosscord/server-util";
+import { BanModel, emitEvent, getPermission, GuildBanAddEvent, GuildBanRemoveEvent, GuildModel, toObject } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { getIpAdress } from "../../../util/ipAddress";
 import { BanCreateSchema } from "../../../schema/Ban";
-import { emitEvent } from "../../../util/Event";
+
 import { check } from "../../../util/instanceOf";
 import { removeMember } from "../../../util/Member";
 import { getPublicUser } from "../../../util/User";
diff --git a/api/src/routes/guilds/#guild_id/channels.ts b/api/src/routes/guilds/#guild_id/channels.ts
index 52361f5e..8d97cf96 100644
--- a/api/src/routes/guilds/#guild_id/channels.ts
+++ b/api/src/routes/guilds/#guild_id/channels.ts
@@ -8,11 +8,12 @@ import {
 	toObject,
 	ChannelUpdateEvent,
 	AnyChannel,
-	getPermission
-} from "@fosscord/server-util";
+	getPermission,
+	emitEvent
+} from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { ChannelModifySchema } from "../../../schema/Channel";
-import { emitEvent } from "../../../util/Event";
+
 import { check } from "../../../util/instanceOf";
 import { createChannel } from "../../../util/Channel";
 const router = Router();
@@ -64,7 +65,7 @@ router.patch(
 
 		const channel = await ChannelModel.findOneAndUpdate({ id: req.body, guild_id }, opts).exec();
 
-		await emitEvent({ event: "CHANNEL_UPDATE", data: channel, channel_id: body.id, guild_id } as ChannelUpdateEvent);
+		await emitEvent({ event: "CHANNEL_UPDATE", data: toObject(channel), channel_id: body.id, guild_id } as ChannelUpdateEvent);
 
 		res.json(toObject(channel));
 	}
diff --git a/api/src/routes/guilds/#guild_id/delete.ts b/api/src/routes/guilds/#guild_id/delete.ts
index 6cca289e..ba1c2fde 100644
--- a/api/src/routes/guilds/#guild_id/delete.ts
+++ b/api/src/routes/guilds/#guild_id/delete.ts
@@ -1,5 +1,6 @@
 import {
 	ChannelModel,
+	emitEvent,
 	EmojiModel,
 	GuildDeleteEvent,
 	GuildModel,
@@ -8,10 +9,9 @@ import {
 	MessageModel,
 	RoleModel,
 	UserModel
-} from "@fosscord/server-util";
+} from "@fosscord/util";
 import { Router, Request, Response } from "express";
 import { HTTPError } from "lambert-server";
-import { emitEvent } from "../../../util/Event";
 
 const router = Router();
 
diff --git a/api/src/routes/guilds/#guild_id/index.ts b/api/src/routes/guilds/#guild_id/index.ts
index dc4ddb39..1afa603f 100644
--- a/api/src/routes/guilds/#guild_id/index.ts
+++ b/api/src/routes/guilds/#guild_id/index.ts
@@ -1,6 +1,7 @@
 import { Request, Response, Router } from "express";
 import {
 	ChannelModel,
+	emitEvent,
 	EmojiModel,
 	getPermission,
 	GuildDeleteEvent,
@@ -12,10 +13,10 @@ import {
 	RoleModel,
 	toObject,
 	UserModel
-} from "@fosscord/server-util";
+} from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { GuildUpdateSchema } from "../../../schema/Guild";
-import { emitEvent } from "../../../util/Event";
+
 import { check } from "../../../util/instanceOf";
 import { handleFile } from "../../../util/cdn";
 import "missing-native-js-functions";
diff --git a/api/src/routes/guilds/#guild_id/invites.ts b/api/src/routes/guilds/#guild_id/invites.ts
index 1894ec96..08048d61 100644
--- a/api/src/routes/guilds/#guild_id/invites.ts
+++ b/api/src/routes/guilds/#guild_id/invites.ts
@@ -1,4 +1,4 @@
-import { getPermission, InviteModel, toObject } from "@fosscord/server-util";
+import { getPermission, InviteModel, toObject } from "@fosscord/util";
 import { Request, Response, Router } from "express";
 
 const router = Router();
diff --git a/api/src/routes/guilds/#guild_id/members/#member_id/index.ts b/api/src/routes/guilds/#guild_id/members/#member_id/index.ts
index 9a1676e6..eac6684a 100644
--- a/api/src/routes/guilds/#guild_id/members/#member_id/index.ts
+++ b/api/src/routes/guilds/#guild_id/members/#member_id/index.ts
@@ -8,13 +8,13 @@ import {
 	getPermission,
 	PermissionResolvable,
 	RoleModel,
-	GuildMemberUpdateEvent
-} from "@fosscord/server-util";
+	GuildMemberUpdateEvent,
+	emitEvent
+} from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { addMember, isMember, removeMember } from "../../../../../util/Member";
 import { check } from "../../../../../util/instanceOf";
 import { MemberChangeSchema } from "../../../../../schema/Member";
-import { emitEvent } from "../../../../../util/Event";
 
 const router = Router();
 
diff --git a/api/src/routes/guilds/#guild_id/members/#member_id/nick.ts b/api/src/routes/guilds/#guild_id/members/#member_id/nick.ts
index 9078409d..5784b5d5 100644
--- a/api/src/routes/guilds/#guild_id/members/#member_id/nick.ts
+++ b/api/src/routes/guilds/#guild_id/members/#member_id/nick.ts
@@ -1,4 +1,4 @@
-import { getPermission, PermissionResolvable } from "@fosscord/server-util";
+import { getPermission, PermissionResolvable } from "@fosscord/util";
 import { Request, Response, Router } from "express";
 import { check } from "lambert-server";
 import { MemberNickChangeSchema } from "../../../../../schema/Member";
diff --git a/api/src/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts b/api/src/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts
index b7a43c74..fad0695e 100644
--- a/api/src/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts
+++ b/api/src/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts
@@ -1,4 +1,4 @@
-import { getPermission } from "@fosscord/server-util";
+import { getPermission } from "@fosscord/util";
 import { Request, Response, Router } from "express";
 import { addRole, removeRole } from "../../../../../../../util/Member";
 
diff --git a/api/src/routes/guilds/#guild_id/members/index.ts b/api/src/routes/guilds/#guild_id/members/index.ts
index a157d8f5..70303436 100644
--- a/api/src/routes/guilds/#guild_id/members/index.ts
+++ b/api/src/routes/guilds/#guild_id/members/index.ts
@@ -1,5 +1,5 @@
 import { Request, Response, Router } from "express";
-import { GuildModel, MemberModel, toObject } from "@fosscord/server-util";
+import { GuildModel, MemberModel, toObject } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { instanceOf, Length } from "../../../../util/instanceOf";
 import { PublicMemberProjection, isMember } from "../../../../util/Member";
diff --git a/api/src/routes/guilds/#guild_id/regions.ts b/api/src/routes/guilds/#guild_id/regions.ts
index 3a46d766..5ec649ee 100644
--- a/api/src/routes/guilds/#guild_id/regions.ts
+++ b/api/src/routes/guilds/#guild_id/regions.ts
@@ -1,4 +1,4 @@
-import { Config } from "@fosscord/server-util";
+import { Config } from "@fosscord/util";
 import { Request, Response, Router } from "express";
 
 const router = Router();
@@ -7,4 +7,4 @@ router.get("/", async (req: Request, res: Response) => {
 	return res.json(Config.get().regions.available);
 });
 
-export default router;
\ No newline at end of file
+export default router;
diff --git a/api/src/routes/guilds/#guild_id/roles.ts b/api/src/routes/guilds/#guild_id/roles.ts
index 77206a0f..a4bc44e0 100644
--- a/api/src/routes/guilds/#guild_id/roles.ts
+++ b/api/src/routes/guilds/#guild_id/roles.ts
@@ -9,10 +9,11 @@ import {
 	MemberModel,
 	GuildRoleCreateEvent,
 	GuildRoleUpdateEvent,
-	GuildRoleDeleteEvent
-} from "@fosscord/server-util";
+	GuildRoleDeleteEvent,
+	emitEvent
+} from "@fosscord/util";
 import { HTTPError } from "lambert-server";
-import { emitEvent } from "../../../util/Event";
+
 import { check } from "../../../util/instanceOf";
 import { RoleModifySchema } from "../../../schema/Roles";
 import { getPublicUser } from "../../../util/User";
diff --git a/api/src/routes/guilds/#guild_id/templates.ts b/api/src/routes/guilds/#guild_id/templates.ts
index 8306ac37..fdca1c40 100644
--- a/api/src/routes/guilds/#guild_id/templates.ts
+++ b/api/src/routes/guilds/#guild_id/templates.ts
@@ -1,5 +1,5 @@
 import { Request, Response, Router } from "express";
-import { TemplateModel, GuildModel, getPermission, toObject, UserModel, Snowflake } from "@fosscord/server-util";
+import { TemplateModel, GuildModel, getPermission, toObject, UserModel, Snowflake } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { TemplateCreateSchema, TemplateModifySchema } from "../../../schema/Template";
 import { check } from "../../../util/instanceOf";
diff --git a/api/src/routes/guilds/#guild_id/vanity-url.ts b/api/src/routes/guilds/#guild_id/vanity-url.ts
index 323b2647..86adfeb0 100644
--- a/api/src/routes/guilds/#guild_id/vanity-url.ts
+++ b/api/src/routes/guilds/#guild_id/vanity-url.ts
@@ -1,4 +1,4 @@
-import { getPermission, GuildModel, InviteModel, trimSpecial } from "@fosscord/server-util";
+import { getPermission, GuildModel, InviteModel, trimSpecial } from "@fosscord/util";
 import { Router, Request, Response } from "express";
 import { HTTPError } from "lambert-server";
 import { check, Length } from "../../../util/instanceOf";
diff --git a/api/src/routes/guilds/#guild_id/welcome_screen.ts b/api/src/routes/guilds/#guild_id/welcome_screen.ts
index 656a0ee0..c717042e 100644
--- a/api/src/routes/guilds/#guild_id/welcome_screen.ts
+++ b/api/src/routes/guilds/#guild_id/welcome_screen.ts
@@ -1,7 +1,7 @@
 import { Request, Response, Router } from "express";
-import { GuildModel, getPermission, toObject, Snowflake } from "@fosscord/server-util";
+import { GuildModel, getPermission, toObject, Snowflake } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
-import { emitEvent } from "../../../util/Event";
+
 import { check } from "../../../util/instanceOf";
 import { isMember } from "../../../util/Member";
 import { GuildAddChannelToWelcomeScreenSchema } from "../../../schema/Guild";
diff --git a/api/src/routes/guilds/#guild_id/widget.json.ts b/api/src/routes/guilds/#guild_id/widget.json.ts
index 6f777ab4..8719bd85 100644
--- a/api/src/routes/guilds/#guild_id/widget.json.ts
+++ b/api/src/routes/guilds/#guild_id/widget.json.ts
@@ -1,5 +1,5 @@
 import { Request, Response, Router } from "express";
-import { Config, Permissions, GuildModel, InviteModel, ChannelModel, MemberModel } from "@fosscord/server-util";
+import { Config, Permissions, GuildModel, InviteModel, ChannelModel, MemberModel } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { random } from "../../../util/RandomInviteID";
 
diff --git a/api/src/routes/guilds/#guild_id/widget.png.ts b/api/src/routes/guilds/#guild_id/widget.png.ts
index a0a8c938..80dc9f2b 100644
--- a/api/src/routes/guilds/#guild_id/widget.png.ts
+++ b/api/src/routes/guilds/#guild_id/widget.png.ts
@@ -1,5 +1,5 @@
 import { Request, Response, Router } from "express";
-import { GuildModel } from "@fosscord/server-util";
+import { GuildModel } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import fs from "fs";
 import path from "path";
diff --git a/api/src/routes/guilds/#guild_id/widget.ts b/api/src/routes/guilds/#guild_id/widget.ts
index 0e6df186..85eed5e9 100644
--- a/api/src/routes/guilds/#guild_id/widget.ts
+++ b/api/src/routes/guilds/#guild_id/widget.ts
@@ -1,5 +1,5 @@
 import { Request, Response, Router } from "express";
-import { getPermission, GuildModel } from "@fosscord/server-util";
+import { getPermission, GuildModel } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { check } from "../../../util/instanceOf";
 import { WidgetModifySchema } from "../../../schema/Widget";
diff --git a/api/src/routes/guilds/index.ts b/api/src/routes/guilds/index.ts
index 25b55896..c97a8205 100644
--- a/api/src/routes/guilds/index.ts
+++ b/api/src/routes/guilds/index.ts
@@ -1,5 +1,5 @@
 import { Router, Request, Response } from "express";
-import { RoleModel, GuildModel, Snowflake, Guild, RoleDocument, Config } from "@fosscord/server-util";
+import { RoleModel, GuildModel, Snowflake, Guild, RoleDocument, Config } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { check } from "./../../util/instanceOf";
 import { GuildCreateSchema } from "../../schema/Guild";
diff --git a/api/src/routes/guilds/templates/index.ts b/api/src/routes/guilds/templates/index.ts
index 0f332de0..7fed3c5d 100644
--- a/api/src/routes/guilds/templates/index.ts
+++ b/api/src/routes/guilds/templates/index.ts
@@ -1,6 +1,6 @@
 import { Request, Response, Router } from "express";
 const router: Router = Router();
-import { TemplateModel, GuildModel, toObject, UserModel, RoleModel, Snowflake, Guild, Config } from "@fosscord/server-util";
+import { TemplateModel, GuildModel, toObject, UserModel, RoleModel, Snowflake, Guild, Config } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { GuildTemplateCreateSchema } from "../../../schema/Guild";
 import { getPublicUser } from "../../../util/User";
diff --git a/api/src/routes/invites/index.ts b/api/src/routes/invites/index.ts
index 8c04713c..992694df 100644
--- a/api/src/routes/invites/index.ts
+++ b/api/src/routes/invites/index.ts
@@ -1,5 +1,5 @@
 import { Router, Request, Response } from "express";
-import { getPermission, InviteModel, toObject } from "@fosscord/server-util";
+import { getPermission, InviteModel, toObject } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { addMember } from "../../util/Member";
 const router: Router = Router();
diff --git a/api/src/routes/users/@me/channels.ts b/api/src/routes/users/@me/channels.ts
index a425a25f..db9f8832 100644
--- a/api/src/routes/users/@me/channels.ts
+++ b/api/src/routes/users/@me/channels.ts
@@ -8,10 +8,11 @@ import {
 	trimSpecial,
 	Channel,
 	DMChannel,
-	UserModel
-} from "@fosscord/server-util";
+	UserModel,
+	emitEvent
+} from "@fosscord/util";
 import { HTTPError } from "lambert-server";
-import { emitEvent } from "../../../util/Event";
+
 import { DmChannelCreateSchema } from "../../../schema/Channel";
 import { check } from "../../../util/instanceOf";
 
diff --git a/api/src/routes/users/@me/delete.ts b/api/src/routes/users/@me/delete.ts
index edda8e2d..f863237d 100644
--- a/api/src/routes/users/@me/delete.ts
+++ b/api/src/routes/users/@me/delete.ts
@@ -1,5 +1,5 @@
 import { Router, Request, Response } from "express";
-import { GuildModel, MemberModel, UserModel } from "@fosscord/server-util";
+import { GuildModel, MemberModel, UserModel } from "@fosscord/util";
 import bcrypt from "bcrypt";
 const router = Router();
 
diff --git a/api/src/routes/users/@me/disable.ts b/api/src/routes/users/@me/disable.ts
index 0e5b734e..2d3a9850 100644
--- a/api/src/routes/users/@me/disable.ts
+++ b/api/src/routes/users/@me/disable.ts
@@ -1,4 +1,4 @@
-import { UserModel } from "@fosscord/server-util";
+import { UserModel } from "@fosscord/util";
 import { Router, Response, Request } from "express";
 import bcrypt from "bcrypt";
 
diff --git a/api/src/routes/users/@me/guilds.ts b/api/src/routes/users/@me/guilds.ts
index 6528552b..a9b53b75 100644
--- a/api/src/routes/users/@me/guilds.ts
+++ b/api/src/routes/users/@me/guilds.ts
@@ -1,7 +1,7 @@
 import { Router, Request, Response } from "express";
-import { GuildModel, MemberModel, UserModel, GuildDeleteEvent, GuildMemberRemoveEvent, toObject } from "@fosscord/server-util";
+import { GuildModel, MemberModel, UserModel, GuildDeleteEvent, GuildMemberRemoveEvent, toObject, emitEvent } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
-import { emitEvent } from "../../../util/Event";
+
 import { getPublicUser } from "../../../util/User";
 
 const router: Router = Router();
@@ -32,10 +32,10 @@ router.delete("/:id", async (req: Request, res: Response) => {
 		emitEvent({
 			event: "GUILD_DELETE",
 			data: {
-				id: guild_id,
+				id: guild_id
 			},
-			user_id: req.user_id,
-		} as GuildDeleteEvent),
+			user_id: req.user_id
+		} as GuildDeleteEvent)
 	]);
 
 	const user = await getPublicUser(req.user_id);
@@ -44,9 +44,9 @@ router.delete("/:id", async (req: Request, res: Response) => {
 		event: "GUILD_MEMBER_REMOVE",
 		data: {
 			guild_id: guild_id,
-			user: user,
+			user: user
 		},
-		guild_id: guild_id,
+		guild_id: guild_id
 	} as GuildMemberRemoveEvent);
 
 	return res.sendStatus(204);
diff --git a/api/src/routes/users/@me/index.ts b/api/src/routes/users/@me/index.ts
index 7bd4a486..c073e78a 100644
--- a/api/src/routes/users/@me/index.ts
+++ b/api/src/routes/users/@me/index.ts
@@ -1,5 +1,5 @@
 import { Router, Request, Response } from "express";
-import { UserModel, toObject, PublicUserProjection } from "@fosscord/server-util";
+import { UserModel, toObject, PublicUserProjection } from "@fosscord/util";
 import { getPublicUser } from "../../../util/User";
 import { UserModifySchema } from "../../../schema/User";
 import { check } from "../../../util/instanceOf";
diff --git a/api/src/routes/users/@me/relationships.ts b/api/src/routes/users/@me/relationships.ts
index a8f03143..642ee5f9 100644
--- a/api/src/routes/users/@me/relationships.ts
+++ b/api/src/routes/users/@me/relationships.ts
@@ -5,11 +5,12 @@ import {
 	toObject,
 	RelationshipType,
 	RelationshipRemoveEvent,
-	UserDocument
-} from "@fosscord/server-util";
+	UserDocument,
+	emitEvent
+} from "@fosscord/util";
 import { Router, Response, Request } from "express";
 import { HTTPError } from "lambert-server";
-import { emitEvent } from "../../../util/Event";
+
 import { check, Length } from "../../../util/instanceOf";
 
 const router = Router();
diff --git a/api/src/schema/Channel.ts b/api/src/schema/Channel.ts
index 48c3a1d2..18a8f835 100644
--- a/api/src/schema/Channel.ts
+++ b/api/src/schema/Channel.ts
@@ -1,4 +1,4 @@
-import { ChannelType } from "@fosscord/server-util";
+import { ChannelType } from "@fosscord/util";
 import { Length } from "../util/instanceOf";
 
 export const ChannelModifySchema = {
diff --git a/api/src/schema/Guild.ts b/api/src/schema/Guild.ts
index 0443e64c..ce40b49f 100644
--- a/api/src/schema/Guild.ts
+++ b/api/src/schema/Guild.ts
@@ -1,4 +1,4 @@
-import { ChannelSchema, GuildChannel } from "@fosscord/server-util";
+import { ChannelSchema, GuildChannel } from "@fosscord/util";
 import { Length } from "../util/instanceOf";
 
 export const GuildCreateSchema = {
diff --git a/api/src/schema/Message.ts b/api/src/schema/Message.ts
index 8423d706..2dd54f0c 100644
--- a/api/src/schema/Message.ts
+++ b/api/src/schema/Message.ts
@@ -1,4 +1,4 @@
-import { Embed, EmbedImage } from "@fosscord/server-util";
+import { Embed, EmbedImage } from "@fosscord/util";
 import { Length } from "../util/instanceOf";
 
 export const MessageCreateSchema = {
diff --git a/api/src/test/test.ts b/api/src/test/test.ts
index 478edcc4..c37c762b 100644
--- a/api/src/test/test.ts
+++ b/api/src/test/test.ts
@@ -1,3 +1,3 @@
-import { Snowflake } from "@fosscord/server-util";
+import { Snowflake } from "@fosscord/util";
 
 console.log(Snowflake.deconstruct("0"));
diff --git a/api/src/util/Channel.ts b/api/src/util/Channel.ts
index 4d322812..ef04d521 100644
--- a/api/src/util/Channel.ts
+++ b/api/src/util/Channel.ts
@@ -2,18 +2,18 @@ import {
 	ChannelCreateEvent,
 	ChannelModel,
 	ChannelType,
+	emitEvent,
 	getPermission,
 	GuildModel,
 	Snowflake,
 	TextChannel,
+	toObject,
 	VoiceChannel
-} from "@fosscord/server-util";
+} from "@fosscord/util";
 import { HTTPError } from "lambert-server";
-import { emitEvent } from "./Event";
 
 // TODO: DM channel
 export async function createChannel(channel: Partial<TextChannel | VoiceChannel>, user_id: string = "0") {
-
 	// Always check if user has permission first
 	const permissions = await getPermission(user_id, channel.guild_id);
 	permissions.hasThrow("MANAGE_CHANNELS");
@@ -50,7 +50,7 @@ export async function createChannel(channel: Partial<TextChannel | VoiceChannel>
 		recipient_ids: null
 	}).save();
 
-	await emitEvent({ event: "CHANNEL_CREATE", data: channel, guild_id: channel.guild_id } as ChannelCreateEvent);
+	await emitEvent({ event: "CHANNEL_CREATE", data: toObject(channel), guild_id: channel.guild_id } as ChannelCreateEvent);
 
 	return channel;
 }
diff --git a/api/src/util/Config.ts b/api/src/util/Config.ts
index e2e0d312..c86afbe7 100644
--- a/api/src/util/Config.ts
+++ b/api/src/util/Config.ts
@@ -1,7 +1,7 @@
 // @ts-nocheck
 import Ajv, { JSONSchemaType } from "ajv";
-import { getConfigPathForFile } from "@fosscord/server-util/dist/util/Config";
-import { Config } from "@fosscord/server-util";
+import { getConfigPathForFile } from "@fosscord/util/dist/util/Config";
+import { Config } from "@fosscord/util";
 
 export interface RateLimitOptions {
 	count: number;
diff --git a/api/src/util/Event.ts b/api/src/util/Event.ts
deleted file mode 100644
index 4dd56417..00000000
--- a/api/src/util/Event.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import { Config, Event, EventModel, RabbitMQ } from "@fosscord/server-util";
-
-export async function emitEvent(payload: Omit<Event, "created_at">) {
-	if (RabbitMQ.connection) {
-		const id = (payload.channel_id || payload.user_id || payload.guild_id) as string;
-		if (!id) console.error("event doesn't contain any id", payload);
-		const data = typeof payload.data === "object" ? JSON.stringify(payload.data) : payload.data; // use rabbitmq for event transmission
-		await RabbitMQ.channel?.assertExchange(id, "fanout", { durable: false });
-
-		// assertQueue isn't needed, because a queue will automatically created if it doesn't exist
-		const successful = RabbitMQ.channel?.publish(id, "", Buffer.from(`${data}`), { type: payload.event });
-		if (!successful) throw new Error("failed to send event");
-	} else {
-		// use mongodb for event transmission
-		// TODO: use event emitter for local server bundle
-		const obj = {
-			created_at: new Date(), // in seconds
-			...payload
-		};
-		// TODO: bigint isn't working
-
-		return await new EventModel(obj).save();
-	}
-}
-
-export async function emitAuditLog(payload: any) {}
diff --git a/api/src/util/Member.ts b/api/src/util/Member.ts
index 7b06720b..ee3f64ad 100644
--- a/api/src/util/Member.ts
+++ b/api/src/util/Member.ts
@@ -11,11 +11,12 @@ import {
 	toObject,
 	UserModel,
 	GuildDocument,
-	Config
-} from "@fosscord/server-util";
+	Config,
+	emitEvent
+} from "@fosscord/util";
 
 import { HTTPError } from "lambert-server";
-import { emitEvent } from "./Event";
+
 import { getPublicUser } from "./User";
 
 export const PublicMemberProjection = {
diff --git a/api/src/util/Message.ts b/api/src/util/Message.ts
index e811f522..a55c3365 100644
--- a/api/src/util/Message.ts
+++ b/api/src/util/Message.ts
@@ -1,14 +1,14 @@
-import { ChannelModel, Embed, Message, MessageCreateEvent, MessageUpdateEvent } from "@fosscord/server-util";
-import { Snowflake } from "@fosscord/server-util";
-import { MessageModel } from "@fosscord/server-util";
-import { PublicMemberProjection } from "@fosscord/server-util";
-import { toObject } from "@fosscord/server-util";
-import { getPermission } from "@fosscord/server-util";
+import { ChannelModel, Embed, emitEvent, Message, MessageCreateEvent, MessageUpdateEvent } from "@fosscord/util";
+import { Snowflake } from "@fosscord/util";
+import { MessageModel } from "@fosscord/util";
+import { PublicMemberProjection } from "@fosscord/util";
+import { toObject } from "@fosscord/util";
+import { getPermission } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import fetch from "node-fetch";
 import cheerio from "cheerio";
-import { emitEvent } from "./Event";
-import { MessageType } from "@fosscord/server-util/dist/util/Constants";
+
+import { MessageType } from "@fosscord/util/dist/util/Constants";
 // TODO: check webhook, application, system author
 
 const LINK_REGEX = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/g;
diff --git a/api/src/util/User.ts b/api/src/util/User.ts
index 107fc759..392c7101 100644
--- a/api/src/util/User.ts
+++ b/api/src/util/User.ts
@@ -1,4 +1,4 @@
-import { toObject, UserModel, PublicUserProjection } from "@fosscord/server-util";
+import { toObject, UserModel, PublicUserProjection } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 
 export { PublicUserProjection };
diff --git a/api/src/util/cdn.ts b/api/src/util/cdn.ts
index aed8ca0a..3c71d980 100644
--- a/api/src/util/cdn.ts
+++ b/api/src/util/cdn.ts
@@ -1,4 +1,4 @@
-import { Config } from "@fosscord/server-util";
+import { Config } from "@fosscord/util";
 import FormData from "form-data";
 import { HTTPError } from "lambert-server";
 import fetch from "node-fetch";
diff --git a/api/src/util/ipAddress.ts b/api/src/util/ipAddress.ts
index f2c8fd4d..0a724daa 100644
--- a/api/src/util/ipAddress.ts
+++ b/api/src/util/ipAddress.ts
@@ -1,4 +1,4 @@
-import { Config } from "@fosscord/server-util";
+import { Config } from "@fosscord/util";
 import { Request } from "express";
 // use ipdata package instead of simple fetch because of integrated caching
 import fetch from "node-fetch";
diff --git a/api/src/util/passwordStrength.ts b/api/src/util/passwordStrength.ts
index cc503843..dfffa2c0 100644
--- a/api/src/util/passwordStrength.ts
+++ b/api/src/util/passwordStrength.ts
@@ -1,4 +1,4 @@
-import { Config } from "@fosscord/server-util";
+import { Config } from "@fosscord/util";
 import "missing-native-js-functions";
 
 const reNUMBER = /[0-9]/g;
diff --git a/bundle/package-lock.json b/bundle/package-lock.json
new file mode 100644
index 00000000..8f012973
--- /dev/null
+++ b/bundle/package-lock.json
@@ -0,0 +1,2750 @@
+{
+	"name": "@fosscord/server",
+	"version": "1.0.0",
+	"lockfileVersion": 2,
+	"requires": true,
+	"packages": {
+		"": {
+			"name": "@fosscord/server",
+			"version": "1.0.0",
+			"hasInstallScript": true,
+			"license": "AGPLV3",
+			"dependencies": {
+				"@fosscord/api": "file:../api",
+				"@fosscord/cdn": "file:../cdn",
+				"@fosscord/gateway": "file:../gateway",
+				"@fosscord/util": "file:../util",
+				"async-exit-hook": "^2.0.1",
+				"express": "^4.17.1",
+				"link": "^0.1.5",
+				"mongodb-memory-server-global-4.4": "^7.3.6",
+				"node-os-utils": "^1.3.5"
+			},
+			"devDependencies": {
+				"@types/async-exit-hook": "^2.0.0",
+				"@types/express": "^4.17.13",
+				"@types/node": "^16.6.1",
+				"@types/node-os-utils": "^1.2.0",
+				"typescript": "^4.3.5"
+			}
+		},
+		"../api": {
+			"name": "@fosscord/api",
+			"version": "1.0.0",
+			"hasInstallScript": true,
+			"license": "ISC",
+			"dependencies": {
+				"@fosscord/server-util": "^1.3.52",
+				"@fosscord/util": "file:../util",
+				"@types/jest": "^26.0.22",
+				"@types/json-schema": "^7.0.7",
+				"ajv": "^8.4.0",
+				"ajv-formats": "^2.1.0",
+				"amqplib": "^0.8.0",
+				"assert": "^1.5.0",
+				"atomically": "^1.7.0",
+				"bcrypt": "^5.0.1",
+				"body-parser": "^1.19.0",
+				"canvas": "^2.8.0",
+				"cheerio": "^1.0.0-rc.9",
+				"dot-prop": "^6.0.1",
+				"dotenv": "^8.2.0",
+				"env-paths": "^2.2.1",
+				"express": "^4.17.1",
+				"express-validator": "^6.9.2",
+				"form-data": "^3.0.0",
+				"i18next": "^19.8.5",
+				"i18next-http-middleware": "^3.1.3",
+				"i18next-node-fs-backend": "^2.1.3",
+				"image-size": "^1.0.0",
+				"jsonwebtoken": "^8.5.1",
+				"lambert-server": "^1.2.8",
+				"missing-native-js-functions": "^1.2.6",
+				"mongoose": "^5.12.3",
+				"mongoose-autopopulate": "^0.12.3",
+				"mongoose-long": "^0.3.2",
+				"multer": "^1.4.2",
+				"node-fetch": "^2.6.1",
+				"require_optional": "^1.0.1"
+			},
+			"devDependencies": {
+				"@types/amqplib": "^0.8.1",
+				"@types/bcrypt": "^5.0.0",
+				"@types/express": "^4.17.9",
+				"@types/i18next-node-fs-backend": "^2.1.0",
+				"@types/jsonwebtoken": "^8.5.0",
+				"@types/multer": "^1.4.5",
+				"@types/node": "^14.14.22",
+				"@types/node-fetch": "^2.5.7",
+				"@zerollup/ts-transform-paths": "^1.7.18",
+				"0x": "^4.10.2",
+				"caxa": "^2.1.0",
+				"jest": "^26.6.3",
+				"saslprep": "^1.0.3",
+				"ts-node": "^9.1.1",
+				"ts-node-dev": "^1.1.6",
+				"typescript": "^4.1.2"
+			}
+		},
+		"../cdn": {
+			"name": "@fosscord/cdn",
+			"version": "1.0.0",
+			"hasInstallScript": true,
+			"license": "ISC",
+			"dependencies": {
+				"@fosscord/server-util": "^1.3.42",
+				"@fosscord/util": "file:../util",
+				"body-parser": "^1.19.0",
+				"btoa": "^1.2.1",
+				"cheerio": "^1.0.0-rc.5",
+				"dotenv": "^10.0.0",
+				"exif-be-gone": "^1.2.0",
+				"express": "^4.17.1",
+				"express-async-errors": "^3.1.1",
+				"file-type": "^16.5.0",
+				"fs-extra": "^10.0.0",
+				"image-size": "^1.0.0",
+				"lambert-db": "^1.2.3",
+				"lambert-server": "^1.2.8",
+				"missing-native-js-functions": "^1.0.8",
+				"multer": "^1.4.2",
+				"node-fetch": "^2.6.1",
+				"uuid": "^8.3.2"
+			},
+			"devDependencies": {
+				"@types/body-parser": "^1.19.0",
+				"@types/btoa": "^1.2.3",
+				"@types/dotenv": "^8.2.0",
+				"@types/express": "^4.17.12",
+				"@types/fs-extra": "^9.0.12",
+				"@types/multer": "^1.4.7",
+				"@types/node": "^14.17.0",
+				"@types/node-fetch": "^2.5.7",
+				"@types/uuid": "^8.3.0"
+			}
+		},
+		"../gateway": {
+			"name": "@fosscord/gateway",
+			"version": "1.0.0",
+			"hasInstallScript": true,
+			"license": "ISC",
+			"dependencies": {
+				"@fosscord/server-util": "^1.3.51",
+				"@fosscord/util": "file:../util",
+				"ajv": "^8.5.0",
+				"amqplib": "^0.8.0",
+				"dotenv": "^8.2.0",
+				"jsonwebtoken": "^8.5.1",
+				"lambert-server": "^1.2.8",
+				"missing-native-js-functions": "^1.2.3",
+				"mongoose-autopopulate": "^0.12.3",
+				"node-fetch": "^2.6.1",
+				"typescript": "^4.2.3",
+				"uuid": "^8.3.2",
+				"ws": "^7.4.2"
+			},
+			"devDependencies": {
+				"@types/amqplib": "^0.8.1",
+				"@types/jsonwebtoken": "^8.5.0",
+				"@types/mongoose-autopopulate": "^0.10.1",
+				"@types/uuid": "^8.3.0",
+				"@types/ws": "^7.4.0",
+				"erlpack": "^0.1.3",
+				"ts-node-dev": "^1.1.6"
+			}
+		},
+		"../util": {
+			"name": "@fosscord/util",
+			"version": "1.3.52",
+			"license": "GPLV3",
+			"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",
+				"amqplib": "^0.8.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.9",
+				"mongoose": "^5.13.7",
+				"mongoose-autopopulate": "^0.12.3",
+				"typescript": "^4.1.3"
+			},
+			"devDependencies": {
+				"@types/amqplib": "^0.8.1"
+			}
+		},
+		"node_modules/@fosscord/api": {
+			"resolved": "../api",
+			"link": true
+		},
+		"node_modules/@fosscord/cdn": {
+			"resolved": "../cdn",
+			"link": true
+		},
+		"node_modules/@fosscord/gateway": {
+			"resolved": "../gateway",
+			"link": true
+		},
+		"node_modules/@fosscord/util": {
+			"resolved": "../util",
+			"link": true
+		},
+		"node_modules/@types/async-exit-hook": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/@types/async-exit-hook/-/async-exit-hook-2.0.0.tgz",
+			"integrity": "sha512-RNjIyjnVZdcP5a1zeIPb5c0hq2nbJc/NOCLNKUAqeCw+J5z2zMcINISn9wybCWhczHnUu3VSUFy7ZCO6ir4ZRw==",
+			"dev": true
+		},
+		"node_modules/@types/body-parser": {
+			"version": "1.19.1",
+			"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.1.tgz",
+			"integrity": "sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg==",
+			"dev": true,
+			"dependencies": {
+				"@types/connect": "*",
+				"@types/node": "*"
+			}
+		},
+		"node_modules/@types/connect": {
+			"version": "3.4.35",
+			"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz",
+			"integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==",
+			"dev": true,
+			"dependencies": {
+				"@types/node": "*"
+			}
+		},
+		"node_modules/@types/express": {
+			"version": "4.17.13",
+			"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz",
+			"integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==",
+			"dev": true,
+			"dependencies": {
+				"@types/body-parser": "*",
+				"@types/express-serve-static-core": "^4.17.18",
+				"@types/qs": "*",
+				"@types/serve-static": "*"
+			}
+		},
+		"node_modules/@types/express-serve-static-core": {
+			"version": "4.17.24",
+			"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz",
+			"integrity": "sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA==",
+			"dev": true,
+			"dependencies": {
+				"@types/node": "*",
+				"@types/qs": "*",
+				"@types/range-parser": "*"
+			}
+		},
+		"node_modules/@types/mime": {
+			"version": "1.3.2",
+			"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
+			"integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==",
+			"dev": true
+		},
+		"node_modules/@types/node": {
+			"version": "16.6.1",
+			"resolved": "https://registry.npmjs.org/@types/node/-/node-16.6.1.tgz",
+			"integrity": "sha512-Sr7BhXEAer9xyGuCN3Ek9eg9xPviCF2gfu9kTfuU2HkTVAMYSDeX40fvpmo72n5nansg3nsBjuQBrsS28r+NUw==",
+			"dev": true
+		},
+		"node_modules/@types/node-os-utils": {
+			"version": "1.2.0",
+			"resolved": "https://registry.npmjs.org/@types/node-os-utils/-/node-os-utils-1.2.0.tgz",
+			"integrity": "sha512-sstDo2s8gQR/Qh2Bd6yNQ5xJv+D4ttyB9ZVjB3mBm3VkGl2RoqjV7fiw9mIHLbshHSRm2m8uf0XrIRQNWB/z6A==",
+			"dev": true
+		},
+		"node_modules/@types/qs": {
+			"version": "6.9.7",
+			"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
+			"integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
+			"dev": true
+		},
+		"node_modules/@types/range-parser": {
+			"version": "1.2.4",
+			"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz",
+			"integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==",
+			"dev": true
+		},
+		"node_modules/@types/serve-static": {
+			"version": "1.13.10",
+			"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz",
+			"integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==",
+			"dev": true,
+			"dependencies": {
+				"@types/mime": "^1",
+				"@types/node": "*"
+			}
+		},
+		"node_modules/@types/tmp": {
+			"version": "0.2.1",
+			"resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.2.1.tgz",
+			"integrity": "sha512-7cTXwKP/HLOPVgjg+YhBdQ7bMiobGMuoBmrGmqwIWJv8elC6t1DfVc/mn4fD9UE1IjhwmhaQ5pGVXkmXbH0rhg=="
+		},
+		"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",
+			"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+			"dependencies": {
+				"debug": "4"
+			},
+			"engines": {
+				"node": ">= 6.0.0"
+			}
+		},
+		"node_modules/agent-base/node_modules/debug": {
+			"version": "4.3.2",
+			"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
+			"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
+			"dependencies": {
+				"ms": "2.1.2"
+			},
+			"engines": {
+				"node": ">=6.0"
+			},
+			"peerDependenciesMeta": {
+				"supports-color": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/agent-base/node_modules/ms": {
+			"version": "2.1.2",
+			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+			"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+		},
+		"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/async-exit-hook": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz",
+			"integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==",
+			"engines": {
+				"node": ">=0.12.0"
+			}
+		},
+		"node_modules/async-mutex": {
+			"version": "0.3.1",
+			"resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.3.1.tgz",
+			"integrity": "sha512-vRfQwcqBnJTLzVQo72Sf7KIUbcSUP5hNchx6udI1U6LuPQpfePgdjJzlCe76yFZ8pxlLjn9lwcl/Ya0TSOv0Tw==",
+			"dependencies": {
+				"tslib": "^2.1.0"
+			}
+		},
+		"node_modules/balanced-match": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+			"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+		},
+		"node_modules/base64-js": {
+			"version": "1.5.1",
+			"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+			"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+			"funding": [
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/feross"
+				},
+				{
+					"type": "patreon",
+					"url": "https://www.patreon.com/feross"
+				},
+				{
+					"type": "consulting",
+					"url": "https://feross.org/support"
+				}
+			]
+		},
+		"node_modules/bl": {
+			"version": "2.2.1",
+			"resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz",
+			"integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==",
+			"dependencies": {
+				"readable-stream": "^2.3.5",
+				"safe-buffer": "^5.1.1"
+			}
+		},
+		"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/brace-expansion": {
+			"version": "1.1.11",
+			"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+			"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+			"dependencies": {
+				"balanced-match": "^1.0.0",
+				"concat-map": "0.0.1"
+			}
+		},
+		"node_modules/bson": {
+			"version": "1.1.6",
+			"resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz",
+			"integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==",
+			"engines": {
+				"node": ">=0.6.19"
+			}
+		},
+		"node_modules/buffer": {
+			"version": "5.7.1",
+			"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+			"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+			"funding": [
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/feross"
+				},
+				{
+					"type": "patreon",
+					"url": "https://www.patreon.com/feross"
+				},
+				{
+					"type": "consulting",
+					"url": "https://feross.org/support"
+				}
+			],
+			"dependencies": {
+				"base64-js": "^1.3.1",
+				"ieee754": "^1.1.13"
+			}
+		},
+		"node_modules/buffer-crc32": {
+			"version": "0.2.13",
+			"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+			"integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
+			"engines": {
+				"node": "*"
+			}
+		},
+		"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/camelcase": {
+			"version": "6.2.0",
+			"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz",
+			"integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==",
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/commondir": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+			"integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs="
+		},
+		"node_modules/concat-map": {
+			"version": "0.0.1",
+			"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+			"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+		},
+		"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-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/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",
+			"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+		},
+		"node_modules/debug": {
+			"version": "2.6.9",
+			"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+			"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+			"dependencies": {
+				"ms": "2.0.0"
+			}
+		},
+		"node_modules/denque": {
+			"version": "1.5.0",
+			"resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz",
+			"integrity": "sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ==",
+			"engines": {
+				"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/ee-first": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+			"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+		},
+		"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/end-of-stream": {
+			"version": "1.4.4",
+			"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+			"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+			"dependencies": {
+				"once": "^1.4.0"
+			}
+		},
+		"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/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/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/fd-slicer": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+			"integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
+			"dependencies": {
+				"pend": "~1.2.0"
+			}
+		},
+		"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-cache-dir": {
+			"version": "3.3.1",
+			"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz",
+			"integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==",
+			"dependencies": {
+				"commondir": "^1.0.1",
+				"make-dir": "^3.0.2",
+				"pkg-dir": "^4.1.0"
+			},
+			"engines": {
+				"node": ">=8"
+			},
+			"funding": {
+				"url": "https://github.com/avajs/find-cache-dir?sponsor=1"
+			}
+		},
+		"node_modules/find-up": {
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+			"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+			"dependencies": {
+				"locate-path": "^5.0.0",
+				"path-exists": "^4.0.0"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"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-constants": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+			"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
+		},
+		"node_modules/fs.realpath": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+			"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+		},
+		"node_modules/get-port": {
+			"version": "5.1.1",
+			"resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz",
+			"integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==",
+			"engines": {
+				"node": ">=8"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/glob": {
+			"version": "7.1.7",
+			"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
+			"integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
+			"dependencies": {
+				"fs.realpath": "^1.0.0",
+				"inflight": "^1.0.4",
+				"inherits": "2",
+				"minimatch": "^3.0.4",
+				"once": "^1.3.0",
+				"path-is-absolute": "^1.0.0"
+			},
+			"engines": {
+				"node": "*"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/isaacs"
+			}
+		},
+		"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/https-proxy-agent": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
+			"integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
+			"dependencies": {
+				"agent-base": "6",
+				"debug": "4"
+			},
+			"engines": {
+				"node": ">= 6"
+			}
+		},
+		"node_modules/https-proxy-agent/node_modules/debug": {
+			"version": "4.3.2",
+			"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
+			"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
+			"dependencies": {
+				"ms": "2.1.2"
+			},
+			"engines": {
+				"node": ">=6.0"
+			},
+			"peerDependenciesMeta": {
+				"supports-color": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/https-proxy-agent/node_modules/ms": {
+			"version": "2.1.2",
+			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+			"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+		},
+		"node_modules/iconv-lite": {
+			"version": "0.4.24",
+			"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+			"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+			"dependencies": {
+				"safer-buffer": ">= 2.1.2 < 3"
+			},
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/ieee754": {
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+			"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+			"funding": [
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/feross"
+				},
+				{
+					"type": "patreon",
+					"url": "https://www.patreon.com/feross"
+				},
+				{
+					"type": "consulting",
+					"url": "https://feross.org/support"
+				}
+			]
+		},
+		"node_modules/inflight": {
+			"version": "1.0.6",
+			"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+			"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+			"dependencies": {
+				"once": "^1.3.0",
+				"wrappy": "1"
+			}
+		},
+		"node_modules/inherits": {
+			"version": "2.0.3",
+			"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+			"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+		},
+		"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/isarray": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+			"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+		},
+		"node_modules/link": {
+			"version": "0.1.5",
+			"resolved": "https://registry.npmjs.org/link/-/link-0.1.5.tgz",
+			"integrity": "sha1-f8eqW9P2rFoZxSVaI/QgfWhS6S4=",
+			"bin": {
+				"link.js": "Source/Node/link.js",
+				"linkjs": "Source/Node/link.js"
+			},
+			"engines": {
+				"node": "> 0.4.x < 0.9.0"
+			}
+		},
+		"node_modules/locate-path": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+			"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+			"dependencies": {
+				"p-locate": "^4.1.0"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/lru-cache": {
+			"version": "6.0.0",
+			"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+			"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+			"dependencies": {
+				"yallist": "^4.0.0"
+			},
+			"engines": {
+				"node": ">=10"
+			}
+		},
+		"node_modules/make-dir": {
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+			"integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+			"dependencies": {
+				"semver": "^6.0.0"
+			},
+			"engines": {
+				"node": ">=8"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/make-dir/node_modules/semver": {
+			"version": "6.3.0",
+			"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+			"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+			"bin": {
+				"semver": "bin/semver.js"
+			}
+		},
+		"node_modules/md5-file": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/md5-file/-/md5-file-5.0.0.tgz",
+			"integrity": "sha512-xbEFXCYVWrSx/gEKS1VPlg84h/4L20znVIulKw6kMfmBUAZNAnF00eczz9ICMl+/hjQGo5KSXRxbL/47X3rmMw==",
+			"bin": {
+				"md5-file": "cli.js"
+			},
+			"engines": {
+				"node": ">=10.13.0"
+			}
+		},
+		"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",
+			"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
+			"optional": 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/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/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==",
+			"engines": {
+				"node": ">= 0.6"
+			}
+		},
+		"node_modules/mime-types": {
+			"version": "2.1.32",
+			"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz",
+			"integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==",
+			"dependencies": {
+				"mime-db": "1.49.0"
+			},
+			"engines": {
+				"node": ">= 0.6"
+			}
+		},
+		"node_modules/minimatch": {
+			"version": "3.0.4",
+			"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+			"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+			"dependencies": {
+				"brace-expansion": "^1.1.7"
+			},
+			"engines": {
+				"node": "*"
+			}
+		},
+		"node_modules/mkdirp": {
+			"version": "1.0.4",
+			"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+			"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+			"bin": {
+				"mkdirp": "bin/cmd.js"
+			},
+			"engines": {
+				"node": ">=10"
+			}
+		},
+		"node_modules/mongodb": {
+			"version": "3.6.11",
+			"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.11.tgz",
+			"integrity": "sha512-4Y4lTFHDHZZdgMaHmojtNAlqkvddX2QQBEN0K//GzxhGwlI9tZ9R0vhbjr1Decw+TF7qK0ZLjQT292XgHRRQgw==",
+			"dependencies": {
+				"bl": "^2.2.1",
+				"bson": "^1.1.4",
+				"denque": "^1.4.1",
+				"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/mongodb-memory-server-core": {
+			"version": "7.3.6",
+			"resolved": "https://registry.npmjs.org/mongodb-memory-server-core/-/mongodb-memory-server-core-7.3.6.tgz",
+			"integrity": "sha512-dxprJ5Xqb0y/9nqv709BGf8Cz4dnInhG3sTuYvMJijK4cAHYxk0xkKrvZX2X9PrYiCQqKix59hHMBGyBetN3hg==",
+			"dependencies": {
+				"@types/tmp": "^0.2.0",
+				"async-mutex": "^0.3.0",
+				"camelcase": "^6.1.0",
+				"debug": "^4.2.0",
+				"find-cache-dir": "^3.3.1",
+				"get-port": "^5.1.1",
+				"https-proxy-agent": "^5.0.0",
+				"md5-file": "^5.0.0",
+				"mkdirp": "^1.0.4",
+				"mongodb": "^3.6.9",
+				"new-find-package-json": "^1.1.0",
+				"semver": "^7.3.5",
+				"tar-stream": "^2.1.4",
+				"tmp": "^0.2.1",
+				"tslib": "^2.3.0",
+				"uuid": "^8.3.1",
+				"yauzl": "^2.10.0"
+			},
+			"engines": {
+				"node": ">=12.22.0"
+			}
+		},
+		"node_modules/mongodb-memory-server-core/node_modules/debug": {
+			"version": "4.3.2",
+			"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
+			"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
+			"dependencies": {
+				"ms": "2.1.2"
+			},
+			"engines": {
+				"node": ">=6.0"
+			},
+			"peerDependenciesMeta": {
+				"supports-color": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/mongodb-memory-server-core/node_modules/ms": {
+			"version": "2.1.2",
+			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+			"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+		},
+		"node_modules/mongodb-memory-server-global-4.4": {
+			"version": "7.3.6",
+			"resolved": "https://registry.npmjs.org/mongodb-memory-server-global-4.4/-/mongodb-memory-server-global-4.4-7.3.6.tgz",
+			"integrity": "sha512-Qd7RwXvcwjlTKRvVyXZYF5rTlbnyBt8RK445+hqLzsMveQVmPK1VV4NWuEQ7JW3MWE/8CAVsNg+llIQBk0HfGw==",
+			"hasInstallScript": true,
+			"dependencies": {
+				"mongodb-memory-server-core": "7.3.6",
+				"tslib": "^2.3.0"
+			},
+			"engines": {
+				"node": ">=12.22.0"
+			}
+		},
+		"node_modules/ms": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+			"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+		},
+		"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/new-find-package-json": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/new-find-package-json/-/new-find-package-json-1.1.0.tgz",
+			"integrity": "sha512-KOH3BNZcTKPzEkaJgG2iSUaurxKmefqRKmCOYH+8xqJytNIgjqU4J88BHfK+gy/UlEzlhccLyuJDJAcCgexSwA==",
+			"dependencies": {
+				"debug": "^4.3.2",
+				"tslib": "^2.3.0"
+			},
+			"engines": {
+				"node": ">=12.22.0"
+			}
+		},
+		"node_modules/new-find-package-json/node_modules/debug": {
+			"version": "4.3.2",
+			"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
+			"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
+			"dependencies": {
+				"ms": "2.1.2"
+			},
+			"engines": {
+				"node": ">=6.0"
+			},
+			"peerDependenciesMeta": {
+				"supports-color": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/new-find-package-json/node_modules/ms": {
+			"version": "2.1.2",
+			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+			"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+		},
+		"node_modules/node-os-utils": {
+			"version": "1.3.5",
+			"resolved": "https://registry.npmjs.org/node-os-utils/-/node-os-utils-1.3.5.tgz",
+			"integrity": "sha512-bIJIlk+hA+7/ATnu3sQMtF697iw9T/JksDhKMe9uENG0OhzIG7hLM6fbcyu18bOuajlYWnSlj0IhDo2q7k0ebg=="
+		},
+		"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",
+			"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+			"dependencies": {
+				"wrappy": "1"
+			}
+		},
+		"node_modules/optional-require": {
+			"version": "1.1.6",
+			"resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.1.6.tgz",
+			"integrity": "sha512-ZO2GGh1A84LV90OAIsMDmIJ5k/f7crSjP4aJSuLudp7C7wfVOAoyWWHV8Jf3ZMHyNHwpLD/DGhzaxbbN/duF+g==",
+			"dependencies": {
+				"require-at": "^1.0.6"
+			},
+			"engines": {
+				"node": ">=4"
+			}
+		},
+		"node_modules/p-limit": {
+			"version": "2.3.0",
+			"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+			"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+			"dependencies": {
+				"p-try": "^2.0.0"
+			},
+			"engines": {
+				"node": ">=6"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/p-locate": {
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+			"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+			"dependencies": {
+				"p-limit": "^2.2.0"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/p-try": {
+			"version": "2.2.0",
+			"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+			"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+			"engines": {
+				"node": ">=6"
+			}
+		},
+		"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/path-exists": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+			"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/path-is-absolute": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+			"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"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/pend": {
+			"version": "1.2.0",
+			"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+			"integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA="
+		},
+		"node_modules/pkg-dir": {
+			"version": "4.2.0",
+			"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+			"integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+			"dependencies": {
+				"find-up": "^4.0.0"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/process-nextick-args": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+			"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+		},
+		"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/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/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/readable-stream": {
+			"version": "2.3.7",
+			"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+			"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+			"dependencies": {
+				"core-util-is": "~1.0.0",
+				"inherits": "~2.0.3",
+				"isarray": "~1.0.0",
+				"process-nextick-args": "~2.0.0",
+				"safe-buffer": "~5.1.1",
+				"string_decoder": "~1.1.1",
+				"util-deprecate": "~1.0.1"
+			}
+		},
+		"node_modules/require-at": {
+			"version": "1.0.6",
+			"resolved": "https://registry.npmjs.org/require-at/-/require-at-1.0.6.tgz",
+			"integrity": "sha512-7i1auJbMUrXEAZCOQ0VNJgmcT2VOKPRl2YGJwgpHpC9CE91Mv4/4UYIUm4chGJaI381ZDq1JUicFii64Hapd8g==",
+			"engines": {
+				"node": ">=4"
+			}
+		},
+		"node_modules/rimraf": {
+			"version": "3.0.2",
+			"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+			"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+			"dependencies": {
+				"glob": "^7.1.3"
+			},
+			"bin": {
+				"rimraf": "bin.js"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/isaacs"
+			}
+		},
+		"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/safer-buffer": {
+			"version": "2.1.2",
+			"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+			"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+		},
+		"node_modules/saslprep": {
+			"version": "1.0.3",
+			"resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
+			"integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==",
+			"optional": true,
+			"dependencies": {
+				"sparse-bitfield": "^3.0.3"
+			},
+			"engines": {
+				"node": ">=6"
+			}
+		},
+		"node_modules/semver": {
+			"version": "7.3.5",
+			"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+			"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
+			"dependencies": {
+				"lru-cache": "^6.0.0"
+			},
+			"bin": {
+				"semver": "bin/semver.js"
+			},
+			"engines": {
+				"node": ">=10"
+			}
+		},
+		"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/setprototypeof": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
+			"integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
+		},
+		"node_modules/sparse-bitfield": {
+			"version": "3.0.3",
+			"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
+			"integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=",
+			"optional": true,
+			"dependencies": {
+				"memory-pager": "^1.0.2"
+			}
+		},
+		"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": "1.1.1",
+			"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+			"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+			"dependencies": {
+				"safe-buffer": "~5.1.0"
+			}
+		},
+		"node_modules/tar-stream": {
+			"version": "2.2.0",
+			"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+			"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
+			"dependencies": {
+				"bl": "^4.0.3",
+				"end-of-stream": "^1.4.1",
+				"fs-constants": "^1.0.0",
+				"inherits": "^2.0.3",
+				"readable-stream": "^3.1.1"
+			},
+			"engines": {
+				"node": ">=6"
+			}
+		},
+		"node_modules/tar-stream/node_modules/bl": {
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+			"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+			"dependencies": {
+				"buffer": "^5.5.0",
+				"inherits": "^2.0.4",
+				"readable-stream": "^3.4.0"
+			}
+		},
+		"node_modules/tar-stream/node_modules/inherits": {
+			"version": "2.0.4",
+			"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+			"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+		},
+		"node_modules/tar-stream/node_modules/readable-stream": {
+			"version": "3.6.0",
+			"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+			"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+			"dependencies": {
+				"inherits": "^2.0.3",
+				"string_decoder": "^1.1.1",
+				"util-deprecate": "^1.0.1"
+			},
+			"engines": {
+				"node": ">= 6"
+			}
+		},
+		"node_modules/tmp": {
+			"version": "0.2.1",
+			"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
+			"integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
+			"dependencies": {
+				"rimraf": "^3.0.0"
+			},
+			"engines": {
+				"node": ">=8.17.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/tslib": {
+			"version": "2.3.1",
+			"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
+			"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
+		},
+		"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/typescript": {
+			"version": "4.3.5",
+			"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
+			"integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==",
+			"dev": true,
+			"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",
+			"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
+			"engines": {
+				"node": ">= 0.8"
+			}
+		},
+		"node_modules/util-deprecate": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+			"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+		},
+		"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": "8.3.2",
+			"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+			"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+			"bin": {
+				"uuid": "dist/bin/uuid"
+			}
+		},
+		"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/wrappy": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+			"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+		},
+		"node_modules/yallist": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+			"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+		},
+		"node_modules/yauzl": {
+			"version": "2.10.0",
+			"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+			"integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
+			"dependencies": {
+				"buffer-crc32": "~0.2.3",
+				"fd-slicer": "~1.1.0"
+			}
+		}
+	},
+	"dependencies": {
+		"@fosscord/api": {
+			"version": "file:../api",
+			"requires": {
+				"@fosscord/server-util": "^1.3.52",
+				"@fosscord/util": "file:../util",
+				"@types/amqplib": "^0.8.1",
+				"@types/bcrypt": "^5.0.0",
+				"@types/express": "^4.17.9",
+				"@types/i18next-node-fs-backend": "^2.1.0",
+				"@types/jest": "^26.0.22",
+				"@types/json-schema": "^7.0.7",
+				"@types/jsonwebtoken": "^8.5.0",
+				"@types/multer": "^1.4.5",
+				"@types/node": "^14.14.22",
+				"@types/node-fetch": "^2.5.7",
+				"@zerollup/ts-transform-paths": "^1.7.18",
+				"0x": "^4.10.2",
+				"ajv": "^8.4.0",
+				"ajv-formats": "^2.1.0",
+				"amqplib": "^0.8.0",
+				"assert": "^1.5.0",
+				"atomically": "^1.7.0",
+				"bcrypt": "^5.0.1",
+				"body-parser": "^1.19.0",
+				"canvas": "^2.8.0",
+				"caxa": "^2.1.0",
+				"cheerio": "^1.0.0-rc.9",
+				"dot-prop": "^6.0.1",
+				"dotenv": "^8.2.0",
+				"env-paths": "^2.2.1",
+				"express": "^4.17.1",
+				"express-validator": "^6.9.2",
+				"form-data": "^3.0.0",
+				"i18next": "^19.8.5",
+				"i18next-http-middleware": "^3.1.3",
+				"i18next-node-fs-backend": "^2.1.3",
+				"image-size": "^1.0.0",
+				"jest": "^26.6.3",
+				"jsonwebtoken": "^8.5.1",
+				"lambert-server": "^1.2.8",
+				"missing-native-js-functions": "^1.2.6",
+				"mongoose": "^5.12.3",
+				"mongoose-autopopulate": "^0.12.3",
+				"mongoose-long": "^0.3.2",
+				"multer": "^1.4.2",
+				"node-fetch": "^2.6.1",
+				"require_optional": "^1.0.1",
+				"saslprep": "^1.0.3",
+				"ts-node": "^9.1.1",
+				"ts-node-dev": "^1.1.6",
+				"typescript": "^4.1.2"
+			}
+		},
+		"@fosscord/cdn": {
+			"version": "file:../cdn",
+			"requires": {
+				"@fosscord/server-util": "^1.3.42",
+				"@fosscord/util": "file:../util",
+				"@types/body-parser": "^1.19.0",
+				"@types/btoa": "^1.2.3",
+				"@types/dotenv": "^8.2.0",
+				"@types/express": "^4.17.12",
+				"@types/fs-extra": "^9.0.12",
+				"@types/multer": "^1.4.7",
+				"@types/node": "^14.17.0",
+				"@types/node-fetch": "^2.5.7",
+				"@types/uuid": "^8.3.0",
+				"body-parser": "^1.19.0",
+				"btoa": "^1.2.1",
+				"cheerio": "^1.0.0-rc.5",
+				"dotenv": "^10.0.0",
+				"exif-be-gone": "^1.2.0",
+				"express": "^4.17.1",
+				"express-async-errors": "^3.1.1",
+				"file-type": "^16.5.0",
+				"fs-extra": "^10.0.0",
+				"image-size": "^1.0.0",
+				"lambert-db": "^1.2.3",
+				"lambert-server": "^1.2.8",
+				"missing-native-js-functions": "^1.0.8",
+				"multer": "^1.4.2",
+				"node-fetch": "^2.6.1",
+				"uuid": "^8.3.2"
+			}
+		},
+		"@fosscord/gateway": {
+			"version": "file:../gateway",
+			"requires": {
+				"@fosscord/server-util": "^1.3.51",
+				"@fosscord/util": "file:../util",
+				"@types/amqplib": "^0.8.1",
+				"@types/jsonwebtoken": "^8.5.0",
+				"@types/mongoose-autopopulate": "^0.10.1",
+				"@types/uuid": "^8.3.0",
+				"@types/ws": "^7.4.0",
+				"ajv": "^8.5.0",
+				"amqplib": "^0.8.0",
+				"dotenv": "^8.2.0",
+				"erlpack": "^0.1.3",
+				"jsonwebtoken": "^8.5.1",
+				"lambert-server": "^1.2.8",
+				"missing-native-js-functions": "^1.2.3",
+				"mongoose-autopopulate": "^0.12.3",
+				"node-fetch": "^2.6.1",
+				"ts-node-dev": "^1.1.6",
+				"typescript": "^4.2.3",
+				"uuid": "^8.3.2",
+				"ws": "^7.4.2"
+			}
+		},
+		"@fosscord/util": {
+			"version": "file:../util",
+			"requires": {
+				"@types/amqplib": "^0.8.1",
+				"@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",
+				"amqplib": "^0.8.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.9",
+				"mongoose": "^5.13.7",
+				"mongoose-autopopulate": "^0.12.3",
+				"typescript": "^4.1.3"
+			}
+		},
+		"@types/async-exit-hook": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/@types/async-exit-hook/-/async-exit-hook-2.0.0.tgz",
+			"integrity": "sha512-RNjIyjnVZdcP5a1zeIPb5c0hq2nbJc/NOCLNKUAqeCw+J5z2zMcINISn9wybCWhczHnUu3VSUFy7ZCO6ir4ZRw==",
+			"dev": true
+		},
+		"@types/body-parser": {
+			"version": "1.19.1",
+			"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.1.tgz",
+			"integrity": "sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg==",
+			"dev": true,
+			"requires": {
+				"@types/connect": "*",
+				"@types/node": "*"
+			}
+		},
+		"@types/connect": {
+			"version": "3.4.35",
+			"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz",
+			"integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==",
+			"dev": true,
+			"requires": {
+				"@types/node": "*"
+			}
+		},
+		"@types/express": {
+			"version": "4.17.13",
+			"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz",
+			"integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==",
+			"dev": true,
+			"requires": {
+				"@types/body-parser": "*",
+				"@types/express-serve-static-core": "^4.17.18",
+				"@types/qs": "*",
+				"@types/serve-static": "*"
+			}
+		},
+		"@types/express-serve-static-core": {
+			"version": "4.17.24",
+			"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz",
+			"integrity": "sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA==",
+			"dev": true,
+			"requires": {
+				"@types/node": "*",
+				"@types/qs": "*",
+				"@types/range-parser": "*"
+			}
+		},
+		"@types/mime": {
+			"version": "1.3.2",
+			"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
+			"integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==",
+			"dev": true
+		},
+		"@types/node": {
+			"version": "16.6.1",
+			"resolved": "https://registry.npmjs.org/@types/node/-/node-16.6.1.tgz",
+			"integrity": "sha512-Sr7BhXEAer9xyGuCN3Ek9eg9xPviCF2gfu9kTfuU2HkTVAMYSDeX40fvpmo72n5nansg3nsBjuQBrsS28r+NUw==",
+			"dev": true
+		},
+		"@types/node-os-utils": {
+			"version": "1.2.0",
+			"resolved": "https://registry.npmjs.org/@types/node-os-utils/-/node-os-utils-1.2.0.tgz",
+			"integrity": "sha512-sstDo2s8gQR/Qh2Bd6yNQ5xJv+D4ttyB9ZVjB3mBm3VkGl2RoqjV7fiw9mIHLbshHSRm2m8uf0XrIRQNWB/z6A==",
+			"dev": true
+		},
+		"@types/qs": {
+			"version": "6.9.7",
+			"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
+			"integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
+			"dev": true
+		},
+		"@types/range-parser": {
+			"version": "1.2.4",
+			"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz",
+			"integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==",
+			"dev": true
+		},
+		"@types/serve-static": {
+			"version": "1.13.10",
+			"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz",
+			"integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==",
+			"dev": true,
+			"requires": {
+				"@types/mime": "^1",
+				"@types/node": "*"
+			}
+		},
+		"@types/tmp": {
+			"version": "0.2.1",
+			"resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.2.1.tgz",
+			"integrity": "sha512-7cTXwKP/HLOPVgjg+YhBdQ7bMiobGMuoBmrGmqwIWJv8elC6t1DfVc/mn4fD9UE1IjhwmhaQ5pGVXkmXbH0rhg=="
+		},
+		"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",
+			"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+			"requires": {
+				"debug": "4"
+			},
+			"dependencies": {
+				"debug": {
+					"version": "4.3.2",
+					"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
+					"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
+					"requires": {
+						"ms": "2.1.2"
+					}
+				},
+				"ms": {
+					"version": "2.1.2",
+					"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+					"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+				}
+			}
+		},
+		"array-flatten": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+			"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+		},
+		"async-exit-hook": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz",
+			"integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw=="
+		},
+		"async-mutex": {
+			"version": "0.3.1",
+			"resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.3.1.tgz",
+			"integrity": "sha512-vRfQwcqBnJTLzVQo72Sf7KIUbcSUP5hNchx6udI1U6LuPQpfePgdjJzlCe76yFZ8pxlLjn9lwcl/Ya0TSOv0Tw==",
+			"requires": {
+				"tslib": "^2.1.0"
+			}
+		},
+		"balanced-match": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+			"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+		},
+		"base64-js": {
+			"version": "1.5.1",
+			"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+			"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
+		},
+		"bl": {
+			"version": "2.2.1",
+			"resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz",
+			"integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==",
+			"requires": {
+				"readable-stream": "^2.3.5",
+				"safe-buffer": "^5.1.1"
+			}
+		},
+		"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"
+			}
+		},
+		"brace-expansion": {
+			"version": "1.1.11",
+			"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+			"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+			"requires": {
+				"balanced-match": "^1.0.0",
+				"concat-map": "0.0.1"
+			}
+		},
+		"bson": {
+			"version": "1.1.6",
+			"resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz",
+			"integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg=="
+		},
+		"buffer": {
+			"version": "5.7.1",
+			"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+			"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+			"requires": {
+				"base64-js": "^1.3.1",
+				"ieee754": "^1.1.13"
+			}
+		},
+		"buffer-crc32": {
+			"version": "0.2.13",
+			"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+			"integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI="
+		},
+		"bytes": {
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+			"integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
+		},
+		"camelcase": {
+			"version": "6.2.0",
+			"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz",
+			"integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg=="
+		},
+		"commondir": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+			"integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs="
+		},
+		"concat-map": {
+			"version": "0.0.1",
+			"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+			"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+		},
+		"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"
+			}
+		},
+		"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=="
+		},
+		"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",
+			"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+		},
+		"debug": {
+			"version": "2.6.9",
+			"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+			"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+			"requires": {
+				"ms": "2.0.0"
+			}
+		},
+		"denque": {
+			"version": "1.5.0",
+			"resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz",
+			"integrity": "sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ=="
+		},
+		"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="
+		},
+		"ee-first": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+			"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+		},
+		"encodeurl": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+			"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
+		},
+		"end-of-stream": {
+			"version": "1.4.4",
+			"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+			"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+			"requires": {
+				"once": "^1.4.0"
+			}
+		},
+		"escape-html": {
+			"version": "1.0.3",
+			"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+			"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+		},
+		"etag": {
+			"version": "1.8.1",
+			"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+			"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
+		},
+		"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"
+			}
+		},
+		"fd-slicer": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+			"integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
+			"requires": {
+				"pend": "~1.2.0"
+			}
+		},
+		"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-cache-dir": {
+			"version": "3.3.1",
+			"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz",
+			"integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==",
+			"requires": {
+				"commondir": "^1.0.1",
+				"make-dir": "^3.0.2",
+				"pkg-dir": "^4.1.0"
+			}
+		},
+		"find-up": {
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+			"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+			"requires": {
+				"locate-path": "^5.0.0",
+				"path-exists": "^4.0.0"
+			}
+		},
+		"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-constants": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+			"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
+		},
+		"fs.realpath": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+			"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+		},
+		"get-port": {
+			"version": "5.1.1",
+			"resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz",
+			"integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ=="
+		},
+		"glob": {
+			"version": "7.1.7",
+			"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
+			"integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
+			"requires": {
+				"fs.realpath": "^1.0.0",
+				"inflight": "^1.0.4",
+				"inherits": "2",
+				"minimatch": "^3.0.4",
+				"once": "^1.3.0",
+				"path-is-absolute": "^1.0.0"
+			}
+		},
+		"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"
+			}
+		},
+		"https-proxy-agent": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
+			"integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
+			"requires": {
+				"agent-base": "6",
+				"debug": "4"
+			},
+			"dependencies": {
+				"debug": {
+					"version": "4.3.2",
+					"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
+					"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
+					"requires": {
+						"ms": "2.1.2"
+					}
+				},
+				"ms": {
+					"version": "2.1.2",
+					"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+					"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+				}
+			}
+		},
+		"iconv-lite": {
+			"version": "0.4.24",
+			"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+			"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+			"requires": {
+				"safer-buffer": ">= 2.1.2 < 3"
+			}
+		},
+		"ieee754": {
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+			"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
+		},
+		"inflight": {
+			"version": "1.0.6",
+			"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+			"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+			"requires": {
+				"once": "^1.3.0",
+				"wrappy": "1"
+			}
+		},
+		"inherits": {
+			"version": "2.0.3",
+			"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+			"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+		},
+		"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=="
+		},
+		"isarray": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+			"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+		},
+		"link": {
+			"version": "0.1.5",
+			"resolved": "https://registry.npmjs.org/link/-/link-0.1.5.tgz",
+			"integrity": "sha1-f8eqW9P2rFoZxSVaI/QgfWhS6S4="
+		},
+		"locate-path": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+			"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+			"requires": {
+				"p-locate": "^4.1.0"
+			}
+		},
+		"lru-cache": {
+			"version": "6.0.0",
+			"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+			"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+			"requires": {
+				"yallist": "^4.0.0"
+			}
+		},
+		"make-dir": {
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+			"integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+			"requires": {
+				"semver": "^6.0.0"
+			},
+			"dependencies": {
+				"semver": {
+					"version": "6.3.0",
+					"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+					"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+				}
+			}
+		},
+		"md5-file": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/md5-file/-/md5-file-5.0.0.tgz",
+			"integrity": "sha512-xbEFXCYVWrSx/gEKS1VPlg84h/4L20znVIulKw6kMfmBUAZNAnF00eczz9ICMl+/hjQGo5KSXRxbL/47X3rmMw=="
+		},
+		"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",
+			"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
+			"optional": true
+		},
+		"merge-descriptors": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+			"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
+		},
+		"methods": {
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+			"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
+		},
+		"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=="
+		},
+		"mime-types": {
+			"version": "2.1.32",
+			"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz",
+			"integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==",
+			"requires": {
+				"mime-db": "1.49.0"
+			}
+		},
+		"minimatch": {
+			"version": "3.0.4",
+			"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+			"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+			"requires": {
+				"brace-expansion": "^1.1.7"
+			}
+		},
+		"mkdirp": {
+			"version": "1.0.4",
+			"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+			"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
+		},
+		"mongodb": {
+			"version": "3.6.11",
+			"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.11.tgz",
+			"integrity": "sha512-4Y4lTFHDHZZdgMaHmojtNAlqkvddX2QQBEN0K//GzxhGwlI9tZ9R0vhbjr1Decw+TF7qK0ZLjQT292XgHRRQgw==",
+			"requires": {
+				"bl": "^2.2.1",
+				"bson": "^1.1.4",
+				"denque": "^1.4.1",
+				"optional-require": "^1.0.3",
+				"safe-buffer": "^5.1.2",
+				"saslprep": "^1.0.0"
+			}
+		},
+		"mongodb-memory-server-core": {
+			"version": "7.3.6",
+			"resolved": "https://registry.npmjs.org/mongodb-memory-server-core/-/mongodb-memory-server-core-7.3.6.tgz",
+			"integrity": "sha512-dxprJ5Xqb0y/9nqv709BGf8Cz4dnInhG3sTuYvMJijK4cAHYxk0xkKrvZX2X9PrYiCQqKix59hHMBGyBetN3hg==",
+			"requires": {
+				"@types/tmp": "^0.2.0",
+				"async-mutex": "^0.3.0",
+				"camelcase": "^6.1.0",
+				"debug": "^4.2.0",
+				"find-cache-dir": "^3.3.1",
+				"get-port": "^5.1.1",
+				"https-proxy-agent": "^5.0.0",
+				"md5-file": "^5.0.0",
+				"mkdirp": "^1.0.4",
+				"mongodb": "^3.6.9",
+				"new-find-package-json": "^1.1.0",
+				"semver": "^7.3.5",
+				"tar-stream": "^2.1.4",
+				"tmp": "^0.2.1",
+				"tslib": "^2.3.0",
+				"uuid": "^8.3.1",
+				"yauzl": "^2.10.0"
+			},
+			"dependencies": {
+				"debug": {
+					"version": "4.3.2",
+					"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
+					"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
+					"requires": {
+						"ms": "2.1.2"
+					}
+				},
+				"ms": {
+					"version": "2.1.2",
+					"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+					"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+				}
+			}
+		},
+		"mongodb-memory-server-global-4.4": {
+			"version": "7.3.6",
+			"resolved": "https://registry.npmjs.org/mongodb-memory-server-global-4.4/-/mongodb-memory-server-global-4.4-7.3.6.tgz",
+			"integrity": "sha512-Qd7RwXvcwjlTKRvVyXZYF5rTlbnyBt8RK445+hqLzsMveQVmPK1VV4NWuEQ7JW3MWE/8CAVsNg+llIQBk0HfGw==",
+			"requires": {
+				"mongodb-memory-server-core": "7.3.6",
+				"tslib": "^2.3.0"
+			}
+		},
+		"ms": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+			"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+		},
+		"negotiator": {
+			"version": "0.6.2",
+			"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
+			"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
+		},
+		"new-find-package-json": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/new-find-package-json/-/new-find-package-json-1.1.0.tgz",
+			"integrity": "sha512-KOH3BNZcTKPzEkaJgG2iSUaurxKmefqRKmCOYH+8xqJytNIgjqU4J88BHfK+gy/UlEzlhccLyuJDJAcCgexSwA==",
+			"requires": {
+				"debug": "^4.3.2",
+				"tslib": "^2.3.0"
+			},
+			"dependencies": {
+				"debug": {
+					"version": "4.3.2",
+					"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
+					"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
+					"requires": {
+						"ms": "2.1.2"
+					}
+				},
+				"ms": {
+					"version": "2.1.2",
+					"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+					"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+				}
+			}
+		},
+		"node-os-utils": {
+			"version": "1.3.5",
+			"resolved": "https://registry.npmjs.org/node-os-utils/-/node-os-utils-1.3.5.tgz",
+			"integrity": "sha512-bIJIlk+hA+7/ATnu3sQMtF697iw9T/JksDhKMe9uENG0OhzIG7hLM6fbcyu18bOuajlYWnSlj0IhDo2q7k0ebg=="
+		},
+		"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",
+			"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+			"requires": {
+				"wrappy": "1"
+			}
+		},
+		"optional-require": {
+			"version": "1.1.6",
+			"resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.1.6.tgz",
+			"integrity": "sha512-ZO2GGh1A84LV90OAIsMDmIJ5k/f7crSjP4aJSuLudp7C7wfVOAoyWWHV8Jf3ZMHyNHwpLD/DGhzaxbbN/duF+g==",
+			"requires": {
+				"require-at": "^1.0.6"
+			}
+		},
+		"p-limit": {
+			"version": "2.3.0",
+			"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+			"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+			"requires": {
+				"p-try": "^2.0.0"
+			}
+		},
+		"p-locate": {
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+			"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+			"requires": {
+				"p-limit": "^2.2.0"
+			}
+		},
+		"p-try": {
+			"version": "2.2.0",
+			"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+			"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
+		},
+		"parseurl": {
+			"version": "1.3.3",
+			"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+			"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
+		},
+		"path-exists": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+			"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
+		},
+		"path-is-absolute": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+			"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+		},
+		"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="
+		},
+		"pend": {
+			"version": "1.2.0",
+			"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+			"integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA="
+		},
+		"pkg-dir": {
+			"version": "4.2.0",
+			"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+			"integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+			"requires": {
+				"find-up": "^4.0.0"
+			}
+		},
+		"process-nextick-args": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+			"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+		},
+		"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"
+			}
+		},
+		"qs": {
+			"version": "6.7.0",
+			"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+			"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
+		},
+		"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"
+			}
+		},
+		"readable-stream": {
+			"version": "2.3.7",
+			"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+			"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+			"requires": {
+				"core-util-is": "~1.0.0",
+				"inherits": "~2.0.3",
+				"isarray": "~1.0.0",
+				"process-nextick-args": "~2.0.0",
+				"safe-buffer": "~5.1.1",
+				"string_decoder": "~1.1.1",
+				"util-deprecate": "~1.0.1"
+			}
+		},
+		"require-at": {
+			"version": "1.0.6",
+			"resolved": "https://registry.npmjs.org/require-at/-/require-at-1.0.6.tgz",
+			"integrity": "sha512-7i1auJbMUrXEAZCOQ0VNJgmcT2VOKPRl2YGJwgpHpC9CE91Mv4/4UYIUm4chGJaI381ZDq1JUicFii64Hapd8g=="
+		},
+		"rimraf": {
+			"version": "3.0.2",
+			"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+			"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+			"requires": {
+				"glob": "^7.1.3"
+			}
+		},
+		"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=="
+		},
+		"safer-buffer": {
+			"version": "2.1.2",
+			"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+			"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+		},
+		"saslprep": {
+			"version": "1.0.3",
+			"resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
+			"integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==",
+			"optional": true,
+			"requires": {
+				"sparse-bitfield": "^3.0.3"
+			}
+		},
+		"semver": {
+			"version": "7.3.5",
+			"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+			"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
+			"requires": {
+				"lru-cache": "^6.0.0"
+			}
+		},
+		"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"
+			}
+		},
+		"setprototypeof": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
+			"integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
+		},
+		"sparse-bitfield": {
+			"version": "3.0.3",
+			"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
+			"integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=",
+			"optional": true,
+			"requires": {
+				"memory-pager": "^1.0.2"
+			}
+		},
+		"statuses": {
+			"version": "1.5.0",
+			"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+			"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
+		},
+		"string_decoder": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+			"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+			"requires": {
+				"safe-buffer": "~5.1.0"
+			}
+		},
+		"tar-stream": {
+			"version": "2.2.0",
+			"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+			"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
+			"requires": {
+				"bl": "^4.0.3",
+				"end-of-stream": "^1.4.1",
+				"fs-constants": "^1.0.0",
+				"inherits": "^2.0.3",
+				"readable-stream": "^3.1.1"
+			},
+			"dependencies": {
+				"bl": {
+					"version": "4.1.0",
+					"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+					"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+					"requires": {
+						"buffer": "^5.5.0",
+						"inherits": "^2.0.4",
+						"readable-stream": "^3.4.0"
+					}
+				},
+				"inherits": {
+					"version": "2.0.4",
+					"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+					"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+				},
+				"readable-stream": {
+					"version": "3.6.0",
+					"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+					"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+					"requires": {
+						"inherits": "^2.0.3",
+						"string_decoder": "^1.1.1",
+						"util-deprecate": "^1.0.1"
+					}
+				}
+			}
+		},
+		"tmp": {
+			"version": "0.2.1",
+			"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
+			"integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
+			"requires": {
+				"rimraf": "^3.0.0"
+			}
+		},
+		"toidentifier": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
+			"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
+		},
+		"tslib": {
+			"version": "2.3.1",
+			"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
+			"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
+		},
+		"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"
+			}
+		},
+		"typescript": {
+			"version": "4.3.5",
+			"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
+			"integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==",
+			"dev": true
+		},
+		"unpipe": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+			"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+		},
+		"util-deprecate": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+			"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+		},
+		"utils-merge": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+			"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
+		},
+		"uuid": {
+			"version": "8.3.2",
+			"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+			"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
+		},
+		"vary": {
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+			"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
+		},
+		"wrappy": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+			"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+		},
+		"yallist": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+			"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+		},
+		"yauzl": {
+			"version": "2.10.0",
+			"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+			"integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
+			"requires": {
+				"buffer-crc32": "~0.2.3",
+				"fd-slicer": "~1.1.0"
+			}
+		}
+	}
+}
diff --git a/bundle/package.json b/bundle/package.json
new file mode 100644
index 00000000..f4188565
--- /dev/null
+++ b/bundle/package.json
@@ -0,0 +1,42 @@
+{
+	"name": "@fosscord/server",
+	"version": "1.0.0",
+	"description": "",
+	"main": "src/start.js",
+	"scripts": {
+		"linkInstall": "npm run --prefix ../util/ link && npm run --prefix ../api/ link && npm run --prefix ../cdn/ link && npm run --prefix ../gateway/ link",
+		"postinstall": "npm run linkInstall && npm link @fosscord/util && npm link @fosscord/api && npm link @fosscord/gateway && npm link @fosscord/cdn",
+		"build": "tsc -b .",
+		"start": "npm run build && node dist/start.js",
+		"test": "echo \"Error: no test specified\" && exit 1"
+	},
+	"repository": {
+		"type": "git",
+		"url": "git+https://github.com/fosscord/fosscord-api.git"
+	},
+	"keywords": [],
+	"author": "Fosscord",
+	"license": "AGPLV3",
+	"bugs": {
+		"url": "https://github.com/fosscord/fosscord-api/issues"
+	},
+	"homepage": "https://github.com/fosscord/fosscord-api#readme",
+	"devDependencies": {
+		"@types/async-exit-hook": "^2.0.0",
+		"@types/express": "^4.17.13",
+		"@types/node": "^16.6.1",
+		"@types/node-os-utils": "^1.2.0",
+		"typescript": "^4.3.5"
+	},
+	"dependencies": {
+		"@fosscord/api": "file:../api",
+		"@fosscord/cdn": "file:../cdn",
+		"@fosscord/gateway": "file:../gateway",
+		"@fosscord/util": "file:../util",
+		"async-exit-hook": "^2.0.1",
+		"express": "^4.17.1",
+		"link": "^0.1.5",
+		"mongodb-memory-server-global-4.4": "^7.3.6",
+		"node-os-utils": "^1.3.5"
+	}
+}
diff --git a/bundle/src/Server.ts b/bundle/src/Server.ts
new file mode 100644
index 00000000..14abc128
--- /dev/null
+++ b/bundle/src/Server.ts
@@ -0,0 +1,33 @@
+process.on("unhandledRejection", console.error);
+process.on("uncaughtException", console.error);
+
+import http from "http";
+import { FosscordServer as APIServer } from "@fosscord/api";
+import { Server as GatewayServer } from "@fosscord/gateway";
+import { CDNServer } from "@fosscord/cdn/";
+import express from "express";
+import { Config } from "../../util/dist";
+
+const app = express();
+const server = http.createServer();
+const port = Number(process.env.PORT) || 8080;
+const production = true;
+server.on("request", app);
+
+// @ts-ignore
+const api = new APIServer({ server, port, production, app });
+// @ts-ignore
+const cdn = new CDNServer({ server, port, production, app });
+// @ts-ignore
+const gateway = new GatewayServer({ server, port, production });
+
+async function main() {
+	await api.start();
+	await cdn.start();
+	await gateway.start();
+
+	if (!Config.get().gateway.endpoint) await Config.set({ gateway: { endpoint: `ws://localhost:${port}` } });
+	if (!Config.get().cdn.endpoint) await Config.set({ cdn: { endpoint: `http://localhost:${port}` } });
+}
+
+main().catch(console.error);
diff --git a/bundle/src/start.ts b/bundle/src/start.ts
new file mode 100644
index 00000000..2ae2ce87
--- /dev/null
+++ b/bundle/src/start.ts
@@ -0,0 +1,74 @@
+import fs from "fs";
+import { MongoMemoryServer } from "mongodb-memory-server-global-4.4";
+import path from "path";
+import cluster from "cluster";
+import os from "os";
+import osu from "node-os-utils";
+import exitHook from "async-exit-hook";
+
+const cores = Number(process.env.threads) || 1 || os.cpus().length;
+
+if (cluster.isMaster && !process.env.masterStarted) {
+	const dbPath = path.join(__dirname, "..", "..", "db");
+	const dbName = "fosscord";
+	const storageEngine = "wiredTiger";
+	const port = 27020;
+	const ip = "127.0.0.1";
+	var mongod: MongoMemoryServer;
+	fs.mkdirSync(dbPath, { recursive: true });
+
+	exitHook((callback: any) => {
+		(async () => {
+			console.log(`Stopping MongoDB ...`);
+			await mongod.stop();
+			console.log(`Stopped MongoDB`);
+			callback();
+		})();
+	});
+
+	process.env.masterStarted = "true";
+
+	setInterval(async () => {
+		const [cpuUsed, memory, network] = await Promise.all([osu.cpu.usage(), osu.mem.info(), osu.netstat.inOut()]);
+		if (typeof network === "object") {
+			console.log(`Network: in ${network.total.inputMb}mb | out ${network.total.outputMb}mb`);
+		}
+
+		console.log(
+			`[CPU] ${cpuUsed.toFixed(2)}% | [Memory] ${memory.usedMemMb.toFixed(0)}mb/${memory.totalMemMb.toFixed(0)}mb`
+		);
+	}, 1000 * 60);
+
+	(async () => {
+		console.log(`[Database] starting ...`);
+		mongod = new MongoMemoryServer({
+			instance: {
+				port,
+				ip,
+				dbName,
+				dbPath,
+				storageEngine,
+				auth: false, // by default `mongod` is started with '--noauth', start `mongod` with '--auth'
+			},
+		});
+		await mongod.start();
+		process.env.MONGO_URL = mongod.getUri(dbName);
+
+		console.log(`[CPU] ${osu.cpu.model()} Cores x${osu.cpu.count()}`);
+		console.log(`[System] ${await osu.os.oos()} ${os.arch()}`);
+		console.log(`[Database] started`);
+		console.log(`[Process] running with pid: ${process.pid}`);
+
+		// Fork workers.
+		for (let i = 0; i < cores; i++) {
+			cluster.fork();
+		}
+
+		cluster.on("exit", (worker: any, code: any, signal: any) => {
+			console.log(`[Worker] died with pid: ${worker.process.pid} , restarting ...`);
+			cluster.fork();
+		});
+	})();
+} else {
+	require("./Server.js");
+}
diff --git a/rtc/tsconfig.json b/bundle/tsconfig.json
index 520774d3..6bf2e6b7 100644
--- a/rtc/tsconfig.json
+++ b/bundle/tsconfig.json
@@ -5,7 +5,7 @@
 
 		/* Basic Options */
 		// "incremental": true,                   /* Enable incremental compilation */
-		"target": "ES2020" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
+		"target": "ESNext" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
 		"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
 		"lib": ["ES2020"] /* Specify library files to be included in the compilation. */,
 		"allowJs": true /* Allow javascript files to be compiled. */,
@@ -43,8 +43,6 @@
 
 		/* Module Resolution Options */
 		// "moduleResolution": "node",            /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
-		// "baseUrl": "./",                       /* Base directory to resolve non-absolute module names. */
-		// "paths": {},                           /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
 		// "rootDirs": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. */
 		// "typeRoots": [],                       /* List of folders to include type definitions from. */
 		"types": ["node"] /* Type declaration files to be included in compilation. */,
diff --git a/cdn/package.json b/cdn/package.json
index 47dc6afa..21976809 100644
--- a/cdn/package.json
+++ b/cdn/package.json
@@ -5,6 +5,8 @@
 	"main": "dist/index.js",
 	"types": "dist/index.d.ts",
 	"scripts": {
+		"link": "npm run build && npm link",
+		"postinstall": "npm run --prefix ../util/ link && npm link @fosscord/util && npm run link",
 		"test": "echo \"Error: no test specified\" && exit 1",
 		"build": "tsc -b .",
 		"start": "npm run build && node dist/start.js"
@@ -21,7 +23,7 @@
 	},
 	"homepage": "https://github.com/discord-open-source/discord-cdn#readme",
 	"dependencies": {
-		"@fosscord/server-util": "file:../util",
+		"@fosscord/util": "file:../util",
 		"body-parser": "^1.19.0",
 		"btoa": "^1.2.1",
 		"cheerio": "^1.0.0-rc.5",
diff --git a/cdn/src/Server.ts b/cdn/src/Server.ts
index 1b79b037..a73a948c 100644
--- a/cdn/src/Server.ts
+++ b/cdn/src/Server.ts
@@ -1,5 +1,5 @@
 import { Server, ServerOptions } from "lambert-server";
-import { Config, db } from "@fosscord/server-util";
+import { Config, db } from "@fosscord/util";
 import path from "path";
 import avatarsRoute from "./routes/avatars";
 
@@ -13,11 +13,9 @@ export class CDNServer extends Server {
 	}
 
 	async start() {
-		console.log("[Database] connecting ...");
 		// @ts-ignore
 		await (db as Promise<Connection>);
 		await Config.init();
-		console.log("[Database] connected");
 		this.app.use((req, res, next) => {
 			res.set("Access-Control-Allow-Origin", "*");
 			// TODO: use better CSP policy
@@ -33,31 +31,31 @@ export class CDNServer extends Server {
 		await this.registerRoutes(path.join(__dirname, "routes/"));
 
 		this.app.use("/icons/", avatarsRoute);
-		this.log("info", "[Server] Route /icons registered");
+		this.log("verbose", "[Server] Route /icons registered");
 
 		this.app.use("/emojis/", avatarsRoute);
-		this.log("info", "[Server] Route /emojis registered");
+		this.log("verbose", "[Server] Route /emojis registered");
 
 		this.app.use("/stickers/", avatarsRoute);
-		this.log("info", "[Server] Route /stickers registered");
+		this.log("verbose", "[Server] Route /stickers registered");
 
 		this.app.use("/banners/", avatarsRoute);
-		this.log("info", "[Server] Route /banners registered");
-		
+		this.log("verbose", "[Server] Route /banners registered");
+
 		this.app.use("/splashes/", avatarsRoute);
-		this.log("info", "[Server] Route /splashes registered");
+		this.log("verbose", "[Server] Route /splashes registered");
 
 		this.app.use("/app-icons/", avatarsRoute);
-		this.log("info", "[Server] Route /app-icons registered");
+		this.log("verbose", "[Server] Route /app-icons registered");
 
 		this.app.use("/app-assets/", avatarsRoute);
-		this.log("info", "[Server] Route /app-assets registered");
+		this.log("verbose", "[Server] Route /app-assets registered");
 
 		this.app.use("/discover-splashes/", avatarsRoute);
-		this.log("info", "[Server] Route /discover-splashes registered");
+		this.log("verbose", "[Server] Route /discover-splashes registered");
 
 		this.app.use("/team-icons/", avatarsRoute);
-		this.log("info", "[Server] Route /team-icons registered");
+		this.log("verbose", "[Server] Route /team-icons registered");
 
 		return super.start();
 	}
diff --git a/cdn/src/routes/attachments.ts b/cdn/src/routes/attachments.ts
index c387aa37..6ce64ed4 100644
--- a/cdn/src/routes/attachments.ts
+++ b/cdn/src/routes/attachments.ts
@@ -1,5 +1,5 @@
 import { Router, Response, Request } from "express";
-import { Config, Snowflake } from "@fosscord/server-util";
+import { Config, Snowflake } from "@fosscord/util";
 import { storage } from "../util/Storage";
 import FileType from "file-type";
 import { HTTPError } from "lambert-server";
diff --git a/cdn/src/routes/avatars.ts b/cdn/src/routes/avatars.ts
index 60befe2c..03388afc 100644
--- a/cdn/src/routes/avatars.ts
+++ b/cdn/src/routes/avatars.ts
@@ -1,5 +1,5 @@
 import { Router, Response, Request } from "express";
-import { Config, Snowflake } from "@fosscord/server-util";
+import { Config, Snowflake } from "@fosscord/util";
 import { storage } from "../util/Storage";
 import FileType from "file-type";
 import { HTTPError } from "lambert-server";
diff --git a/cdn/src/routes/external.ts b/cdn/src/routes/external.ts
index 3abe9c22..625b6bbd 100644
--- a/cdn/src/routes/external.ts
+++ b/cdn/src/routes/external.ts
@@ -4,7 +4,7 @@ import { Router, Response, Request } from "express";
 import fetch from "node-fetch";
 import crypto from "crypto";
 import { HTTPError } from "lambert-server";
-import { Snowflake } from "@fosscord/server-util";
+import { Snowflake } from "@fosscord/util";
 import { storage } from "../util/Storage";
 
 const router = Router();
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 00000000..5861e12f
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,24 @@
+version: "3"
+services:
+    db:
+        hostname: fosscord_db
+        image: mongo:latest
+        volumes:
+            - ./db:/data/db
+        restart: unless-stopped
+    api:
+        hostname: fosscord_api
+        image: fosscord/api
+        depends_on:
+            - db
+        ports:
+            - 3001:3001
+        env_file: ./.docker/env
+    gateway:
+        hostname: fosscord_gateway
+        image: fosscord/gateway
+        depends_on:
+            - db
+        ports:
+            - 3002:3002
+        env_file: ./.docker/env
\ No newline at end of file
diff --git a/gateway/.github/workflows/docker-publish.yml b/gateway/.github/workflows/docker-publish.yml
deleted file mode 100644
index 46d9d04d..00000000
--- a/gateway/.github/workflows/docker-publish.yml
+++ /dev/null
@@ -1,47 +0,0 @@
-name: docker-publish
-
-on:
-  push:
-    branches:
-      - 'master'
-
-jobs:
-  docker:
-    runs-on: ubuntu-latest
-    steps:
-      -
-        name: Checkout
-        uses: actions/checkout@v2
-      -
-        name: Set up Docker Buildx
-        uses: docker/setup-buildx-action@v1
-      -
-        name: Cache Docker layers
-        uses: actions/cache@v2
-        with:
-          path: /tmp/.buildx-cache
-          key: ${{ runner.os }}-buildx-${{ github.sha }}
-          restore-keys: |
-            ${{ runner.os }}-buildx-
-      -
-        name: Login to DockerHub
-        uses: docker/login-action@v1
-        with:
-          username: ${{ secrets.DOCKERHUB_USERNAME }}
-          password: ${{ secrets.DOCKERHUB_TOKEN }}
-      -
-        name: Build and push
-        uses: docker/build-push-action@v2
-        with:
-          context: .
-          push: true
-          tags: ${{ secrets.DOCKERHUB_TAGS }}
-          cache-from: type=local,src=/tmp/.buildx-cache
-          cache-to: type=local,dest=/tmp/.buildx-cache-new
-      -
-        # Hackfix to cleanup cache; replace after buildx 0.6 and BuildKit 0.9 are released
-        # https://github.com/docker/build-push-action/pull/406#issuecomment-879184394
-        name: Move cache fix
-        run: |
-          rm -rf /tmp/.buildx-cache
-          mv /tmp/.buildx-cache-new /tmp/.buildx-cache
diff --git a/gateway/package.json b/gateway/package.json
index 8f0bb62b..e6c45427 100644
--- a/gateway/package.json
+++ b/gateway/package.json
@@ -4,16 +4,18 @@
 	"description": "",
 	"main": "dist/index.js",
 	"scripts": {
+		"link": "npm run build && npm link",
+		"postinstall": "npm run --prefix ../util/ link && npm link @fosscord/util && npm run link",
 		"test": "echo \"Error: no test specified\" && exit 1",
 		"start": "npm run build && node dist/start.js",
-		"build": "npx tsc -b .",
+		"build": "tsc -b .",
 		"dev": "tsnd --respawn src/start.ts"
 	},
 	"keywords": [],
 	"author": "Fosscord",
 	"license": "ISC",
 	"dependencies": {
-		"@fosscord/server-util": "file:../util",
+		"@fosscord/util": "file:../util",
 		"ajv": "^8.5.0",
 		"amqplib": "^0.8.0",
 		"dotenv": "^8.2.0",
diff --git a/gateway/src/Server.ts b/gateway/src/Server.ts
index d4b3271c..482545f1 100644
--- a/gateway/src/Server.ts
+++ b/gateway/src/Server.ts
@@ -1,7 +1,7 @@
 import "missing-native-js-functions";
 import dotenv from "dotenv";
 dotenv.config();
-import { Config, db, RabbitMQ } from "@fosscord/server-util";
+import { Config, db, initEvent, RabbitMQ } from "@fosscord/util";
 import { Server as WebSocketServer } from "ws";
 import { Connection } from "./events/Connection";
 import http from "http";
@@ -40,8 +40,7 @@ export class Server {
 		await (db as Promise<Connection>);
 		await this.setupSchema();
 		await Config.init();
-		await RabbitMQ.init();
-		console.log("[Database] connected");
+		await initEvent();
 		if (!this.server.listening) {
 			this.server.listen(this.port);
 			console.log(`[Gateway] online on 0.0.0.0:${this.port}`);
diff --git a/gateway/src/events/Connection.ts b/gateway/src/events/Connection.ts
index 1ef9fb48..5fbcbff5 100644
--- a/gateway/src/events/Connection.ts
+++ b/gateway/src/events/Connection.ts
@@ -40,6 +40,7 @@ export async function Connection(this: Server, socket: WebSocket, request: Incom
 			socket.deflate.on("data", (chunk) => socket.send(chunk));
 		}
 
+		socket.events = {};
 		socket.permissions = {};
 		socket.sequence = 0;
 
diff --git a/gateway/src/listener/listener.ts b/gateway/src/listener/listener.ts
index 6a6967d6..708bfe5c 100644
--- a/gateway/src/listener/listener.ts
+++ b/gateway/src/listener/listener.ts
@@ -1,63 +1,31 @@
 import {
 	db,
 	Event,
-	MongooseCache,
 	UserModel,
 	getPermission,
 	Permissions,
 	ChannelModel,
 	RabbitMQ,
 	EVENT,
-} from "@fosscord/server-util";
+	listenEvent,
+	EventOpts,
+	ListenEventOpts,
+} from "@fosscord/util";
 import { OPCODES } from "../util/Constants";
 import { Send } from "../util/Send";
 import WebSocket from "../util/WebSocket";
 import "missing-native-js-functions";
 import { ConsumeMessage } from "amqplib";
+import { Channel } from "amqplib";
 
 // TODO: close connection on Invalidated Token
 // TODO: check intent
 // TODO: Guild Member Update is sent for current-user updates regardless of whether the GUILD_MEMBERS intent is set.
-// ? How to resubscribe MongooseCache for new dm channel events? Maybe directly send them to the user_id regardless of the channel_id? -> max overhead of creating 10 events in database for dm user group. Or a new field in event -> recipient_ids?
 
 // Sharding: calculate if the current shard id matches the formula: shard_id = (guild_id >> 22) % num_shards
 // https://discord.com/developers/docs/topics/gateway#sharding
 
-export interface DispatchOpts {
-	eventStream: MongooseCache;
-	guilds: Array<string>;
-}
-
-function getPipeline(this: WebSocket, guilds: string[], channels: string[] = []) {
-	if (this.shard_count) {
-		guilds = guilds.filter((x) => (BigInt(x) >> 22n) % this.shard_count! === this.shard_id);
-	}
-
-	return [
-		{
-			$match: {
-				$or: [
-					{ "fullDocument.guild_id": { $in: guilds } },
-					{ "fullDocument.user_id": this.user_id },
-					{ "fullDocument.channel_id": { $in: channels } },
-				],
-			},
-		},
-	];
-}
-
-async function rabbitListen(this: WebSocket, id: string) {
-	await this.rabbitCh!.assertExchange(id, "fanout", { durable: false });
-	const q = await this.rabbitCh!.assertQueue("", { exclusive: true, autoDelete: true });
-
-	this.rabbitCh!.bindQueue(q.queue, id, "");
-	this.rabbitCh!.consume(q.queue, consume.bind(this), {
-		noAck: false,
-	});
-	this.rabbitCh!.queues[id] = q.queue;
-}
-
-// TODO: use already required guilds/channels of Identify and don't fetch them again
+// TODO: use already queried guilds/channels of Identify and don't fetch them again
 export async function setupListener(this: WebSocket) {
 	const user = await UserModel.findOne({ id: this.user_id }, { guilds: true }).exec();
 	const channels = await ChannelModel.find(
@@ -67,90 +35,77 @@ export async function setupListener(this: WebSocket) {
 	const dm_channels = channels.filter((x) => !x.guild_id);
 	const guild_channels = channels.filter((x) => x.guild_id);
 
+	const opts: { acknowledge: boolean; channel?: Channel } = { acknowledge: true };
+	const consumer = consume.bind(this);
+
 	if (RabbitMQ.connection) {
+		opts.channel = await RabbitMQ.connection.createChannel();
 		// @ts-ignore
-		this.rabbitCh = await RabbitMQ.connection.createChannel();
-		this.rabbitCh!.queues = {};
+		opts.channel.queues = {};
+	}
 
-		rabbitListen.call(this, this.user_id);
+	this.events[this.user_id] = await listenEvent(this.user_id, consumer, opts);
 
-		for (const channel of dm_channels) {
-			rabbitListen.call(this, channel.id);
-		}
-		for (const guild of user.guilds) {
-			// contains guild and dm channels
+	for (const channel of dm_channels) {
+		this.events[channel.id] = await listenEvent(channel.id, consumer, opts);
+	}
 
-			getPermission(this.user_id, guild)
-				.then((x) => {
-					this.permissions[guild] = x;
-					rabbitListen.call(this, guild);
-					for (const channel of guild_channels) {
-						if (x.overwriteChannel(channel.permission_overwrites).has("VIEW_CHANNEL")) {
-							rabbitListen.call(this, channel.id);
-						}
+	for (const guild of user.guilds) {
+		// contains guild and dm channels
+
+		getPermission(this.user_id, guild)
+			.then(async (x) => {
+				this.permissions[guild] = x;
+				this.listeners;
+				this.events[guild] = await listenEvent(guild, consumer, opts);
+				for (const channel of guild_channels) {
+					if (x.overwriteChannel(channel.permission_overwrites).has("VIEW_CHANNEL")) {
+						this.events[channel.id] = await listenEvent(channel.id, consumer, opts);
 					}
-				})
-				.catch((e) => {});
-		}
-
-		this.once("close", () => {
-			this.rabbitCh!.close();
-		});
-	} else {
-		const eventStream = new MongooseCache(
-			db.collection("events"),
-			getPipeline.call(
-				this,
-				user.guilds,
-				channels.map((x) => x.id)
-			),
-			{
-				onlyEvents: true,
-			}
-		);
-
-		await eventStream.init();
-		eventStream.on("insert", (document: Event) =>
-			dispatch.call(this, document, { eventStream, guilds: user.guilds })
-		);
-
-		this.once("close", () => eventStream.destroy());
+				}
+			})
+			.catch((e) => {});
 	}
+
+	this.once("close", () => {
+		if (opts.channel) opts.channel.close();
+		else Object.values(this.events).forEach((x) => x());
+	});
 }
 
-// TODO: use rabbitmq to only receive events that are included in intents
-function consume(this: WebSocket, opts: ConsumeMessage | null) {
-	if (!opts) return;
-	if (!this.rabbitCh) return;
-	const data = JSON.parse(opts.content.toString());
+// TODO: only subscribe for events that are in the connection intents
+function consume(this: WebSocket, opts: EventOpts) {
+	const { data, event } = opts;
 	const id = data.id as string;
-	const event = opts.properties.type as EVENT;
 	const permission = this.permissions[id] || new Permissions("ADMINISTRATOR"); // default permission for dm
 
-	console.log("rabbitmq event", event);
+	const consumer = consume.bind(this);
+	const listenOpts = opts as ListenEventOpts;
+	console.log("event", event);
 
 	// subscription managment
 	switch (event) {
 		case "CHANNEL_DELETE":
 		case "GUILD_DELETE":
-			this.rabbitCh.cancel(id);
+			delete this.events[id];
+			opts.cancel();
 			break;
 		case "CHANNEL_CREATE":
+			if (!permission.overwriteChannel(data.permission_overwrites).has("VIEW_CHANNEL")) return;
 		// TODO: check if user has permission to channel
 		case "GUILD_CREATE":
-			rabbitListen.call(this, id);
+			listenEvent(id, consumer, listenOpts);
 			break;
 		case "CHANNEL_UPDATE":
-			const queue_id = this.rabbitCh.queues[id];
+			const exists = this.events[id];
 			// @ts-ignore
-			const exists = this.rabbitCh.consumers[id];
 			if (permission.overwriteChannel(data.permission_overwrites).has("VIEW_CHANNEL")) {
 				if (exists) break;
-				rabbitListen.call(this, id);
+				listenEvent(id, consumer, listenOpts);
 			} else {
-				if (!exists) break;
-				this.rabbitCh.cancel(queue_id);
-				this.rabbitCh.unbindQueue(queue_id, id, "");
+				if (!exists) return; // return -> do not send channel update events for hidden channels
+				opts.cancel(id);
+				delete this.events[id];
 			}
 			break;
 	}
@@ -216,167 +171,5 @@ function consume(this: WebSocket, opts: ConsumeMessage | null) {
 		d: data,
 		s: this.sequence++,
 	});
-	this.rabbitCh.ack(opts);
-}
-
-// TODO: cache permission
-// we shouldn't fetch the permission for every event, as a message send event with many channel members would result in many thousand db queries.
-// instead we should calculate all (guild, channel) permissions once and dynamically update if it changes.
-// TODO: only subscribe for events that are in the connection intents
-// TODO: only subscribe for channel/guilds that the user has access to (and re-subscribe if it changes)
-
-export async function dispatch(this: WebSocket, document: Event, { eventStream, guilds }: DispatchOpts) {
-	var permission = new Permissions("ADMINISTRATOR"); // default permission for dms
-	console.log("event", document);
-	var channel_id = document.channel_id || document.data?.channel_id;
-	// TODO: clean up
-	if (document.event === "GUILD_CREATE") {
-		guilds.push(document.data.id);
-		eventStream.changeStream(getPipeline.call(this, guilds));
-	} else if (document.event === "GUILD_DELETE") {
-		guilds.remove(document.guild_id!);
-		eventStream.changeStream(getPipeline.call(this, guilds));
-	} else if (document.event === "CHANNEL_DELETE") channel_id = null;
-	if (document.guild_id && !this.intents.has("GUILDS")) return;
-
-	try {
-		permission = await getPermission(this.user_id, document.guild_id, channel_id);
-	} catch (e) {
-		permission = new Permissions();
-	}
-
-	// check intents: https://discord.com/developers/docs/topics/gateway#gateway-intents
-	switch (document.event) {
-		case "GUILD_DELETE":
-		case "GUILD_CREATE":
-		case "GUILD_UPDATE":
-		case "GUILD_ROLE_CREATE":
-		case "GUILD_ROLE_UPDATE":
-		case "GUILD_ROLE_DELETE":
-		case "CHANNEL_CREATE":
-		case "CHANNEL_DELETE":
-		case "CHANNEL_UPDATE":
-			// gets sent if GUILDS intent is set (already checked in if document.guild_id)
-			break;
-		case "GUILD_INTEGRATIONS_UPDATE":
-			if (!this.intents.has("GUILD_INTEGRATIONS")) return;
-			break;
-		case "WEBHOOKS_UPDATE":
-			if (!this.intents.has("GUILD_WEBHOOKS")) return;
-			break;
-		case "GUILD_EMOJI_UPDATE":
-			if (!this.intents.has("GUILD_EMOJIS")) return;
-			break;
-		// only send them, if the user subscribed for this part of the member list, or is a bot
-		case "GUILD_MEMBER_ADD":
-		case "GUILD_MEMBER_REMOVE":
-		case "GUILD_MEMBER_UPDATE":
-			if (!this.intents.has("GUILD_MEMBERS")) return;
-			break;
-		case "VOICE_STATE_UPDATE":
-			if (!this.intents.has("GUILD_VOICE_STATES")) return;
-			break;
-		case "GUILD_BAN_ADD":
-		case "GUILD_BAN_REMOVE":
-			if (!this.intents.has("GUILD_BANS")) return;
-			break;
-		case "INVITE_CREATE":
-		case "INVITE_DELETE":
-			if (!this.intents.has("GUILD_INVITES")) return;
-		case "PRESENCE_UPDATE":
-			if (!this.intents.has("GUILD_PRESENCES")) return;
-			break;
-		case "MESSAGE_CREATE":
-		case "MESSAGE_DELETE":
-		case "MESSAGE_DELETE_BULK":
-		case "MESSAGE_UPDATE":
-		case "CHANNEL_PINS_UPDATE":
-			if (!this.intents.has("GUILD_MESSAGES") && document.guild_id) return;
-			if (!this.intents.has("DIRECT_MESSAGES") && !document.guild_id) return;
-			break;
-		case "MESSAGE_REACTION_ADD":
-		case "MESSAGE_REACTION_REMOVE":
-		case "MESSAGE_REACTION_REMOVE_ALL":
-		case "MESSAGE_REACTION_REMOVE_EMOJI":
-			if (!this.intents.has("GUILD_MESSAGE_REACTIONS") && document.guild_id) return;
-			if (!this.intents.has("DIRECT_MESSAGE_REACTIONS") && !document.guild_id) return;
-			break;
-
-		case "TYPING_START":
-			if (!this.intents.has("GUILD_MESSAGE_TYPING") && document.guild_id) return;
-			if (!this.intents.has("DIRECT_MESSAGE_TYPING") && !document.guild_id) return;
-			break;
-		case "READY": // will be sent by the gateway
-		case "USER_UPDATE":
-		case "APPLICATION_COMMAND_CREATE":
-		case "APPLICATION_COMMAND_DELETE":
-		case "APPLICATION_COMMAND_UPDATE":
-		default:
-			// Any events not defined in an intent are considered "passthrough" and will always be sent to you.
-			break;
-	}
-
-	// check permissions
-	switch (document.event) {
-		case "GUILD_INTEGRATIONS_UPDATE":
-			if (!permission.has("MANAGE_GUILD")) return;
-			break;
-		case "WEBHOOKS_UPDATE":
-			if (!permission.has("MANAGE_WEBHOOKS")) return;
-			break;
-		case "GUILD_MEMBER_ADD":
-		case "GUILD_MEMBER_REMOVE":
-		case "GUILD_MEMBER_UPDATE":
-			// only send them, if the user subscribed for this part of the member list, or is a bot
-			break;
-		case "GUILD_BAN_ADD":
-		case "GUILD_BAN_REMOVE":
-			if (!permission.has("BAN_MEMBERS")) break;
-			break;
-		case "INVITE_CREATE":
-		case "INVITE_DELETE":
-			if (!permission.has("MANAGE_GUILD")) break;
-		case "PRESENCE_UPDATE":
-			break;
-		case "VOICE_STATE_UPDATE":
-		case "MESSAGE_CREATE":
-		case "MESSAGE_DELETE":
-		case "MESSAGE_DELETE_BULK":
-		case "MESSAGE_UPDATE":
-		case "CHANNEL_PINS_UPDATE":
-		case "MESSAGE_REACTION_ADD":
-		case "MESSAGE_REACTION_REMOVE":
-		case "MESSAGE_REACTION_REMOVE_ALL":
-		case "MESSAGE_REACTION_REMOVE_EMOJI":
-		case "TYPING_START":
-			// only gets send if the user is alowed to view the current channel
-			if (!permission.has("VIEW_CHANNEL")) return;
-			break;
-		case "GUILD_CREATE":
-		case "GUILD_DELETE":
-		case "GUILD_UPDATE":
-		case "GUILD_ROLE_CREATE":
-		case "GUILD_ROLE_UPDATE":
-		case "GUILD_ROLE_DELETE":
-		case "CHANNEL_CREATE":
-		case "CHANNEL_DELETE":
-		case "CHANNEL_UPDATE":
-		case "GUILD_EMOJI_UPDATE":
-		case "READY": // will be sent by the gateway
-		case "USER_UPDATE":
-		case "APPLICATION_COMMAND_CREATE":
-		case "APPLICATION_COMMAND_DELETE":
-		case "APPLICATION_COMMAND_UPDATE":
-		default:
-			// always gets sent
-			// Any events not defined in an intent are considered "passthrough" and will always be sent
-			break;
-	}
-
-	return Send(this, {
-		op: OPCODES.Dispatch,
-		t: document.event,
-		d: document.data,
-		s: this.sequence++,
-	});
+	opts.acknowledge?.();
 }
diff --git a/gateway/src/opcodes/Identify.ts b/gateway/src/opcodes/Identify.ts
index 43368367..91f7f675 100644
--- a/gateway/src/opcodes/Identify.ts
+++ b/gateway/src/opcodes/Identify.ts
@@ -12,7 +12,7 @@ import {
 	toObject,
 	EVENTEnum,
 	Config,
-} from "@fosscord/server-util";
+} from "@fosscord/util";
 import { setupListener } from "../listener/listener";
 import { IdentifySchema } from "../schema/Identify";
 import { Send } from "../util/Send";
diff --git a/gateway/src/opcodes/LazyRequest.ts b/gateway/src/opcodes/LazyRequest.ts
index b1d553b9..63075e5a 100644
--- a/gateway/src/opcodes/LazyRequest.ts
+++ b/gateway/src/opcodes/LazyRequest.ts
@@ -1,13 +1,5 @@
 // @ts-nocheck WIP
-import {
-	db,
-	getPermission,
-	MemberModel,
-	MongooseCache,
-	PublicUserProjection,
-	RoleModel,
-	toObject,
-} from "@fosscord/server-util";
+import { db, getPermission, PublicUserProjection, toObject } from "@fosscord/util";
 import { LazyRequest } from "../schema/LazyRequest";
 import { OPCODES, Payload } from "../util/Constants";
 import { Send } from "../util/Send";
diff --git a/gateway/src/schema/Activity.ts b/gateway/src/schema/Activity.ts
index 62cf7ad6..d7e0a30b 100644
--- a/gateway/src/schema/Activity.ts
+++ b/gateway/src/schema/Activity.ts
@@ -1,4 +1,4 @@
-import { ActivityBodySchema } from "@fosscord/server-util";
+import { ActivityBodySchema } from "@fosscord/util";
 import { EmojiSchema } from "./Emoji";
 
 export const ActivitySchema = {
diff --git a/gateway/src/util/Config.ts b/gateway/src/util/Config.ts
index 9ceb8cd5..e99c89f7 100644
--- a/gateway/src/util/Config.ts
+++ b/gateway/src/util/Config.ts
@@ -1,6 +1,6 @@
 // @ts-nocheck
-import { Config } from "@fosscord/server-util";
-import { getConfigPathForFile } from "@fosscord/server-util/dist/util/Config";
+import { Config } from "@fosscord/util";
+import { getConfigPathForFile } from "@fosscord/util/dist/util/Config";
 import Ajv, { JSONSchemaType } from "ajv";
 
 export interface DefaultOptions {
diff --git a/gateway/src/util/WebSocket.ts b/gateway/src/util/WebSocket.ts
index 1bd0ff2f..d1e13555 100644
--- a/gateway/src/util/WebSocket.ts
+++ b/gateway/src/util/WebSocket.ts
@@ -1,4 +1,4 @@
-import { Intents, Permissions } from "@fosscord/server-util";
+import { Intents, Permissions } from "@fosscord/util";
 import WS, { Server, Data } from "ws";
 import { Deflate } from "zlib";
 import { Channel } from "amqplib";
@@ -15,8 +15,8 @@ interface WebSocket extends WS {
 	readyTimeout: NodeJS.Timeout;
 	intents: Intents;
 	sequence: number;
-	rabbitCh?: Channel & { queues: Record<string, string> };
 	permissions: Record<string, Permissions>;
+	events: Record<string, Function>;
 }
 
 export default WebSocket;
diff --git a/rtc/package-lock.json b/rtc/package-lock.json
deleted file mode 100644
index 4977468d..00000000
--- a/rtc/package-lock.json
+++ /dev/null
@@ -1,1268 +0,0 @@
-{
-	"name": "@fosscord/server-util",
-	"version": "1.3.52",
-	"lockfileVersion": 2,
-	"requires": true,
-	"packages": {
-		"": {
-			"name": "@fosscord/server-util",
-			"version": "1.3.52",
-			"license": "GPLV3",
-			"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",
-				"amqplib": "^0.8.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.9",
-				"mongoose": "^5.12.3",
-				"mongoose-autopopulate": "^0.12.3",
-				"typescript": "^4.1.3"
-			},
-			"devDependencies": {
-				"@types/amqplib": "^0.8.1"
-			}
-		},
-		"node_modules/@types/amqplib": {
-			"version": "0.8.1",
-			"resolved": "https://registry.npmjs.org/@types/amqplib/-/amqplib-0.8.1.tgz",
-			"integrity": "sha512-8dCjF+dHZ8Y6JOoHD1BMnxP0quAncvZq4wA/lS072NjX9vIzVRSMcmfKy2Os8ZQ8VWWp74MD09GMbVbKS6/Fxw==",
-			"dev": true,
-			"dependencies": {
-				"@types/bluebird": "*",
-				"@types/node": "*"
-			}
-		},
-		"node_modules/@types/bluebird": {
-			"version": "3.5.36",
-			"resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.36.tgz",
-			"integrity": "sha512-HBNx4lhkxN7bx6P0++W8E289foSu8kO8GCk2unhuVggO+cE7rh9DhZUyPhUxNRG9m+5B5BTKxZQ5ZP92x/mx9Q==",
-			"dev": true
-		},
-		"node_modules/@types/bson": {
-			"version": "4.0.3",
-			"resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.3.tgz",
-			"integrity": "sha512-mVRvYnTOZJz3ccpxhr3wgxVmSeiYinW+zlzQz3SXWaJmD1DuL05Jeq7nKw3SnbKmbleW5qrLG5vdyWe/A9sXhw==",
-			"dependencies": {
-				"@types/node": "*"
-			}
-		},
-		"node_modules/@types/jsonwebtoken": {
-			"version": "8.5.0",
-			"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.0.tgz",
-			"integrity": "sha512-9bVao7LvyorRGZCw0VmH/dr7Og+NdjYSsKAxB43OQoComFbBgsEpoR9JW6+qSq/ogwVBg8GI2MfAlk4SYI4OLg==",
-			"dependencies": {
-				"@types/node": "*"
-			}
-		},
-		"node_modules/@types/mongodb": {
-			"version": "3.6.6",
-			"resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.6.tgz",
-			"integrity": "sha512-ghYevKiSh/TGk2MAwSRZP7T1ilR9Pw8Fa7pT9GGVGZPUsWKdZjZ4G6LG3MqK2iXKdNba994F8W9ikA+qx2Eo3A==",
-			"dependencies": {
-				"@types/bson": "*",
-				"@types/node": "*"
-			}
-		},
-		"node_modules/@types/mongoose": {
-			"version": "5.10.4",
-			"resolved": "https://registry.npmjs.org/@types/mongoose/-/mongoose-5.10.4.tgz",
-			"integrity": "sha512-U7fNDcTcdaSGzQ3+mlSBeebiYr6eaacJi330LTLOEh8Sm6mXfuec70ag/UXkL+alFm7pfAjFqfc7jEaJEJvAHQ==",
-			"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/node": {
-			"version": "14.14.25",
-			"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.25.tgz",
-			"integrity": "sha512-EPpXLOVqDvisVxtlbvzfyqSsFeQxltFbluZNRndIb8tr9KiBnYNLzrc1N3pyKUCww2RNrfHDViqDWWE1LCJQtQ=="
-		},
-		"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/amqplib": {
-			"version": "0.8.0",
-			"resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.8.0.tgz",
-			"integrity": "sha512-icU+a4kkq4Y1PS4NNi+YPDMwdlbFcZ1EZTQT2nigW3fvOb6AOgUQ9+Mk4ue0Zu5cBg/XpDzB40oH10ysrk2dmA==",
-			"dependencies": {
-				"bitsyntax": "~0.1.0",
-				"bluebird": "^3.7.2",
-				"buffer-more-ints": "~1.0.0",
-				"readable-stream": "1.x >=1.1.9",
-				"safe-buffer": "~5.2.1",
-				"url-parse": "~1.5.1"
-			},
-			"engines": {
-				"node": ">=10"
-			}
-		},
-		"node_modules/amqplib/node_modules/bluebird": {
-			"version": "3.7.2",
-			"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
-			"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
-		},
-		"node_modules/amqplib/node_modules/isarray": {
-			"version": "0.0.1",
-			"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
-			"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
-		},
-		"node_modules/amqplib/node_modules/readable-stream": {
-			"version": "1.1.14",
-			"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
-			"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
-			"dependencies": {
-				"core-util-is": "~1.0.0",
-				"inherits": "~2.0.1",
-				"isarray": "0.0.1",
-				"string_decoder": "~0.10.x"
-			}
-		},
-		"node_modules/amqplib/node_modules/string_decoder": {
-			"version": "0.10.31",
-			"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
-			"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
-		},
-		"node_modules/bitsyntax": {
-			"version": "0.1.0",
-			"resolved": "https://registry.npmjs.org/bitsyntax/-/bitsyntax-0.1.0.tgz",
-			"integrity": "sha512-ikAdCnrloKmFOugAfxWws89/fPc+nw0OOG1IzIE72uSOg/A3cYptKCjSUhDTuj7fhsJtzkzlv7l3b8PzRHLN0Q==",
-			"dependencies": {
-				"buffer-more-ints": "~1.0.0",
-				"debug": "~2.6.9",
-				"safe-buffer": "~5.1.2"
-			},
-			"engines": {
-				"node": ">=0.8"
-			}
-		},
-		"node_modules/bitsyntax/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/bl": {
-			"version": "2.2.1",
-			"resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz",
-			"integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==",
-			"dependencies": {
-				"readable-stream": "^2.3.5",
-				"safe-buffer": "^5.1.1"
-			}
-		},
-		"node_modules/bluebird": {
-			"version": "3.5.1",
-			"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
-			"integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
-		},
-		"node_modules/bson": {
-			"version": "1.1.5",
-			"resolved": "https://registry.npmjs.org/bson/-/bson-1.1.5.tgz",
-			"integrity": "sha512-kDuEzldR21lHciPQAIulLs1LZlCXdLziXI6Mb/TDkwXhb//UORJNPXgcRs2CuO4H0DcMkpfT3/ySsP3unoZjBg==",
-			"engines": {
-				"node": ">=0.6.19"
-			}
-		},
-		"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-more-ints": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz",
-			"integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg=="
-		},
-		"node_modules/core-util-is": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
-			"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
-		},
-		"node_modules/debug": {
-			"version": "2.6.9",
-			"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-			"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-			"dependencies": {
-				"ms": "2.0.0"
-			}
-		},
-		"node_modules/debug/node_modules/ms": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-			"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
-		},
-		"node_modules/denque": {
-			"version": "1.5.0",
-			"resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz",
-			"integrity": "sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ==",
-			"engines": {
-				"node": ">=0.10"
-			}
-		},
-		"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/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/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/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/inherits": {
-			"version": "2.0.4",
-			"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-			"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
-		},
-		"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/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",
-			"integrity": "sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ=="
-		},
-		"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/memory-pager": {
-			"version": "1.5.0",
-			"resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
-			"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
-			"optional": true
-		},
-		"node_modules/missing-native-js-functions": {
-			"version": "1.2.2",
-			"resolved": "https://registry.npmjs.org/missing-native-js-functions/-/missing-native-js-functions-1.2.2.tgz",
-			"integrity": "sha512-kNdwKWXh1hM8RdNqW2BIHsqD6fYN9RV27M+0uQF1pGF1yLKVc+xIv1VB8WEN1HxQ22N8Rj9sdEezOX2yBpsMZA=="
-		},
-		"node_modules/mongodb": {
-			"version": "3.6.9",
-			"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.9.tgz",
-			"integrity": "sha512-1nSCKgSunzn/CXwgOWgbPHUWOO5OfERcuOWISmqd610jn0s8BU9K4879iJVabqgpPPbA6hO7rG48eq+fGED3Mg==",
-			"dependencies": {
-				"bl": "^2.2.1",
-				"bson": "^1.1.4",
-				"denque": "^1.4.1",
-				"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.12.3",
-			"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.12.3.tgz",
-			"integrity": "sha512-frsSR9yeldaRpSUeTegXCSB0Tu5UGq8sHuHBuEV31Jk3COyxlKFQPL7UsdMhxPUCmk74FpOYSmNwxhWBEqgzQg==",
-			"dependencies": {
-				"@types/mongodb": "^3.5.27",
-				"bson": "^1.1.4",
-				"kareem": "2.3.2",
-				"mongodb": "3.6.5",
-				"mongoose-legacy-pluralize": "1.0.2",
-				"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",
-				"sliced": "1.0.1"
-			},
-			"engines": {
-				"node": ">=4.0.0"
-			}
-		},
-		"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=="
-		},
-		"node_modules/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=="
-		},
-		"node_modules/mongoose/node_modules/mongodb": {
-			"version": "3.6.5",
-			"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.5.tgz",
-			"integrity": "sha512-mQlYKw1iGbvJJejcPuyTaytq0xxlYbIoVDm2FODR+OHxyEiMR021vc32bTvamgBjCswsD54XIRwhg3yBaWqJjg==",
-			"dependencies": {
-				"bl": "^2.2.1",
-				"bson": "^1.1.4",
-				"denque": "^1.4.1",
-				"require_optional": "^1.0.1",
-				"safe-buffer": "^5.1.2"
-			},
-			"engines": {
-				"node": ">=4"
-			},
-			"optionalDependencies": {
-				"saslprep": "^1.0.0"
-			}
-		},
-		"node_modules/mpath": {
-			"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.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",
-				"regexp-clone": "^1.0.0",
-				"safe-buffer": "5.1.2",
-				"sliced": "1.0.1"
-			},
-			"engines": {
-				"node": ">=4.0.0"
-			}
-		},
-		"node_modules/mquery/node_modules/debug": {
-			"version": "3.1.0",
-			"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
-			"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
-			"dependencies": {
-				"ms": "2.0.0"
-			}
-		},
-		"node_modules/mquery/node_modules/ms": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-			"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
-		},
-		"node_modules/mquery/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/ms": {
-			"version": "2.1.2",
-			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-			"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
-		},
-		"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/process-nextick-args": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
-			"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
-		},
-		"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/querystringify": {
-			"version": "2.2.0",
-			"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
-			"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
-		},
-		"node_modules/readable-stream": {
-			"version": "2.3.7",
-			"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
-			"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
-			"dependencies": {
-				"core-util-is": "~1.0.0",
-				"inherits": "~2.0.3",
-				"isarray": "~1.0.0",
-				"process-nextick-args": "~2.0.0",
-				"safe-buffer": "~5.1.1",
-				"string_decoder": "~1.1.1",
-				"util-deprecate": "~1.0.1"
-			}
-		},
-		"node_modules/readable-stream/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/regexp-clone": {
-			"version": "1.0.0",
-			"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/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"
-			}
-		},
-		"node_modules/requires-port": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
-			"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
-		},
-		"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=",
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/safe-buffer": {
-			"version": "5.2.1",
-			"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
-			"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
-		},
-		"node_modules/saslprep": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
-			"integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==",
-			"optional": true,
-			"dependencies": {
-				"sparse-bitfield": "^3.0.3"
-			},
-			"engines": {
-				"node": ">=6"
-			}
-		},
-		"node_modules/semver": {
-			"version": "5.7.1",
-			"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
-			"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
-			"bin": {
-				"semver": "bin/semver"
-			}
-		},
-		"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=="
-		},
-		"node_modules/sliced": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
-			"integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E="
-		},
-		"node_modules/sparse-bitfield": {
-			"version": "3.0.3",
-			"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
-			"integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=",
-			"optional": true,
-			"dependencies": {
-				"memory-pager": "^1.0.2"
-			}
-		},
-		"node_modules/string_decoder": {
-			"version": "1.1.1",
-			"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-			"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
-			"dependencies": {
-				"safe-buffer": "~5.1.0"
-			}
-		},
-		"node_modules/string_decoder/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/typescript": {
-			"version": "4.1.3",
-			"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz",
-			"integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==",
-			"bin": {
-				"tsc": "bin/tsc",
-				"tsserver": "bin/tsserver"
-			},
-			"engines": {
-				"node": ">=4.2.0"
-			}
-		},
-		"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/url-parse": {
-			"version": "1.5.3",
-			"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz",
-			"integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==",
-			"dependencies": {
-				"querystringify": "^2.1.1",
-				"requires-port": "^1.0.0"
-			}
-		},
-		"node_modules/util-deprecate": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
-			"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
-		}
-	},
-	"dependencies": {
-		"@types/amqplib": {
-			"version": "0.8.1",
-			"resolved": "https://registry.npmjs.org/@types/amqplib/-/amqplib-0.8.1.tgz",
-			"integrity": "sha512-8dCjF+dHZ8Y6JOoHD1BMnxP0quAncvZq4wA/lS072NjX9vIzVRSMcmfKy2Os8ZQ8VWWp74MD09GMbVbKS6/Fxw==",
-			"dev": true,
-			"requires": {
-				"@types/bluebird": "*",
-				"@types/node": "*"
-			}
-		},
-		"@types/bluebird": {
-			"version": "3.5.36",
-			"resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.36.tgz",
-			"integrity": "sha512-HBNx4lhkxN7bx6P0++W8E289foSu8kO8GCk2unhuVggO+cE7rh9DhZUyPhUxNRG9m+5B5BTKxZQ5ZP92x/mx9Q==",
-			"dev": true
-		},
-		"@types/bson": {
-			"version": "4.0.3",
-			"resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.3.tgz",
-			"integrity": "sha512-mVRvYnTOZJz3ccpxhr3wgxVmSeiYinW+zlzQz3SXWaJmD1DuL05Jeq7nKw3SnbKmbleW5qrLG5vdyWe/A9sXhw==",
-			"requires": {
-				"@types/node": "*"
-			}
-		},
-		"@types/jsonwebtoken": {
-			"version": "8.5.0",
-			"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.0.tgz",
-			"integrity": "sha512-9bVao7LvyorRGZCw0VmH/dr7Og+NdjYSsKAxB43OQoComFbBgsEpoR9JW6+qSq/ogwVBg8GI2MfAlk4SYI4OLg==",
-			"requires": {
-				"@types/node": "*"
-			}
-		},
-		"@types/mongodb": {
-			"version": "3.6.6",
-			"resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.6.tgz",
-			"integrity": "sha512-ghYevKiSh/TGk2MAwSRZP7T1ilR9Pw8Fa7pT9GGVGZPUsWKdZjZ4G6LG3MqK2iXKdNba994F8W9ikA+qx2Eo3A==",
-			"requires": {
-				"@types/bson": "*",
-				"@types/node": "*"
-			}
-		},
-		"@types/mongoose": {
-			"version": "5.10.4",
-			"resolved": "https://registry.npmjs.org/@types/mongoose/-/mongoose-5.10.4.tgz",
-			"integrity": "sha512-U7fNDcTcdaSGzQ3+mlSBeebiYr6eaacJi330LTLOEh8Sm6mXfuec70ag/UXkL+alFm7pfAjFqfc7jEaJEJvAHQ==",
-			"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/node": {
-			"version": "14.14.25",
-			"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.25.tgz",
-			"integrity": "sha512-EPpXLOVqDvisVxtlbvzfyqSsFeQxltFbluZNRndIb8tr9KiBnYNLzrc1N3pyKUCww2RNrfHDViqDWWE1LCJQtQ=="
-		},
-		"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"
-			}
-		},
-		"amqplib": {
-			"version": "0.8.0",
-			"resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.8.0.tgz",
-			"integrity": "sha512-icU+a4kkq4Y1PS4NNi+YPDMwdlbFcZ1EZTQT2nigW3fvOb6AOgUQ9+Mk4ue0Zu5cBg/XpDzB40oH10ysrk2dmA==",
-			"requires": {
-				"bitsyntax": "~0.1.0",
-				"bluebird": "^3.7.2",
-				"buffer-more-ints": "~1.0.0",
-				"readable-stream": "1.x >=1.1.9",
-				"safe-buffer": "~5.2.1",
-				"url-parse": "~1.5.1"
-			},
-			"dependencies": {
-				"bluebird": {
-					"version": "3.7.2",
-					"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
-					"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
-				},
-				"isarray": {
-					"version": "0.0.1",
-					"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
-					"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
-				},
-				"readable-stream": {
-					"version": "1.1.14",
-					"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
-					"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
-					"requires": {
-						"core-util-is": "~1.0.0",
-						"inherits": "~2.0.1",
-						"isarray": "0.0.1",
-						"string_decoder": "~0.10.x"
-					}
-				},
-				"string_decoder": {
-					"version": "0.10.31",
-					"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
-					"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
-				}
-			}
-		},
-		"bitsyntax": {
-			"version": "0.1.0",
-			"resolved": "https://registry.npmjs.org/bitsyntax/-/bitsyntax-0.1.0.tgz",
-			"integrity": "sha512-ikAdCnrloKmFOugAfxWws89/fPc+nw0OOG1IzIE72uSOg/A3cYptKCjSUhDTuj7fhsJtzkzlv7l3b8PzRHLN0Q==",
-			"requires": {
-				"buffer-more-ints": "~1.0.0",
-				"debug": "~2.6.9",
-				"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=="
-				}
-			}
-		},
-		"bl": {
-			"version": "2.2.1",
-			"resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz",
-			"integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==",
-			"requires": {
-				"readable-stream": "^2.3.5",
-				"safe-buffer": "^5.1.1"
-			}
-		},
-		"bluebird": {
-			"version": "3.5.1",
-			"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
-			"integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
-		},
-		"bson": {
-			"version": "1.1.5",
-			"resolved": "https://registry.npmjs.org/bson/-/bson-1.1.5.tgz",
-			"integrity": "sha512-kDuEzldR21lHciPQAIulLs1LZlCXdLziXI6Mb/TDkwXhb//UORJNPXgcRs2CuO4H0DcMkpfT3/ySsP3unoZjBg=="
-		},
-		"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-more-ints": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz",
-			"integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg=="
-		},
-		"core-util-is": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
-			"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
-		},
-		"debug": {
-			"version": "2.6.9",
-			"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-			"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-			"requires": {
-				"ms": "2.0.0"
-			},
-			"dependencies": {
-				"ms": {
-					"version": "2.0.0",
-					"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-					"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
-				}
-			}
-		},
-		"denque": {
-			"version": "1.5.0",
-			"resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz",
-			"integrity": "sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ=="
-		},
-		"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"
-			}
-		},
-		"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"
-			}
-		},
-		"env-paths": {
-			"version": "2.2.1",
-			"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
-			"integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="
-		},
-		"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=="
-		},
-		"inherits": {
-			"version": "2.0.4",
-			"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-			"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
-		},
-		"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"
-			}
-		},
-		"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",
-			"integrity": "sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ=="
-		},
-		"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="
-		},
-		"memory-pager": {
-			"version": "1.5.0",
-			"resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
-			"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
-			"optional": true
-		},
-		"missing-native-js-functions": {
-			"version": "1.2.2",
-			"resolved": "https://registry.npmjs.org/missing-native-js-functions/-/missing-native-js-functions-1.2.2.tgz",
-			"integrity": "sha512-kNdwKWXh1hM8RdNqW2BIHsqD6fYN9RV27M+0uQF1pGF1yLKVc+xIv1VB8WEN1HxQ22N8Rj9sdEezOX2yBpsMZA=="
-		},
-		"mongodb": {
-			"version": "3.6.9",
-			"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.9.tgz",
-			"integrity": "sha512-1nSCKgSunzn/CXwgOWgbPHUWOO5OfERcuOWISmqd610jn0s8BU9K4879iJVabqgpPPbA6hO7rG48eq+fGED3Mg==",
-			"requires": {
-				"bl": "^2.2.1",
-				"bson": "^1.1.4",
-				"denque": "^1.4.1",
-				"optional-require": "^1.0.3",
-				"safe-buffer": "^5.1.2",
-				"saslprep": "^1.0.0"
-			}
-		},
-		"mongoose": {
-			"version": "5.12.3",
-			"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.12.3.tgz",
-			"integrity": "sha512-frsSR9yeldaRpSUeTegXCSB0Tu5UGq8sHuHBuEV31Jk3COyxlKFQPL7UsdMhxPUCmk74FpOYSmNwxhWBEqgzQg==",
-			"requires": {
-				"@types/mongodb": "^3.5.27",
-				"bson": "^1.1.4",
-				"kareem": "2.3.2",
-				"mongodb": "3.6.5",
-				"mongoose-legacy-pluralize": "1.0.2",
-				"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",
-				"sliced": "1.0.1"
-			},
-			"dependencies": {
-				"mongodb": {
-					"version": "3.6.5",
-					"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.5.tgz",
-					"integrity": "sha512-mQlYKw1iGbvJJejcPuyTaytq0xxlYbIoVDm2FODR+OHxyEiMR021vc32bTvamgBjCswsD54XIRwhg3yBaWqJjg==",
-					"requires": {
-						"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"
-					}
-				}
-			}
-		},
-		"mongoose-autopopulate": {
-			"version": "0.12.3",
-			"resolved": "https://registry.npmjs.org/mongoose-autopopulate/-/mongoose-autopopulate-0.12.3.tgz",
-			"integrity": "sha512-yNmYsfi6OpS/GQ+48mkB0KQ199ExHmmPrt3wt3fyxPHPMtEBGts7yq3wBQR6VgKCPOQaKvCI1URbJCPOtrPeLw=="
-		},
-		"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.3",
-			"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.3.tgz",
-			"integrity": "sha512-eb9rRvhDltXVNL6Fxd2zM9D4vKBxjVVQNLNijlj7uoXUy19zNDsIif5zR+pWmPCWNKwAtqyo4JveQm4nfD5+eA=="
-		},
-		"mquery": {
-			"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",
-				"regexp-clone": "^1.0.0",
-				"safe-buffer": "5.1.2",
-				"sliced": "1.0.1"
-			},
-			"dependencies": {
-				"debug": {
-					"version": "3.1.0",
-					"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
-					"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
-					"requires": {
-						"ms": "2.0.0"
-					}
-				},
-				"ms": {
-					"version": "2.0.0",
-					"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-					"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
-				},
-				"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=="
-				}
-			}
-		},
-		"ms": {
-			"version": "2.1.2",
-			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-			"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
-		},
-		"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=="
-		},
-		"process-nextick-args": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
-			"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
-		},
-		"punycode": {
-			"version": "2.1.1",
-			"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
-			"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
-		},
-		"querystringify": {
-			"version": "2.2.0",
-			"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
-			"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
-		},
-		"readable-stream": {
-			"version": "2.3.7",
-			"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
-			"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
-			"requires": {
-				"core-util-is": "~1.0.0",
-				"inherits": "~2.0.3",
-				"isarray": "~1.0.0",
-				"process-nextick-args": "~2.0.0",
-				"safe-buffer": "~5.1.1",
-				"string_decoder": "~1.1.1",
-				"util-deprecate": "~1.0.1"
-			},
-			"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=="
-				}
-			}
-		},
-		"regexp-clone": {
-			"version": "1.0.0",
-			"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"
-			}
-		},
-		"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=="
-		},
-		"requires-port": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
-			"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
-		},
-		"resolve-from": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz",
-			"integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c="
-		},
-		"safe-buffer": {
-			"version": "5.2.1",
-			"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
-			"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
-		},
-		"saslprep": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
-			"integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==",
-			"optional": true,
-			"requires": {
-				"sparse-bitfield": "^3.0.3"
-			}
-		},
-		"semver": {
-			"version": "5.7.1",
-			"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
-			"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
-		},
-		"sift": {
-			"version": "7.0.1",
-			"resolved": "https://registry.npmjs.org/sift/-/sift-7.0.1.tgz",
-			"integrity": "sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g=="
-		},
-		"sliced": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
-			"integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E="
-		},
-		"sparse-bitfield": {
-			"version": "3.0.3",
-			"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
-			"integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=",
-			"optional": true,
-			"requires": {
-				"memory-pager": "^1.0.2"
-			}
-		},
-		"string_decoder": {
-			"version": "1.1.1",
-			"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-			"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
-			"requires": {
-				"safe-buffer": "~5.1.0"
-			},
-			"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=="
-				}
-			}
-		},
-		"typescript": {
-			"version": "4.1.3",
-			"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz",
-			"integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg=="
-		},
-		"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"
-			}
-		},
-		"url-parse": {
-			"version": "1.5.3",
-			"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz",
-			"integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==",
-			"requires": {
-				"querystringify": "^2.1.1",
-				"requires-port": "^1.0.0"
-			}
-		},
-		"util-deprecate": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
-			"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
-		}
-	}
-}
diff --git a/rtc/package.json b/rtc/package.json
deleted file mode 100644
index 0478fe69..00000000
--- a/rtc/package.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
-	"name": "@fosscord/server-util",
-	"version": "1.3.52",
-	"description": "Utility functions for the all server repositories",
-	"main": "dist/index.js",
-	"types": "dist/index.d.ts",
-	"scripts": {
-		"test": "echo \"Error: no test specified\" && exit 1",
-		"build": "tsc -b .",
-		"prepublish": "npm run build"
-	},
-	"repository": {
-		"type": "git",
-		"url": "git+https://github.com/fosscord/fosscord-server-util.git"
-	},
-	"keywords": [
-		"discord",
-		"fosscord",
-		"fosscord-server-util",
-		"discord open source",
-		"discord-open-source"
-	],
-	"author": "Fosscord",
-	"license": "GPLV3",
-	"bugs": {
-		"url": "https://github.com/fosscord/fosscord-server-util/issues"
-	},
-	"homepage": "https://docs.fosscord.com/",
-	"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",
-		"amqplib": "^0.8.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.9",
-		"mongoose": "^5.12.3",
-		"mongoose-autopopulate": "^0.12.3",
-		"typescript": "^4.1.3"
-	},
-	"devDependencies": {
-		"@types/amqplib": "^0.8.1"
-	}
-}
diff --git a/rtc/src/index.ts b/rtc/src/index.ts
deleted file mode 100644
index 3565fb6b..00000000
--- a/rtc/src/index.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-export * from "./util/checkToken";
-
-export * as Constants from "./util/Constants";
-export * from "./models/index";
-export * from "./util/index";
-
-import Config from "./util/Config";
-import db, { MongooseCache, toObject } from "./util/Database";
-
-export { Config, db, MongooseCache, toObject };
diff --git a/rtc/src/models/Activity.ts b/rtc/src/models/Activity.ts
deleted file mode 100644
index 17abd1ca..00000000
--- a/rtc/src/models/Activity.ts
+++ /dev/null
@@ -1,132 +0,0 @@
-import { User } from "..";
-import { ClientStatus, Status } from "./Status";
-import { Schema, model, Types, Document } from "mongoose";
-import toBigInt from "../util/toBigInt";
-
-export interface Presence {
-	user: User;
-	guild_id?: string;
-	status: Status;
-	activities: Activity[];
-	client_status: ClientStatus;
-}
-
-export interface Activity {
-	name: string;
-	type: ActivityType;
-	url?: string;
-	created_at?: Date;
-	timestamps?: {
-		start?: number;
-		end?: number;
-	}[];
-	application_id?: string;
-	details?: string;
-	state?: string;
-	emoji?: {
-		name: string;
-		id?: string;
-		amimated?: boolean;
-	};
-	party?: {
-		id?: string;
-		size?: [number, number];
-	};
-	assets?: {
-		large_image?: string;
-		large_text?: string;
-		small_image?: string;
-		small_text?: string;
-	};
-	secrets?: {
-		join?: string;
-		spectate?: string;
-		match?: string;
-	};
-	instance?: boolean;
-	flags?: bigint;
-}
-
-export const ActivitySchema = {
-	name: { type: String, required: true },
-	type: { type: Number, required: true },
-	url: String,
-	created_at: Date,
-	timestamps: [
-		{
-			start: Number,
-			end: Number,
-		},
-	],
-	application_id: String,
-	details: String,
-	state: String,
-	emoji: {
-		name: String,
-		id: String,
-		amimated: Boolean,
-	},
-	party: {
-		id: String,
-		size: [Number, Number],
-	},
-	assets: {
-		large_image: String,
-		large_text: String,
-		small_image: String,
-		small_text: String,
-	},
-	secrets: {
-		join: String,
-		spectate: String,
-		match: String,
-	},
-	instance: Boolean,
-	flags: { type: String, get: toBigInt },
-};
-
-export const ActivityBodySchema = {
-	name: String,
-	type: Number,
-	$url: String,
-	$created_at: Date,
-	$timestamps: [
-		{
-			$start: Number,
-			$end: Number,
-		},
-	],
-	$application_id: String,
-	$details: String,
-	$state: String,
-	$emoji: {
-		$name: String,
-		$id: String,
-		$amimated: Boolean,
-	},
-	$party: {
-		$id: String,
-		$size: [Number, Number],
-	},
-	$assets: {
-		$large_image: String,
-		$large_text: String,
-		$small_image: String,
-		$small_text: String,
-	},
-	$secrets: {
-		$join: String,
-		$spectate: String,
-		$match: String,
-	},
-	$instance: Boolean,
-	$flags: BigInt,
-};
-
-export enum ActivityType {
-	GAME = 0,
-	STREAMING = 1,
-	LISTENING = 2,
-	CUSTOM = 4,
-	COMPETING = 5,
-}
diff --git a/rtc/src/models/Application.ts b/rtc/src/models/Application.ts
deleted file mode 100644
index fae6e8db..00000000
--- a/rtc/src/models/Application.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-import { Team } from "./Team";
-
-export interface Application {
-	id: string;
-	name: string;
-	icon: string | null;
-	description: string;
-	rpc_origins: string[] | null;
-	bot_public: boolean;
-	bot_require_code_grant: boolean;
-	terms_of_service_url: string | null;
-	privacy_policy_url: string | null;
-	owner_id: string;
-	summary: string | null;
-	verify_key: string;
-	team: Team | null;
-	guild_id: string; // if this application is a game sold on Discord, this field will be the guild to which it has been linked
-	primary_sku_id: string | null; // if this application is a game sold on Discord, this field will be the id of the "Game SKU" that is created, if exists
-	slug: string | null; // if this application is a game sold on Discord, this field will be the URL slug that links to the store page
-	cover_image: string | null; // the application's default rich presence invite cover image hash
-	flags: number; // the application's public flags
-}
-
-export interface ApplicationCommand {
-	id: string;
-	application_id: string;
-	name: string;
-	description: string;
-	options?: ApplicationCommandOption[];
-}
-
-export interface ApplicationCommandOption {
-	type: ApplicationCommandOptionType;
-	name: string;
-	description: string;
-	required?: boolean;
-	choices?: ApplicationCommandOptionChoice[];
-	options?: ApplicationCommandOption[];
-}
-
-export interface ApplicationCommandOptionChoice {
-	name: string;
-	value: string | number;
-}
-
-export enum ApplicationCommandOptionType {
-	SUB_COMMAND = 1,
-	SUB_COMMAND_GROUP = 2,
-	STRING = 3,
-	INTEGER = 4,
-	BOOLEAN = 5,
-	USER = 6,
-	CHANNEL = 7,
-	ROLE = 8,
-}
-
-export interface ApplicationCommandInteractionData {
-	id: string;
-	name: string;
-	options?: ApplicationCommandInteractionDataOption[];
-}
-
-export interface ApplicationCommandInteractionDataOption {
-	name: string;
-	value?: any;
-	options?: ApplicationCommandInteractionDataOption[];
-}
diff --git a/rtc/src/models/AuditLog.ts b/rtc/src/models/AuditLog.ts
deleted file mode 100644
index 02b2c444..00000000
--- a/rtc/src/models/AuditLog.ts
+++ /dev/null
@@ -1,220 +0,0 @@
-import { Schema, Document, Types } from "mongoose";
-import db from "../util/Database";
-import { ChannelPermissionOverwrite } from "./Channel";
-import { PublicUser } from "./User";
-
-export interface AuditLogResponse {
-	webhooks: []; // TODO:
-	users: PublicUser[];
-	audit_log_entries: AuditLogEntries[];
-	integrations: []; // TODO:
-}
-
-export interface AuditLogEntries {
-	target_id?: string;
-	user_id: string;
-	id: string;
-	action_type: AuditLogEvents;
-	options?: {
-		delete_member_days?: string;
-		members_removed?: string;
-		channel_id?: string;
-		messaged_id?: string;
-		count?: string;
-		id?: string;
-		type?: string;
-		role_name?: string;
-	};
-	changes: AuditLogChange[];
-	reason?: string;
-}
-
-export interface AuditLogChange {
-	new_value?: AuditLogChangeValue;
-	old_value?: AuditLogChangeValue;
-	key: string;
-}
-
-export interface AuditLogChangeValue {
-	name?: string;
-	description?: string;
-	icon_hash?: string;
-	splash_hash?: string;
-	discovery_splash_hash?: string;
-	banner_hash?: string;
-	owner_id?: string;
-	region?: string;
-	preferred_locale?: string;
-	afk_channel_id?: string;
-	afk_timeout?: number;
-	rules_channel_id?: string;
-	public_updates_channel_id?: string;
-	mfa_level?: number;
-	verification_level?: number;
-	explicit_content_filter?: number;
-	default_message_notifications?: number;
-	vanity_url_code?: string;
-	$add?: {}[];
-	$remove?: {}[];
-	prune_delete_days?: number;
-	widget_enabled?: boolean;
-	widget_channel_id?: string;
-	system_channel_id?: string;
-	position?: number;
-	topic?: string;
-	bitrate?: number;
-	permission_overwrites?: ChannelPermissionOverwrite[];
-	nsfw?: boolean;
-	application_id?: string;
-	rate_limit_per_user?: number;
-	permissions?: string;
-	color?: number;
-	hoist?: boolean;
-	mentionable?: boolean;
-	allow?: string;
-	deny?: string;
-	code?: string;
-	channel_id?: string;
-	inviter_id?: string;
-	max_uses?: number;
-	uses?: number;
-	max_age?: number;
-	temporary?: boolean;
-	deaf?: boolean;
-	mute?: boolean;
-	nick?: string;
-	avatar_hash?: string;
-	id?: string;
-	type?: number;
-	enable_emoticons?: boolean;
-	expire_behavior?: number;
-	expire_grace_period?: number;
-	user_limit?: number;
-}
-
-export interface AuditLogEntriesDocument extends Document, AuditLogEntries {
-	id: string;
-}
-
-export const AuditLogChanges = {
-	name: String,
-	description: String,
-	icon_hash: String,
-	splash_hash: String,
-	discovery_splash_hash: String,
-	banner_hash: String,
-	owner_id: String,
-	region: String,
-	preferred_locale: String,
-	afk_channel_id: String,
-	afk_timeout: Number,
-	rules_channel_id: String,
-	public_updates_channel_id: String,
-	mfa_level: Number,
-	verification_level: Number,
-	explicit_content_filter: Number,
-	default_message_notifications: Number,
-	vanity_url_code: String,
-	$add: [{}],
-	$remove: [{}],
-	prune_delete_days: Number,
-	widget_enabled: Boolean,
-	widget_channel_id: String,
-	system_channel_id: String,
-	position: Number,
-	topic: String,
-	bitrate: Number,
-	permission_overwrites: [{}],
-	nsfw: Boolean,
-	application_id: String,
-	rate_limit_per_user: Number,
-	permissions: String,
-	color: Number,
-	hoist: Boolean,
-	mentionable: Boolean,
-	allow: String,
-	deny: String,
-	code: String,
-	channel_id: String,
-	inviter_id: String,
-	max_uses: Number,
-	uses: Number,
-	max_age: Number,
-	temporary: Boolean,
-	deaf: Boolean,
-	mute: Boolean,
-	nick: String,
-	avatar_hash: String,
-	id: String,
-	type: Number,
-	enable_emoticons: Boolean,
-	expire_behavior: Number,
-	expire_grace_period: Number,
-	user_limit: Number,
-};
-
-export const AuditLogSchema = new Schema({
-	target_id: String,
-	user_id: { type: String, required: true },
-	id: { type: String, required: true },
-	action_type: { type: Number, required: true },
-	options: {
-		delete_member_days: String,
-		members_removed: String,
-		channel_id: String,
-		messaged_id: String,
-		count: String,
-		id: String,
-		type: { type: Number },
-		role_name: String,
-	},
-	changes: [
-		{
-			new_value: AuditLogChanges,
-			old_value: AuditLogChanges,
-			key: String,
-		},
-	],
-	reason: String,
-});
-
-// @ts-ignore
-export const AuditLogModel = db.model<AuditLogEntries>("AuditLog", AuditLogSchema, "auditlogs");
-
-export enum AuditLogEvents {
-	GUILD_UPDATE = 1,
-	CHANNEL_CREATE = 10,
-	CHANNEL_UPDATE = 11,
-	CHANNEL_DELETE = 12,
-	CHANNEL_OVERWRITE_CREATE = 13,
-	CHANNEL_OVERWRITE_UPDATE = 14,
-	CHANNEL_OVERWRITE_DELETE = 15,
-	MEMBER_KICK = 20,
-	MEMBER_PRUNE = 21,
-	MEMBER_BAN_ADD = 22,
-	MEMBER_BAN_REMOVE = 23,
-	MEMBER_UPDATE = 24,
-	MEMBER_ROLE_UPDATE = 25,
-	MEMBER_MOVE = 26,
-	MEMBER_DISCONNECT = 27,
-	BOT_ADD = 28,
-	ROLE_CREATE = 30,
-	ROLE_UPDATE = 31,
-	ROLE_DELETE = 32,
-	INVITE_CREATE = 40,
-	INVITE_UPDATE = 41,
-	INVITE_DELETE = 42,
-	WEBHOOK_CREATE = 50,
-	WEBHOOK_UPDATE = 51,
-	WEBHOOK_DELETE = 52,
-	EMOJI_CREATE = 60,
-	EMOJI_UPDATE = 61,
-	EMOJI_DELETE = 62,
-	MESSAGE_DELETE = 72,
-	MESSAGE_BULK_DELETE = 73,
-	MESSAGE_PIN = 74,
-	MESSAGE_UNPIN = 75,
-	INTEGRATION_CREATE = 80,
-	INTEGRATION_UPDATE = 81,
-	INTEGRATION_DELETE = 82,
-}
diff --git a/rtc/src/models/Ban.ts b/rtc/src/models/Ban.ts
deleted file mode 100644
index f09950ee..00000000
--- a/rtc/src/models/Ban.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { Schema, model, Types, Document } from "mongoose";
-import db from "../util/Database";
-import { PublicUserProjection, UserModel } from "./User";
-
-export interface Ban extends Document {
-	user_id: string;
-	guild_id: string;
-	executor_id: string;
-	ip: string;
-	reason?: string;
-}
-
-export const BanSchema = new Schema({
-	user_id: { type: String, required: true },
-	guild_id: { type: String, required: true },
-	executor_id: { type: String, required: true },
-	reason: String,
-	ip: String, // ? Should we store this in here, or in the UserModel?
-});
-
-BanSchema.virtual("user", {
-	ref: UserModel,
-	localField: "user_id",
-	foreignField: "id",
-	justOne: true,
-	autopopulate: { select: PublicUserProjection },
-});
-
-BanSchema.set("removeResponse", ["user_id"]);
-
-// @ts-ignore
-export const BanModel = db.model<Ban>("Ban", BanSchema, "bans");
diff --git a/rtc/src/models/Channel.ts b/rtc/src/models/Channel.ts
deleted file mode 100644
index 1dd05896..00000000
--- a/rtc/src/models/Channel.ts
+++ /dev/null
@@ -1,109 +0,0 @@
-import { Schema, model, Types, Document } from "mongoose";
-import db from "../util/Database";
-import toBigInt from "../util/toBigInt";
-import { PublicUserProjection, UserModel } from "./User";
-
-// @ts-ignore
-export interface AnyChannel extends Channel, DMChannel, TextChannel, VoiceChannel {
-	recipient_ids: null | string[];
-}
-
-export interface ChannelDocument extends Document, AnyChannel {
-	id: string;
-}
-
-export const ChannelSchema = new Schema({
-	id: String,
-	created_at: { type: Schema.Types.Date, required: true },
-	name: String, // can't be required for dm channels
-	type: { type: Number, required: true },
-	guild_id: String,
-	owner_id: String,
-	parent_id: String,
-	recipient_ids: [String],
-	position: Number,
-	last_message_id: String,
-	last_pin_timestamp: Date,
-	nsfw: Boolean,
-	rate_limit_per_user: Number,
-	topic: String,
-	permission_overwrites: [
-		{
-			allow: { type: String, get: toBigInt },
-			deny: { type: String, get: toBigInt },
-			id: String,
-			type: { type: Number },
-		},
-	],
-});
-
-ChannelSchema.virtual("recipients", {
-	ref: UserModel,
-	localField: "recipient_ids",
-	foreignField: "id",
-	justOne: false,
-	autopopulate: { select: PublicUserProjection },
-});
-
-ChannelSchema.set("removeResponse", ["recipient_ids"]);
-
-// @ts-ignore
-export const ChannelModel = db.model<ChannelDocument>("Channel", ChannelSchema, "channels");
-
-export interface Channel {
-	id: string;
-	created_at: Date;
-	name: string;
-	type: number;
-}
-
-export interface TextBasedChannel {
-	last_message_id?: string;
-	last_pin_timestamp?: number;
-}
-
-export interface GuildChannel extends Channel {
-	guild_id: string;
-	position: number;
-	parent_id?: string;
-	permission_overwrites: ChannelPermissionOverwrite[];
-}
-
-export interface ChannelPermissionOverwrite {
-	allow: bigint; // for bitfields we use bigints
-	deny: bigint; // for bitfields we use bigints
-	id: string;
-	type: ChannelPermissionOverwriteType;
-}
-
-export enum ChannelPermissionOverwriteType {
-	role = 0,
-	member = 1,
-}
-
-export interface VoiceChannel extends GuildChannel {
-	video_quality_mode?: number;
-	bitrate?: number;
-	user_limit?: number;
-}
-
-export interface TextChannel extends GuildChannel, TextBasedChannel {
-	nsfw: boolean;
-	rate_limit_per_user: number;
-	topic?: string;
-}
-// @ts-ignore
-export interface DMChannel extends Channel, TextBasedChannel {
-	owner_id: string;
-	recipient_ids: string[];
-}
-
-export enum ChannelType {
-	GUILD_TEXT = 0, // a text channel within a server
-	DM = 1, // a direct message between users
-	GUILD_VOICE = 2, // a voice channel within a server
-	GROUP_DM = 3, // a direct message between multiple users
-	GUILD_CATEGORY = 4, // an organizational category that contains up to 50 channels
-	GUILD_NEWS = 5, // a channel that users can follow and crosspost into their own server
-	GUILD_STORE = 6, // a channel in which game developers can sell their game on Discord
-}
diff --git a/rtc/src/models/Emoji.ts b/rtc/src/models/Emoji.ts
deleted file mode 100644
index 3e5cad53..00000000
--- a/rtc/src/models/Emoji.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { Schema, model, Types, Document } from "mongoose";
-import db from "../util/Database";
-
-export interface Emoji extends Document {
-	id: string;
-	animated: boolean;
-	available: boolean;
-	guild_id: string;
-	managed: boolean;
-	name: string;
-	require_colons: boolean;
-	url: string;
-	roles: string[]; // roles this emoji is whitelisted to (new discord feature?)
-}
-
-export const EmojiSchema = new Schema({
-	id: { type: String, required: true },
-	animated: Boolean,
-	available: Boolean,
-	guild_id: String,
-	managed: Boolean,
-	name: String,
-	require_colons: Boolean,
-	url: String,
-	roles: [String],
-});
-
-// @ts-ignore
-export const EmojiModel = db.model<Emoji>("Emoji", EmojiSchema, "emojis");
diff --git a/rtc/src/models/Event.ts b/rtc/src/models/Event.ts
deleted file mode 100644
index 1564107d..00000000
--- a/rtc/src/models/Event.ts
+++ /dev/null
@@ -1,540 +0,0 @@
-import { ConnectedAccount, PublicUser, Relationship, User, UserSettings } from "./User";
-import { DMChannel, Channel } from "./Channel";
-import { Guild } from "./Guild";
-import { Member, PublicMember, UserGuildSettings } from "./Member";
-import { Emoji } from "./Emoji";
-import { Presence } from "./Activity";
-import { Role } from "./Role";
-import { Invite } from "./Invite";
-import { Message, PartialEmoji } from "./Message";
-import { VoiceState } from "./VoiceState";
-import { ApplicationCommand } from "./Application";
-import { Interaction } from "./Interaction";
-import { Schema, model, Types, Document } from "mongoose";
-import db from "../util/Database";
-
-export interface Event {
-	guild_id?: string;
-	user_id?: string;
-	channel_id?: string;
-	created_at?: Date;
-	event: EVENT;
-	data?: any;
-}
-
-export interface EventDocument extends Event, Document {}
-
-export const EventSchema = new Schema({
-	guild_id: String,
-	user_id: String,
-	channel_id: String,
-	created_at: { type: Date, required: true },
-	event: { type: String, required: true },
-	data: Object,
-});
-
-// @ts-ignore
-export const EventModel = db.model<EventDocument>("Event", EventSchema, "events");
-
-// ! Custom Events that shouldn't get sent to the client but processed by the server
-
-export interface InvalidatedEvent extends Event {
-	event: "INVALIDATED";
-}
-
-// ! END Custom Events that shouldn't get sent to the client but processed by the server
-
-export interface ReadyEventData {
-	v: number;
-	user: PublicUser & {
-		mobile: boolean;
-		desktop: boolean;
-		email: string | null;
-		flags: bigint;
-		mfa_enabled: boolean;
-		nsfw_allowed: boolean;
-		phone: string | null;
-		premium: boolean;
-		premium_type: number;
-		verified: boolean;
-		bot: boolean;
-	};
-	private_channels: DMChannel[]; // this will be empty for bots
-	session_id: string; // resuming
-	guilds: Guild[];
-	analytics_token?: string;
-	connected_accounts?: ConnectedAccount[];
-	consents?: {
-		personalization?: {
-			consented?: boolean;
-		};
-	};
-	country_code?: string; // e.g. DE
-	friend_suggestion_count?: number;
-	geo_ordered_rtc_regions?: string[]; // ["europe","russie","india","us-east","us-central"]
-	experiments?: [number, number, number, number, number][];
-	guild_experiments?: [
-		// ? what are guild_experiments?
-		// this is the structure of it:
-		number,
-		null,
-		number,
-		[[number, { e: number; s: number }[]]],
-		[number, [[number, [number, number]]]],
-		{ b: number; k: bigint[] }[]
-	][];
-	guild_join_requests?: []; // ? what is this? this is new
-	shard?: [number, number];
-	user_settings?: UserSettings;
-	relationships?: Relationship[]; // TODO
-	read_state: {
-		entries: []; // TODO
-		partial: boolean;
-		version: number;
-	};
-	user_guild_settings?: {
-		entries: UserGuildSettings[];
-		version: number;
-		partial: boolean;
-	};
-	application?: {
-		id: string;
-		flags: bigint;
-	};
-	merged_members?: Omit<Member, "settings" | "user">[][];
-	// probably all users who the user is in contact with
-	users?: {
-		avatar: string | null;
-		discriminator: string;
-		id: string;
-		username: string;
-		bot: boolean;
-		public_flags: bigint;
-	}[];
-}
-
-export interface ReadyEvent extends Event {
-	event: "READY";
-	data: ReadyEventData;
-}
-
-export interface ChannelCreateEvent extends Event {
-	event: "CHANNEL_CREATE";
-	data: Channel;
-}
-
-export interface ChannelUpdateEvent extends Event {
-	event: "CHANNEL_UPDATE";
-	data: Channel;
-}
-
-export interface ChannelDeleteEvent extends Event {
-	event: "CHANNEL_DELETE";
-	data: Channel;
-}
-
-export interface ChannelPinsUpdateEvent extends Event {
-	event: "CHANNEL_PINS_UPDATE";
-	data: {
-		guild_id?: string;
-		channel_id: string;
-		last_pin_timestamp?: number;
-	};
-}
-
-export interface GuildCreateEvent extends Event {
-	event: "GUILD_CREATE";
-	data: Guild;
-}
-
-export interface GuildUpdateEvent extends Event {
-	event: "GUILD_UPDATE";
-	data: Guild;
-}
-
-export interface GuildDeleteEvent extends Event {
-	event: "GUILD_DELETE";
-	data: {
-		id: string;
-		unavailable?: boolean;
-	};
-}
-
-export interface GuildBanAddEvent extends Event {
-	event: "GUILD_BAN_ADD";
-	data: {
-		guild_id: string;
-		user: User;
-	};
-}
-
-export interface GuildBanRemoveEvent extends Event {
-	event: "GUILD_BAN_REMOVE";
-	data: {
-		guild_id: string;
-		user: User;
-	};
-}
-
-export interface GuildEmojiUpdateEvent extends Event {
-	event: "GUILD_EMOJI_UPDATE";
-	data: {
-		guild_id: string;
-		emojis: Emoji[];
-	};
-}
-
-export interface GuildIntegrationUpdateEvent extends Event {
-	event: "GUILD_INTEGRATIONS_UPDATE";
-	data: {
-		guild_id: string;
-	};
-}
-
-export interface GuildMemberAddEvent extends Event {
-	event: "GUILD_MEMBER_ADD";
-	data: PublicMember & {
-		guild_id: string;
-	};
-}
-
-export interface GuildMemberRemoveEvent extends Event {
-	event: "GUILD_MEMBER_REMOVE";
-	data: {
-		guild_id: string;
-		user: User;
-	};
-}
-
-export interface GuildMemberUpdateEvent extends Event {
-	event: "GUILD_MEMBER_UPDATE";
-	data: {
-		guild_id: string;
-		roles: string[];
-		user: User;
-		nick?: string;
-		joined_at?: Date;
-		premium_since?: number;
-		pending?: boolean;
-	};
-}
-
-export interface GuildMembersChunkEvent extends Event {
-	event: "GUILD_MEMBERS_CHUNK";
-	data: {
-		guild_id: string;
-		members: PublicMember[];
-		chunk_index: number;
-		chunk_count: number;
-		not_found: string[];
-		presences: Presence[];
-		nonce?: string;
-	};
-}
-
-export interface GuildRoleCreateEvent extends Event {
-	event: "GUILD_ROLE_CREATE";
-	data: {
-		guild_id: string;
-		role: Role;
-	};
-}
-
-export interface GuildRoleUpdateEvent extends Event {
-	event: "GUILD_ROLE_UPDATE";
-	data: {
-		guild_id: string;
-		role: Role;
-	};
-}
-
-export interface GuildRoleDeleteEvent extends Event {
-	event: "GUILD_ROLE_DELETE";
-	data: {
-		guild_id: string;
-		role_id: string;
-	};
-}
-
-export interface InviteCreateEvent extends Event {
-	event: "INVITE_CREATE";
-	data: Omit<Invite, "guild" | "channel"> & {
-		channel_id: string;
-		guild_id?: string;
-	};
-}
-
-export interface InviteDeleteEvent extends Event {
-	event: "INVITE_DELETE";
-	data: {
-		channel_id: string;
-		guild_id?: string;
-		code: string;
-	};
-}
-
-export type MessagePayload = Omit<Message, "author_id"> & {
-	channel_id: string;
-	guild_id?: string;
-	author: PublicUser;
-	member: PublicMember;
-	mentions: (PublicUser & { member: PublicMember })[];
-};
-
-export interface MessageCreateEvent extends Event {
-	event: "MESSAGE_CREATE";
-	data: MessagePayload;
-}
-
-export interface MessageUpdateEvent extends Event {
-	event: "MESSAGE_UPDATE";
-	data: MessagePayload;
-}
-
-export interface MessageDeleteEvent extends Event {
-	event: "MESSAGE_DELETE";
-	data: {
-		id: string;
-		channel_id: string;
-		guild_id?: string;
-	};
-}
-
-export interface MessageDeleteBulkEvent extends Event {
-	event: "MESSAGE_DELETE_BULK";
-	data: {
-		ids: string[];
-		channel_id: string;
-		guild_id?: string;
-	};
-}
-
-export interface MessageReactionAddEvent extends Event {
-	event: "MESSAGE_REACTION_ADD";
-	data: {
-		user_id: string;
-		channel_id: string;
-		message_id: string;
-		guild_id?: string;
-		member?: PublicMember;
-		emoji: PartialEmoji;
-	};
-}
-
-export interface MessageReactionRemoveEvent extends Event {
-	event: "MESSAGE_REACTION_REMOVE";
-	data: {
-		user_id: string;
-		channel_id: string;
-		message_id: string;
-		guild_id?: string;
-		emoji: PartialEmoji;
-	};
-}
-
-export interface MessageReactionRemoveAllEvent extends Event {
-	event: "MESSAGE_REACTION_REMOVE_ALL";
-	data: {
-		channel_id: string;
-		message_id: string;
-		guild_id?: string;
-	};
-}
-
-export interface MessageReactionRemoveEmojiEvent extends Event {
-	event: "MESSAGE_REACTION_REMOVE_EMOJI";
-	data: {
-		channel_id: string;
-		message_id: string;
-		guild_id?: string;
-		emoji: PartialEmoji;
-	};
-}
-
-export interface PresenceUpdateEvent extends Event {
-	event: "PRESENCE_UPDATE";
-	data: Presence;
-}
-
-export interface TypingStartEvent extends Event {
-	event: "TYPING_START";
-	data: {
-		channel_id: string;
-		user_id: string;
-		timestamp: number;
-		guild_id?: string;
-		member?: PublicMember;
-	};
-}
-
-export interface UserUpdateEvent extends Event {
-	event: "USER_UPDATE";
-	data: User;
-}
-
-export interface VoiceStateUpdateEvent extends Event {
-	event: "VOICE_STATE_UPDATE";
-	data: VoiceState & {
-		member: PublicMember;
-	};
-}
-
-export interface VoiceServerUpdateEvent extends Event {
-	event: "VOICE_SERVER_UPDATE";
-	data: {
-		token: string;
-		guild_id: string;
-		endpoint: string;
-	};
-}
-
-export interface WebhooksUpdateEvent extends Event {
-	event: "WEBHOOKS_UPDATE";
-	data: {
-		guild_id: string;
-		channel_id: string;
-	};
-}
-
-export type ApplicationCommandPayload = ApplicationCommand & {
-	guild_id: string;
-};
-
-export interface ApplicationCommandCreateEvent extends Event {
-	event: "APPLICATION_COMMAND_CREATE";
-	data: ApplicationCommandPayload;
-}
-
-export interface ApplicationCommandUpdateEvent extends Event {
-	event: "APPLICATION_COMMAND_UPDATE";
-	data: ApplicationCommandPayload;
-}
-
-export interface ApplicationCommandDeleteEvent extends Event {
-	event: "APPLICATION_COMMAND_DELETE";
-	data: ApplicationCommandPayload;
-}
-
-export interface InteractionCreateEvent extends Event {
-	event: "INTERACTION_CREATE";
-	data: Interaction;
-}
-
-export interface MessageAckEvent extends Event {
-	event: "MESSAGE_ACK";
-	data: {
-		channel_id: string;
-		message_id: string;
-		version?: number;
-		manual?: boolean;
-		mention_count?: number;
-	};
-}
-
-export interface RelationshipAddEvent extends Event {
-	event: "RELATIONSHIP_ADD";
-	data: Relationship & {
-		should_notify?: boolean;
-		user: PublicUser;
-	};
-}
-
-export interface RelationshipRemoveEvent extends Event {
-	event: "RELATIONSHIP_REMOVE";
-	data: Omit<Relationship, "nickname">;
-}
-
-// located in collection events
-
-export enum EVENTEnum {
-	Ready = "READY",
-	ChannelCreate = "CHANNEL_CREATE",
-	ChannelUpdate = "CHANNEL_UPDATE",
-	ChannelDelete = "CHANNEL_DELETE",
-	ChannelPinsUpdate = "CHANNEL_PINS_UPDATE",
-	GuildCreate = "GUILD_CREATE",
-	GuildUpdate = "GUILD_UPDATE",
-	GuildDelete = "GUILD_DELETE",
-	GuildBanAdd = "GUILD_BAN_ADD",
-	GuildBanRemove = "GUILD_BAN_REMOVE",
-	GuildEmojUpdate = "GUILD_EMOJI_UPDATE",
-	GuildIntegrationsUpdate = "GUILD_INTEGRATIONS_UPDATE",
-	GuildMemberAdd = "GUILD_MEMBER_ADD",
-	GuildMemberRempve = "GUILD_MEMBER_REMOVE",
-	GuildMemberUpdate = "GUILD_MEMBER_UPDATE",
-	GuildMemberSpeaking = "GUILD_MEMBER_SPEAKING",
-	GuildMembersChunk = "GUILD_MEMBERS_CHUNK",
-	GuildRoleCreate = "GUILD_ROLE_CREATE",
-	GuildRoleDelete = "GUILD_ROLE_DELETE",
-	GuildRoleUpdate = "GUILD_ROLE_UPDATE",
-	InviteCreate = "INVITE_CREATE",
-	InviteDelete = "INVITE_DELETE",
-	MessageCreate = "MESSAGE_CREATE",
-	MessageUpdate = "MESSAGE_UPDATE",
-	MessageDelete = "MESSAGE_DELETE",
-	MessageDeleteBulk = "MESSAGE_DELETE_BULK",
-	MessageReactionAdd = "MESSAGE_REACTION_ADD",
-	MessageReactionRemove = "MESSAGE_REACTION_REMOVE",
-	MessageReactionRemoveAll = "MESSAGE_REACTION_REMOVE_ALL",
-	MessageReactionRemoveEmoji = "MESSAGE_REACTION_REMOVE_EMOJI",
-	PresenceUpdate = "PRESENCE_UPDATE",
-	TypingStart = "TYPING_START",
-	UserUpdate = "USER_UPDATE",
-	WebhooksUpdate = "WEBHOOKS_UPDATE",
-	InteractionCreate = "INTERACTION_CREATE",
-	VoiceStateUpdate = "VOICE_STATE_UPDATE",
-	VoiceServerUpdate = "VOICE_SERVER_UPDATE",
-	ApplicationCommandCreate = "APPLICATION_COMMAND_CREATE",
-	ApplicationCommandUpdate = "APPLICATION_COMMAND_UPDATE",
-	ApplicationCommandDelete = "APPLICATION_COMMAND_DELETE",
-}
-
-export type EVENT =
-	| "READY"
-	| "CHANNEL_CREATE"
-	| "CHANNEL_UPDATE"
-	| "CHANNEL_DELETE"
-	| "CHANNEL_PINS_UPDATE"
-	| "GUILD_CREATE"
-	| "GUILD_UPDATE"
-	| "GUILD_DELETE"
-	| "GUILD_BAN_ADD"
-	| "GUILD_BAN_REMOVE"
-	| "GUILD_EMOJI_UPDATE"
-	| "GUILD_INTEGRATIONS_UPDATE"
-	| "GUILD_MEMBER_ADD"
-	| "GUILD_MEMBER_REMOVE"
-	| "GUILD_MEMBER_UPDATE"
-	| "GUILD_MEMBER_SPEAKING"
-	| "GUILD_MEMBERS_CHUNK"
-	| "GUILD_ROLE_CREATE"
-	| "GUILD_ROLE_DELETE"
-	| "GUILD_ROLE_UPDATE"
-	| "INVITE_CREATE"
-	| "INVITE_DELETE"
-	| "MESSAGE_CREATE"
-	| "MESSAGE_UPDATE"
-	| "MESSAGE_DELETE"
-	| "MESSAGE_DELETE_BULK"
-	| "MESSAGE_REACTION_ADD"
-	// TODO: add a new event: bulk add reaction:
-	// | "MESSAGE_REACTION_BULK_ADD"
-	| "MESSAGE_REACTION_REMOVE"
-	| "MESSAGE_REACTION_REMOVE_ALL"
-	| "MESSAGE_REACTION_REMOVE_EMOJI"
-	| "PRESENCE_UPDATE"
-	| "TYPING_START"
-	| "USER_UPDATE"
-	| "WEBHOOKS_UPDATE"
-	| "INTERACTION_CREATE"
-	| "VOICE_STATE_UPDATE"
-	| "VOICE_SERVER_UPDATE"
-	| "APPLICATION_COMMAND_CREATE"
-	| "APPLICATION_COMMAND_UPDATE"
-	| "APPLICATION_COMMAND_DELETE"
-	| "MESSAGE_ACK"
-	| "RELATIONSHIP_ADD"
-	| "RELATIONSHIP_REMOVE"
-	| CUSTOMEVENTS;
-
-export type CUSTOMEVENTS = "INVALIDATED";
diff --git a/rtc/src/models/Guild.ts b/rtc/src/models/Guild.ts
deleted file mode 100644
index 13a7d078..00000000
--- a/rtc/src/models/Guild.ts
+++ /dev/null
@@ -1,161 +0,0 @@
-import { Schema, model, Types, Document } from "mongoose";
-import db from "../util/Database";
-import { ChannelModel } from "./Channel";
-import { EmojiModel } from "./Emoji";
-import { MemberModel } from "./Member";
-import { RoleModel } from "./Role";
-
-export interface GuildDocument extends Document, Guild {
-	id: string;
-}
-
-export interface Guild {
-	id: string;
-	afk_channel_id?: string;
-	afk_timeout?: number;
-	application_id?: string;
-	banner?: string;
-	default_message_notifications?: number;
-	description?: string;
-	discovery_splash?: string;
-	explicit_content_filter?: number;
-	features: string[];
-	icon?: string;
-	large?: boolean;
-	max_members?: number; // e.g. default 100.000
-	max_presences?: number;
-	max_video_channel_users?: number; // ? default: 25, is this max 25 streaming or watching
-	member_count?: number;
-	presence_count?: number; // users online
-	// members?: Member[]; // * Members are stored in a seperate collection
-	// roles: Role[]; // * Role are stored in a seperate collection
-	// channels: GuildChannel[]; // * Channels are stored in a seperate collection
-	// emojis: Emoji[];  // * Emojis are stored in a seperate collection
-	// voice_states: []; // * voice_states are stored in a seperate collection
-    //TODO:
-	presences?: object[];
-	mfa_level?: number;
-	name: string;
-	owner_id: string;
-	preferred_locale?: string; // only community guilds can choose this
-	premium_subscription_count?: number;
-	premium_tier?: number; // nitro boost level
-	public_updates_channel_id?: string;
-	region?: string;
-	rules_channel_id?: string;
-	splash?: string;
-	system_channel_flags?: number;
-	system_channel_id?: string;
-	unavailable?: boolean;
-	vanity_url?: {
-		code: string;
-		uses: number;
-	};
-	verification_level?: number;
-	welcome_screen: {
-		enabled: boolean;
-		description: string;
-		welcome_channels: { 
-		description: string;
-	    emoji_id?: string;
-	    emoji_name: string;
-	    channel_id: string }[];
-	};
-	widget_channel_id?: string;
-	widget_enabled?: boolean;
-}
-
-export const GuildSchema = new Schema({
-	id: { type: String, required: true },
-	afk_channel_id: String,
-	afk_timeout: Number,
-	application_id: String,
-	banner: String,
-	default_message_notifications: Number,
-	description: String,
-	discovery_splash: String,
-	explicit_content_filter: Number,
-	features: { type: [String], default: [] },
-	icon: String,
-	large: Boolean,
-	max_members: { type: Number, default: 100000 },
-	max_presences: Number,
-	max_video_channel_users: { type: Number, default: 25 },
-	member_count: Number,
-	presences: { type: [Object], default: [] },
-	presence_count: Number,
-	mfa_level: Number,
-	name: { type: String, required: true },
-	owner_id: { type: String, required: true },
-	preferred_locale: String,
-	premium_subscription_count: Number,
-	premium_tier: Number,
-	public_updates_channel_id: String,
-	region: String,
-	rules_channel_id: String,
-	splash: String,
-	system_channel_flags: Number,
-	system_channel_id: String,
-	unavailable: Boolean,
-	vanity_url: {
-		code: String,
-		uses: Number
-	},
-	verification_level: Number,
-	voice_states: { type: [Object], default: [] },
-	welcome_screen: {
-		enabled: Boolean,
-		description: String,
-		welcome_channels: [{ 
-		description: String,
-	    emoji_id: String,
-	    emoji_name: String,
-	    channel_id: String }],
-	},
-	widget_channel_id: String,
-	widget_enabled: Boolean,
-});
-
-GuildSchema.virtual("channels", {
-	ref: ChannelModel,
-	localField: "id",
-	foreignField: "guild_id",
-	justOne: false,
-	autopopulate: true,
-});
-
-GuildSchema.virtual("roles", {
-	ref: RoleModel,
-	localField: "id",
-	foreignField: "guild_id",
-	justOne: false,
-	autopopulate: true,
-});
-
-// nested populate is needed for member users: https://gist.github.com/yangsu/5312204
-GuildSchema.virtual("members", {
-	ref: MemberModel,
-	localField: "id",
-	foreignField: "guild_id",
-	justOne: false,
-});
-
-GuildSchema.virtual("emojis", {
-	ref: EmojiModel,
-	localField: "id",
-	foreignField: "guild_id",
-	justOne: false,
-	autopopulate: true,
-});
-
-GuildSchema.virtual("joined_at", {
-	ref: MemberModel,
-	localField: "id",
-	foreignField: "guild_id",
-	justOne: true,
-}).get((member: any, virtual: any, doc: any) => {
-	return member?.joined_at;
-});
-
-// @ts-ignore
-export const GuildModel = db.model<GuildDocument>("Guild", GuildSchema, "guilds");
diff --git a/rtc/src/models/Interaction.ts b/rtc/src/models/Interaction.ts
deleted file mode 100644
index 764247a5..00000000
--- a/rtc/src/models/Interaction.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { AllowedMentions, Embed } from "./Message";
-
-export interface Interaction {
-	id: string;
-	type: InteractionType;
-	data?: {};
-	guild_id: string;
-	channel_id: string;
-	member_id: string;
-	token: string;
-	version: number;
-}
-
-export enum InteractionType {
-	Ping = 1,
-	ApplicationCommand = 2,
-}
-
-export enum InteractionResponseType {
-	Pong = 1,
-	Acknowledge = 2,
-	ChannelMessage = 3,
-	ChannelMessageWithSource = 4,
-	AcknowledgeWithSource = 5,
-}
-
-export interface InteractionApplicationCommandCallbackData {
-	tts?: boolean;
-	content: string;
-	embeds?: Embed[];
-	allowed_mentions?: AllowedMentions;
-}
diff --git a/rtc/src/models/Invite.ts b/rtc/src/models/Invite.ts
deleted file mode 100644
index 01f12003..00000000
--- a/rtc/src/models/Invite.ts
+++ /dev/null
@@ -1,95 +0,0 @@
-import { Schema, Document, Types } from "mongoose";
-import db from "../util/Database";
-import { ChannelModel } from "./Channel";
-import { PublicUserProjection, UserModel } from "./User";
-import { GuildModel } from "./Guild";
-
-export interface Invite {
-	code: string;
-	temporary: boolean;
-	uses: number;
-	max_uses: number;
-	max_age: number;
-	created_at: Date;
-	expires_at: Date;
-	guild_id: string;
-	channel_id: string;
-	inviter_id: string;
-
-	// ? What is this?
-	target_user_id?: string;
-	target_user_type?: number;
-}
-
-export interface InviteDocument extends Invite, Document {}
-
-export const InviteSchema = new Schema({
-	code: String,
-	temporary: Boolean,
-	uses: Number,
-	max_uses: Number,
-	max_age: Number,
-	created_at: Date,
-	expires_at: Date,
-	guild_id: String,
-	channel_id: String,
-	inviter_id: String,
-
-	// ? What is this?
-	target_user_id: String,
-	target_user_type: Number,
-});
-
-InviteSchema.virtual("channel", {
-	ref: ChannelModel,
-	localField: "channel_id",
-	foreignField: "id",
-	justOne: true,
-	autopopulate: {
-		select: {
-			id: true,
-			name: true,
-			type: true,
-		},
-	},
-});
-
-InviteSchema.virtual("inviter", {
-	ref: UserModel,
-	localField: "inviter_id",
-	foreignField: "id",
-	justOne: true,
-	autopopulate: {
-		select: PublicUserProjection,
-	},
-});
-
-InviteSchema.virtual("guild", {
-	ref: GuildModel,
-	localField: "guild_id",
-	foreignField: "id",
-	justOne: true,
-	autopopulate: {
-		select: {
-			id: true,
-			name: true,
-			splash: true,
-			banner: true,
-			description: true,
-			icon: true,
-			features: true,
-			verification_level: true,
-			vanity_url_code: true,
-			welcome_screen: true,
-			nsfw: true,
-
-			// TODO: hide the following entries:
-			// channels: false,
-			// roles: false,
-			// emojis: false,
-		},
-	},
-});
-
-// @ts-ignore
-export const InviteModel = db.model<InviteDocument>("Invite", InviteSchema, "invites");
diff --git a/rtc/src/models/Member.ts b/rtc/src/models/Member.ts
deleted file mode 100644
index d1c9ad9b..00000000
--- a/rtc/src/models/Member.ts
+++ /dev/null
@@ -1,109 +0,0 @@
-import { PublicUser, PublicUserProjection, User, UserModel } from "./User";
-import { Schema, Types, Document } from "mongoose";
-import db from "../util/Database";
-
-export const PublicMemberProjection = {
-	id: true,
-	guild_id: true,
-	nick: true,
-	roles: true,
-	joined_at: true,
-	pending: true,
-	deaf: true,
-	mute: true,
-	premium_since: true,
-};
-
-export interface Member {
-	id: string;
-	guild_id: string;
-	nick?: string;
-	roles: string[];
-	joined_at: Date;
-	premium_since?: number;
-	deaf: boolean;
-	mute: boolean;
-	pending: boolean;
-	settings: UserGuildSettings;
-	read_state: Record<string, string | null>;
-	// virtual
-	user?: User;
-}
-
-export interface MemberDocument extends Member, Document {
-	id: string;
-}
-
-export interface UserGuildSettings {
-	channel_overrides: {
-		channel_id: string;
-		message_notifications: number;
-		mute_config: MuteConfig;
-		muted: boolean;
-	}[];
-	message_notifications: number;
-	mobile_push: boolean;
-	mute_config: MuteConfig;
-	muted: boolean;
-	suppress_everyone: boolean;
-	suppress_roles: boolean;
-	version: number;
-}
-
-export interface MuteConfig {
-	end_time: number;
-	selected_time_window: number;
-}
-
-const MuteConfig = {
-	end_time: Number,
-	selected_time_window: Number,
-};
-
-export const MemberSchema = new Schema({
-	id: { type: String, required: true },
-	guild_id: String,
-	nick: String,
-	roles: [String],
-	joined_at: Date,
-	premium_since: Number,
-	deaf: Boolean,
-	mute: Boolean,
-	pending: Boolean,
-	read_state: Object,
-	settings: {
-		channel_overrides: [
-			{
-				channel_id: String,
-				message_notifications: Number,
-				mute_config: MuteConfig,
-				muted: Boolean,
-			},
-		],
-		message_notifications: Number,
-		mobile_push: Boolean,
-		mute_config: MuteConfig,
-		muted: Boolean,
-		suppress_everyone: Boolean,
-		suppress_roles: Boolean,
-		version: Number,
-	},
-});
-
-MemberSchema.virtual("user", {
-	ref: UserModel,
-	localField: "id",
-	foreignField: "id",
-	justOne: true,
-	autopopulate: {
-		select: PublicUserProjection,
-	},
-});
-
-// @ts-ignore
-export const MemberModel = db.model<MemberDocument>("Member", MemberSchema, "members");
-
-// @ts-ignore
-export interface PublicMember extends Omit<Member, "settings" | "id" | "read_state"> {
-	user: PublicUser;
-}
diff --git a/rtc/src/models/Message.ts b/rtc/src/models/Message.ts
deleted file mode 100644
index 15a6f40d..00000000
--- a/rtc/src/models/Message.ts
+++ /dev/null
@@ -1,368 +0,0 @@
-import { Schema, Types, Document } from "mongoose";
-import db from "../util/Database";
-import { PublicUser, PublicUserProjection, UserModel } from "./User";
-import { MemberModel, PublicMember } from "./Member";
-import { Role, RoleModel } from "./Role";
-import { Channel } from "./Channel";
-import { Snowflake } from "../util";
-import { InteractionType } from "./Interaction";
-
-export interface Message {
-	id: string;
-	channel_id: string;
-	guild_id?: string;
-	author_id?: string;
-	webhook_id?: string;
-	application_id?: string;
-	content?: string;
-	timestamp: Date;
-	edited_timestamp: Date | null;
-	tts?: boolean;
-	mention_everyone?: boolean;
-	mention_user_ids: string[];
-	mention_role_ids: string[];
-	mention_channels_ids: string[];
-	attachments: Attachment[];
-	embeds: Embed[];
-	reactions: Reaction[];
-	nonce?: string | number;
-	pinned?: boolean;
-	type: MessageType;
-	activity?: {
-		type: number;
-		party_id: string;
-	};
-	flags?: bigint;
-	stickers?: any[];
-	message_reference?: {
-		message_id: string;
-		channel_id?: string;
-		guild_id?: string;
-	};
-	interaction?: {
-		id: string;
-		type: InteractionType;
-		name: string;
-		user_id: string; // the user who invoked the interaction
-		// user: User; // TODO: autopopulate user
-	};
-	components: MessageComponent[];
-
-	// * mongoose virtuals:
-	// TODO:
-	// application: Application; // TODO: auto pouplate application
-	author?: PublicUser;
-	member?: PublicMember;
-	mentions?: (PublicUser & {
-		member: PublicMember;
-	})[];
-	mention_roles?: Role[];
-	mention_channels?: Channel[];
-	created_at?: Date;
-	// thread // TODO
-}
-
-const PartialEmoji = {
-	id: String,
-	name: { type: String, required: true },
-	animated: { type: Boolean, required: true },
-};
-
-const MessageComponent: any = {
-	type: { type: Number, required: true },
-	style: Number,
-	label: String,
-	emoji: PartialEmoji,
-	custom_id: String,
-	url: String,
-	disabled: Boolean,
-	components: [Object],
-};
-
-export interface MessageComponent {
-	type: number;
-	style?: number;
-	label?: string;
-	emoji?: PartialEmoji;
-	custom_id?: string;
-	url?: string;
-	disabled?: boolean;
-	components: MessageComponent[];
-}
-
-export enum MessageComponentType {
-	ActionRow = 1,
-	Button = 2,
-}
-
-export interface MessageDocument extends Document, Message {
-	id: string;
-}
-
-export enum MessageType {
-	DEFAULT = 0,
-	RECIPIENT_ADD = 1,
-	RECIPIENT_REMOVE = 2,
-	CALL = 3,
-	CHANNEL_NAME_CHANGE = 4,
-	CHANNEL_ICON_CHANGE = 5,
-	CHANNEL_PINNED_MESSAGE = 6,
-	GUILD_MEMBER_JOIN = 7,
-	USER_PREMIUM_GUILD_SUBSCRIPTION = 8,
-	USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_1 = 9,
-	USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_2 = 10,
-	USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_3 = 11,
-	CHANNEL_FOLLOW_ADD = 12,
-	GUILD_DISCOVERY_DISQUALIFIED = 14,
-	GUILD_DISCOVERY_REQUALIFIED = 15,
-	REPLY = 19,
-	APPLICATION_COMMAND = 20,
-}
-
-export interface Attachment {
-	id: string; // attachment id
-	filename: string; // name of file attached
-	size: number; // size of file in bytes
-	url: string; // source url of file
-	proxy_url: string; // a proxied url of file
-	height?: number; // height of file (if image)
-	width?: number; // width of file (if image)
-	content_type?: string;
-}
-
-export interface Embed {
-	title?: string; //title of embed
-	type?: EmbedType; // type of embed (always "rich" for webhook embeds)
-	description?: string; // description of embed
-	url?: string; // url of embed
-	timestamp?: Date; // timestamp of embed content
-	color?: number; // color code of the embed
-	footer?: {
-		text: string;
-		icon_url?: string;
-		proxy_icon_url?: string;
-	}; // footer object	footer information
-	image?: EmbedImage; // image object	image information
-	thumbnail?: EmbedImage; // thumbnail object	thumbnail information
-	video?: EmbedImage; // video object	video information
-	provider?: {
-		name?: string;
-		url?: string;
-	}; // provider object	provider information
-	author?: {
-		name?: string;
-		url?: string;
-		icon_url?: string;
-		proxy_icon_url?: string;
-	}; // author object	author information
-	fields?: {
-		name: string;
-		value: string;
-		inline?: boolean;
-	}[];
-}
-
-export enum EmbedType {
-	rich = "rich",
-	image = "image",
-	video = "video",
-	gifv = "gifv",
-	article = "article",
-	link = "link",
-}
-
-export interface EmbedImage {
-	url?: string;
-	proxy_url?: string;
-	height?: number;
-	width?: number;
-}
-
-export interface Reaction {
-	count: number;
-	//// not saved in the database // me: boolean; // whether the current user reacted using this emoji
-	emoji: PartialEmoji;
-	user_ids: string[];
-}
-
-export interface PartialEmoji {
-	id?: string;
-	name: string;
-	animated?: boolean;
-}
-
-export interface AllowedMentions {
-	parse?: ("users" | "roles" | "everyone")[];
-	roles?: string[];
-	users?: string[];
-	replied_user?: boolean;
-}
-
-export const Attachment = {
-	id: String, // attachment id
-	filename: String, // name of file attached
-	size: Number, // size of file in bytes
-	url: String, // source url of file
-	proxy_url: String, // a proxied url of file
-	height: Number, // height of file (if image)
-	width: Number, // width of file (if image)
-	content_type: String,
-};
-
-export const EmbedImage = {
-	url: String,
-	proxy_url: String,
-	height: Number,
-	width: Number,
-};
-
-const Reaction = {
-	count: Number,
-	user_ids: [String],
-	emoji: {
-		id: String,
-		name: String,
-		animated: Boolean,
-	},
-};
-
-export const Embed = {
-	title: String, //title of embed
-	type: { type: String }, // type of embed (always "rich" for webhook embeds)
-	description: String, // description of embed
-	url: String, // url of embed
-	timestamp: Date, // timestamp of embed content
-	color: Number, // color code of the embed
-	footer: {
-		text: String,
-		icon_url: String,
-		proxy_icon_url: String,
-	}, // footer object	footer information
-	image: EmbedImage, // image object	image information
-	thumbnail: EmbedImage, // thumbnail object	thumbnail information
-	video: EmbedImage, // video object	video information
-	provider: {
-		name: String,
-		url: String,
-	}, // provider object	provider information
-	author: {
-		name: String,
-		url: String,
-		icon_url: String,
-		proxy_icon_url: String,
-	}, // author object	author information
-	fields: [
-		{
-			name: String,
-			value: String,
-			inline: Boolean,
-		},
-	],
-};
-
-export const MessageSchema = new Schema({
-	id: String,
-	channel_id: String,
-	author_id: String,
-	webhook_id: String,
-	guild_id: String,
-	application_id: String,
-	content: String,
-	timestamp: Date,
-	edited_timestamp: Date,
-	tts: Boolean,
-	mention_everyone: Boolean,
-	mention_user_ids: [String],
-	mention_role_ids: [String],
-	mention_channel_ids: [String],
-	attachments: [Attachment],
-	embeds: [Embed],
-	reactions: [Reaction],
-	nonce: Schema.Types.Mixed, // can be a long or a string
-	pinned: Boolean,
-	type: { type: Number },
-	activity: {
-		type: { type: Number },
-		party_id: String,
-	},
-	flags: Types.Long,
-	stickers: [],
-	message_reference: {
-		message_id: String,
-		channel_id: String,
-		guild_id: String,
-	},
-	components: [MessageComponent],
-	// virtual:
-	// author: {
-	// 	ref: UserModel,
-	// 	localField: "author_id",
-	// 	foreignField: "id",
-	// 	justOne: true,
-	// 	autopopulate: { select: { id: true, user_data: false } },
-	// },
-});
-
-MessageSchema.virtual("author", {
-	ref: UserModel,
-	localField: "author_id",
-	foreignField: "id",
-	justOne: true,
-	autopopulate: { select: PublicUserProjection },
-});
-
-MessageSchema.virtual("member", {
-	ref: MemberModel,
-	localField: "author_id",
-	foreignField: "id",
-	justOne: true,
-});
-
-MessageSchema.virtual("mentions", {
-	ref: UserModel,
-	localField: "mention_user_ids",
-	foreignField: "id",
-	justOne: false,
-	autopopulate: { select: PublicUserProjection },
-});
-
-MessageSchema.virtual("mention_roles", {
-	ref: RoleModel,
-	localField: "mention_role_ids",
-	foreignField: "id",
-	justOne: false,
-	autopopulate: true,
-});
-
-MessageSchema.virtual("mention_channels", {
-	ref: RoleModel,
-	localField: "mention_channel_ids",
-	foreignField: "id",
-	justOne: false,
-	autopopulate: { select: { id: true, guild_id: true, type: true, name: true } },
-});
-
-MessageSchema.virtual("referenced_message", {
-	ref: "Message",
-	localField: "message_reference.message_id",
-	foreignField: "id",
-	justOne: true,
-	autopopulate: true,
-});
-
-MessageSchema.virtual("created_at").get(function (this: MessageDocument) {
-	return new Date(Snowflake.deconstruct(this.id).timestamp);
-});
-
-MessageSchema.set("removeResponse", ["mention_channel_ids", "mention_role_ids", "mention_user_ids", "author_id"]);
-
-// TODO: missing Application Model
-// MessageSchema.virtual("application", {
-// 	ref: Application,
-// 	localField: "mention_role_ids",
-// 	foreignField: "id",
-// 	justOne: true,
-// });
-
-// @ts-ignore
-export const MessageModel = db.model<MessageDocument>("Message", MessageSchema, "messages");
diff --git a/rtc/src/models/RateLimit.ts b/rtc/src/models/RateLimit.ts
deleted file mode 100644
index 6a0e1ffd..00000000
--- a/rtc/src/models/RateLimit.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { Schema, Document, Types } from "mongoose";
-import db from "../util/Database";
-
-export interface Bucket {
-	id: "global" | "error" | string; // channel_239842397 | guild_238927349823 | webhook_238923423498
-	user_id: string;
-	hits: number;
-	blocked: boolean;
-	expires_at: Date;
-}
-
-export interface BucketDocument extends Bucket, Document {
-	id: string;
-}
-
-export const BucketSchema = new Schema({
-	id: { type: String, required: true },
-	user_id: { type: String, required: true }, // bot, user, oauth_application, webhook
-	hits: { type: Number, required: true }, // Number of times the user hit this bucket
-	blocked: { type: Boolean, required: true },
-	expires_at: { type: Date, required: true },
-});
-
-// @ts-ignore
-export const BucketModel = db.model<BucketDocument>("Bucket", BucketSchema, "ratelimits");
diff --git a/rtc/src/models/ReadState.ts b/rtc/src/models/ReadState.ts
deleted file mode 100644
index 9c4fb323..00000000
--- a/rtc/src/models/ReadState.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import { PublicMember } from "./Member";
-import { Schema, model, Types, Document } from "mongoose";
-import db from "../util/Database";
-
-export interface ReadState extends Document {
-	message_id: string;
-	channel_id: string;
-	user_id: string;
-	last_message_id?: string;
-	last_pin_timestamp?: Date;
-	mention_count: number;
-	manual: boolean;
-}
-
-export const ReadStateSchema = new Schema({
-	message_id: String,
-	channel_id: String,
-	user_id: String,
-	last_message_id: String,
-	last_pin_timestamp: Date,
-	mention_count: Number,
-	manual: Boolean,
-});
-
-// @ts-ignore
-export const ReadStateModel = db.model<ReadState>("ReadState", ReadStateSchema, "readstates");
diff --git a/rtc/src/models/Role.ts b/rtc/src/models/Role.ts
deleted file mode 100644
index c1111c84..00000000
--- a/rtc/src/models/Role.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { Schema, model, Types, Document } from "mongoose";
-import db from "../util/Database";
-import toBigInt from "../util/toBigInt";
-
-export interface Role {
-	id: string;
-	guild_id: string;
-	color: number;
-	hoist: boolean;
-	managed: boolean;
-	mentionable: boolean;
-	name: string;
-	permissions: bigint;
-	position: number;
-	tags?: {
-		bot_id?: string;
-	};
-}
-
-export interface RoleDocument extends Document, Role {
-	id: string;
-}
-
-export const RoleSchema = new Schema({
-	id: String,
-	guild_id: String,
-	color: Number,
-	hoist: Boolean,
-	managed: Boolean,
-	mentionable: Boolean,
-	name: String,
-	permissions: { type: String, get: toBigInt },
-	position: Number,
-	tags: {
-		bot_id: String,
-	},
-});
-
-RoleSchema.set("removeResponse", ["guild_id"]);
-
-// @ts-ignore
-export const RoleModel = db.model<RoleDocument>("Role", RoleSchema, "roles");
diff --git a/rtc/src/models/Status.ts b/rtc/src/models/Status.ts
deleted file mode 100644
index 5a9bf2ca..00000000
--- a/rtc/src/models/Status.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-export type Status = "idle" | "dnd" | "online" | "offline";
-
-export interface ClientStatus {
-	desktop?: string; // e.g. Windows/Linux/Mac
-	mobile?: string; // e.g. iOS/Android
-	web?: string; // e.g. browser, bot account
-}
-
-export const ClientStatus = {
-	desktop: String,
-	mobile: String,
-	web: String,
-};
diff --git a/rtc/src/models/Team.ts b/rtc/src/models/Team.ts
deleted file mode 100644
index 795c82d2..00000000
--- a/rtc/src/models/Team.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-export interface Team {
-	icon: string | null;
-	id: string;
-	members: {
-		membership_state: number;
-		permissions: string[];
-		team_id: string;
-		user_id: string;
-	}[];
-	name: string;
-	owner_user_id: string;
-}
-
-export enum TeamMemberState {
-	INVITED = 1,
-	ACCEPTED = 2,
-}
diff --git a/rtc/src/models/Template.ts b/rtc/src/models/Template.ts
deleted file mode 100644
index ad0f9104..00000000
--- a/rtc/src/models/Template.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import { Schema, model, Types, Document } from "mongoose";
-import db from "../util/Database";
-import { PublicUser, User, UserModel, PublicUserProjection } from "./User";
-import { Guild, GuildModel } from "./Guild";
-
-export interface Template extends Document {
-	id: string;
-	code: string;
-	name: string;
-	description?: string;
-	usage_count?: number;
-	creator_id: string;
-	creator: User;
-	created_at: Date;
-	updated_at: Date;
-	source_guild_id: String;
-	serialized_source_guild: Guild;
-}
-
-export const TemplateSchema = new Schema({
-	id: String,
-	code: String,
-	name: String,
-	description: String,
-	usage_count: Number,
-	creator_id: String,
-	created_at: Date,
-	updated_at: Date,
-	source_guild_id: String,
-});
-
-TemplateSchema.virtual("creator", {
-	ref: UserModel,
-	localField: "creator_id",
-	foreignField: "id",
-	justOne: true,
-	autopopulate: {
-		select: PublicUserProjection,
-	},
-});
-
-TemplateSchema.virtual("serialized_source_guild", {
-	ref: GuildModel,
-	localField: "source_guild_id",
-	foreignField: "id",
-	justOne: true,
-	autopopulate: true,
-});
-
-// @ts-ignore
-export const TemplateModel = db.model<Template>("Template", TemplateSchema, "templates");
diff --git a/rtc/src/models/User.ts b/rtc/src/models/User.ts
deleted file mode 100644
index c667e954..00000000
--- a/rtc/src/models/User.ts
+++ /dev/null
@@ -1,252 +0,0 @@
-import { Activity, ActivitySchema } from "./Activity";
-import { ClientStatus, Status } from "./Status";
-import { Schema, Types, Document } from "mongoose";
-import db from "../util/Database";
-import toBigInt from "../util/toBigInt";
-
-export const PublicUserProjection = {
-	username: true,
-	discriminator: true,
-	id: true,
-	public_flags: true,
-	avatar: true,
-	accent_color: true,
-	banner: true,
-	bio: true,
-	bot: true,
-};
-
-export interface User {
-	id: string;
-	username: string; // username max length 32, min 2
-	discriminator: string; // #0001 4 digit long string from #0001 - #9999
-	avatar: string | null; // hash of the user avatar
-	accent_color: number | null; // banner color of user
-	banner: string | null;
-	phone: string | null; // phone number of the user
-	desktop: boolean; // if the user has desktop app installed
-	mobile: boolean; // if the user has mobile app installed
-	premium: boolean; // if user bought nitro
-	premium_type: number; // nitro level
-	bot: boolean; // if user is bot
-	bio: string; // short description of the user (max 190 chars)
-	system: boolean; // shouldn't be used, the api sents this field type true, if the genetaed message comes from a system generated author
-	nsfw_allowed: boolean; // if the user is older than 18 (resp. Config)
-	mfa_enabled: boolean; // if multi factor authentication is enabled
-	created_at: Date; // registration date
-	verified: boolean; // if the user is offically verified
-	disabled: boolean; // if the account is disabled
-	deleted: boolean; // if the user was deleted
-	email: string | null; // email of the user
-	flags: bigint; // UserFlags
-	public_flags: bigint;
-	user_settings: UserSettings;
-	guilds: string[]; // array of guild ids the user is part of
-	user_data: UserData;
-	presence: {
-		status: Status;
-		activities: Activity[];
-		client_status: ClientStatus;
-	};
-}
-
-// Private user data:
-export interface UserData {
-	valid_tokens_since: Date; // all tokens with a previous issue date are invalid
-	relationships: Relationship[];
-	connected_accounts: ConnectedAccount[];
-	hash: string; // hash of the password, salt is saved in password (bcrypt)
-	fingerprints: string[]; // array of fingerprints -> used to prevent multiple accounts
-}
-
-export interface UserDocument extends User, Document {
-	id: string;
-}
-
-export interface PublicUser {
-	id: string;
-	discriminator: string;
-	username: string;
-	avatar: string | null;
-	accent_color: number;
-	banner: string | null;
-	public_flags: bigint;
-	bot: boolean;
-}
-
-export interface ConnectedAccount {
-	access_token: string;
-	friend_sync: boolean;
-	id: string;
-	name: string;
-	revoked: boolean;
-	show_activity: boolean;
-	type: string;
-	verifie: boolean;
-	visibility: number;
-}
-
-export interface Relationship {
-	id: string;
-	nickname?: string;
-	type: RelationshipType;
-}
-
-export enum RelationshipType {
-	outgoing = 4,
-	incoming = 3,
-	blocked = 2,
-	friends = 1,
-}
-
-export interface UserSettings {
-	afk_timeout: number;
-	allow_accessibility_detection: boolean;
-	animate_emoji: boolean;
-	animate_stickers: number;
-	contact_sync_enabled: boolean;
-	convert_emoticons: boolean;
-	custom_status: {
-		emoji_id: string | null;
-		emoji_name: string | null;
-		expires_at: number | null;
-		text: string | null;
-	};
-	default_guilds_restricted: boolean;
-	detect_platform_accounts: boolean;
-	developer_mode: boolean;
-	disable_games_tab: boolean;
-	enable_tts_command: boolean;
-	explicit_content_filter: number;
-	friend_source_flags: { all: boolean };
-	gateway_connected: boolean;
-	gif_auto_play: boolean;
-	guild_folders: // every top guild is displayed as a "folder"
-	{
-		color: number;
-		guild_ids: string[];
-		id: number;
-		name: string;
-	}[];
-	guild_positions: string[]; // guild ids ordered by position
-	inline_attachment_media: boolean;
-	inline_embed_media: boolean;
-	locale: string; // en_US
-	message_display_compact: boolean;
-	native_phone_integration_enabled: boolean;
-	render_embeds: boolean;
-	render_reactions: boolean;
-	restricted_guilds: string[];
-	show_current_game: boolean;
-	status: "online" | "offline" | "dnd" | "idle";
-	stream_notifications_enabled: boolean;
-	theme: "dark" | "white"; // dark
-	timezone_offset: number; // e.g -60
-}
-
-export const UserSchema = new Schema({
-	id: String,
-	username: String,
-	discriminator: String,
-	avatar: String,
-	accent_color: Number,
-	banner: String,
-	phone: String,
-	desktop: Boolean,
-	mobile: Boolean,
-	premium: Boolean,
-	premium_type: Number,
-	bot: Boolean,
-	bio: String,
-	system: Boolean,
-	nsfw_allowed: Boolean,
-	mfa_enabled: Boolean,
-	created_at: Date,
-	verified: Boolean,
-	disabled: Boolean,
-	deleted: Boolean,
-	email: String,
-	flags: { type: String, get: toBigInt }, // TODO: automatically convert Types.Long to BitField of UserFlags
-	public_flags: { type: String, get: toBigInt },
-	guilds: [String], // array of guild ids the user is part of
-	user_data: {
-		fingerprints: [String],
-		hash: String, // hash of the password, salt is saved in password (bcrypt)
-		valid_tokens_since: Date, // all tokens with a previous issue date are invalid
-		relationships: [
-			{
-				id: { type: String, required: true },
-				nickname: String,
-				type: { type: Number },
-			},
-		],
-		connected_accounts: [
-			{
-				access_token: String,
-				friend_sync: Boolean,
-				id: String,
-				name: String,
-				revoked: Boolean,
-				show_activity: Boolean,
-				type: { type: String },
-				verifie: Boolean,
-				visibility: Number,
-			},
-		],
-	},
-	user_settings: {
-		afk_timeout: Number,
-		allow_accessibility_detection: Boolean,
-		animate_emoji: Boolean,
-		animate_stickers: Number,
-		contact_sync_enabled: Boolean,
-		convert_emoticons: Boolean,
-		custom_status: {
-			emoji_id: String,
-			emoji_name: String,
-			expires_at: Number,
-			text: String,
-		},
-		default_guilds_restricted: Boolean,
-		detect_platform_accounts: Boolean,
-		developer_mode: Boolean,
-		disable_games_tab: Boolean,
-		enable_tts_command: Boolean,
-		explicit_content_filter: Number,
-		friend_source_flags: { all: Boolean },
-		gateway_connected: Boolean,
-		gif_auto_play: Boolean,
-		// every top guild is displayed as a "folder"
-		guild_folders: [
-			{
-				color: Number,
-				guild_ids: [String],
-				id: Number,
-				name: String,
-			},
-		],
-		guild_positions: [String], // guild ids ordered by position
-		inline_attachment_media: Boolean,
-		inline_embed_media: Boolean,
-		locale: String, // en_US
-		message_display_compact: Boolean,
-		native_phone_integration_enabled: Boolean,
-		render_embeds: Boolean,
-		render_reactions: Boolean,
-		restricted_guilds: [String],
-		show_current_game: Boolean,
-		status: String,
-		stream_notifications_enabled: Boolean,
-		theme: String, // dark
-		timezone_offset: Number, // e.g -60,
-	},
-
-	presence: {
-		status: String,
-		activities: [ActivitySchema],
-		client_status: ClientStatus,
-	},
-});
-
-// @ts-ignore
-export const UserModel = db.model<UserDocument>("User", UserSchema, "users");
diff --git a/rtc/src/models/VoiceState.ts b/rtc/src/models/VoiceState.ts
deleted file mode 100644
index c1f90edd..00000000
--- a/rtc/src/models/VoiceState.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import { PublicMember } from "./Member";
-import { Schema, model, Types, Document } from "mongoose";
-import db from "../util/Database";
-
-export interface VoiceState extends Document {
-	guild_id?: string;
-	channel_id: string;
-	user_id: string;
-	session_id: string;
-	deaf: boolean;
-	mute: boolean;
-	self_deaf: boolean;
-	self_mute: boolean;
-	self_stream?: boolean;
-	self_video: boolean;
-	suppress: boolean; // whether this user is muted by the current user
-}
-
-export const VoiceSateSchema = new Schema({
-	guild_id: String,
-	channel_id: String,
-	user_id: String,
-	session_id: String,
-	deaf: Boolean,
-	mute: Boolean,
-	self_deaf: Boolean,
-	self_mute: Boolean,
-	self_stream: Boolean,
-	self_video: Boolean,
-	suppress: Boolean, // whether this user is muted by the current user
-});
-
-// @ts-ignore
-export const VoiceStateModel = db.model<VoiceState>("VoiceState", VoiceSateSchema, "voicestates");
diff --git a/rtc/src/models/Webhook.ts b/rtc/src/models/Webhook.ts
deleted file mode 100644
index 7379e98f..00000000
--- a/rtc/src/models/Webhook.ts
+++ /dev/null
@@ -1,84 +0,0 @@
-import { Schema, Document, Types } from "mongoose";
-import { transpileModule } from "typescript";
-import db from "../util/Database";
-import { ChannelModel } from "./Channel";
-import { GuildModel } from "./Guild";
-
-export interface Webhook {}
-
-export enum WebhookType {
-	Incoming = 1,
-	ChannelFollower = 2,
-}
-
-export interface WebhookDocument extends Document, Webhook {
-	id: String;
-	type: number;
-	guild_id?: string;
-	channel_id: string;
-	name?: string;
-	avatar?: string;
-	token?: string;
-	application_id?: string;
-	user_id?: string;
-	source_guild_id: string;
-}
-
-export const WebhookSchema = new Schema({
-	id: { type: String, required: true },
-	type: { type: Number, required: true },
-	guild_id: String,
-	channel_id: String,
-	name: String,
-	avatar: String,
-	token: String,
-	application_id: String,
-	user_id: String,
-	source_guild_id: String,
-	source_channel_id: String,
-});
-
-WebhookSchema.virtual("source_guild", {
-	ref: GuildModel,
-	localField: "id",
-	foreignField: "source_guild_id",
-	justOne: true,
-	autopopulate: {
-		select: {
-			icon: true,
-			id: true,
-			name: true,
-		},
-	},
-});
-
-WebhookSchema.virtual("source_channel", {
-	ref: ChannelModel,
-	localField: "id",
-	foreignField: "source_channel_id",
-	justOne: true,
-	autopopulate: {
-		select: {
-			id: true,
-			name: true,
-		},
-	},
-});
-
-WebhookSchema.virtual("source_channel", {
-	ref: ChannelModel,
-	localField: "id",
-	foreignField: "source_channel_id",
-	justOne: true,
-	autopopulate: {
-		select: {
-			id: true,
-			name: true,
-		},
-	},
-});
-
-WebhookSchema.set("removeResponse", ["source_channel_id", "source_guild_id"]);
-
-// @ts-ignore
-export const WebhookModel = db.model<WebhookDocument>("Webhook", WebhookSchema, "webhooks");
diff --git a/rtc/src/models/index.ts b/rtc/src/models/index.ts
deleted file mode 100644
index d0a46bf9..00000000
--- a/rtc/src/models/index.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-import mongoose, { Schema, Document } from "mongoose";
-import mongooseAutoPopulate from "mongoose-autopopulate";
-
-type UpdateWithAggregationPipeline = UpdateAggregationStage[];
-type UpdateAggregationStage =
-	| { $addFields: any }
-	| { $set: any }
-	| { $project: any }
-	| { $unset: any }
-	| { $replaceRoot: any }
-	| { $replaceWith: any };
-type EnforceDocument<T, TMethods> = T extends Document ? T : T & Document & TMethods;
-
-declare module "mongoose" {
-	interface Model<T, TQueryHelpers = {}, TMethods = {}> {
-		// removed null -> always return document -> throw error if it doesn't exist
-		findOne(
-			filter?: FilterQuery<T>,
-			projection?: any | null,
-			options?: QueryOptions | null,
-			callback?: (err: CallbackError, doc: EnforceDocument<T, TMethods>) => void
-		): QueryWithHelpers<EnforceDocument<T, TMethods>, EnforceDocument<T, TMethods>, TQueryHelpers>;
-		findOneAndUpdate(
-			filter?: FilterQuery<T>,
-			update?: UpdateQuery<T> | UpdateWithAggregationPipeline,
-			options?: QueryOptions | null,
-			callback?: (err: any, doc: EnforceDocument<T, TMethods> | null, res: any) => void
-		): QueryWithHelpers<EnforceDocument<T, TMethods>, EnforceDocument<T, TMethods>, TQueryHelpers>;
-	}
-}
-
-var HTTPError: any;
-
-try {
-	HTTPError = require("lambert-server").HTTPError;
-} catch (e) {
-	HTTPError = Error;
-}
-
-mongoose.plugin(mongooseAutoPopulate);
-
-mongoose.plugin((schema: Schema, opts: any) => {
-	schema.set("toObject", {
-		virtuals: true,
-		versionKey: false,
-		transform(doc: any, ret: any) {
-			delete ret._id;
-			delete ret.__v;
-			const props = schema.get("removeResponse") || [];
-			props.forEach((prop: string) => {
-				delete ret[prop];
-			});
-		},
-	});
-	schema.post("findOne", function (doc, next) {
-		try {
-			// @ts-ignore
-			const isExistsQuery = JSON.stringify(this._userProvidedFields) === JSON.stringify({ _id: 1 });
-			if (!doc && !isExistsQuery) {
-				// @ts-ignore
-				return next(new HTTPError(`${this?.mongooseCollection?.name}.${this?._conditions?.id} not found`, 400));
-			}
-			// @ts-ignore
-			return next();
-		} catch (error) {
-			// @ts-ignore
-			next();
-		}
-	});
-});
-
-export * from "./Activity";
-export * from "./Application";
-export * from "./Ban";
-export * from "./Channel";
-export * from "./Emoji";
-export * from "./Event";
-export * from "./Template";
-export * from "./Guild";
-export * from "./Invite";
-export * from "./Interaction";
-export * from "./Member";
-export * from "./Message";
-export * from "./Status";
-export * from "./Role";
-export * from "./User";
-export * from "./VoiceState";
-export * from "./ReadState";
-export * from "./RateLimit";
diff --git a/rtc/src/util/BitField.ts b/rtc/src/util/BitField.ts
deleted file mode 100644
index 728dc632..00000000
--- a/rtc/src/util/BitField.ts
+++ /dev/null
@@ -1,143 +0,0 @@
-"use strict";
-
-// https://github.com/discordjs/discord.js/blob/master/src/util/BitField.js
-// Apache License Version 2.0 Copyright 2015 - 2021 Amish Shah
-
-export type BitFieldResolvable = number | BigInt | BitField | string | BitFieldResolvable[];
-
-/**
- * Data structure that makes it easy to interact with a bitfield.
- */
-export class BitField {
-	public bitfield: bigint = BigInt(0);
-
-	public static FLAGS: Record<string, bigint> = {};
-
-	constructor(bits: BitFieldResolvable = 0) {
-		this.bitfield = BitField.resolve.call(this, bits);
-	}
-
-	/**
-	 * Checks whether the bitfield has a bit, or any of multiple bits.
-	 */
-	any(bit: BitFieldResolvable): boolean {
-		return (this.bitfield & BitField.resolve.call(this, bit)) !== 0n;
-	}
-
-	/**
-	 * Checks if this bitfield equals another
-	 */
-	equals(bit: BitFieldResolvable): boolean {
-		return this.bitfield === BitField.resolve.call(this, bit);
-	}
-
-	/**
-	 * Checks whether the bitfield has a bit, or multiple bits.
-	 */
-	has(bit: BitFieldResolvable): boolean {
-		if (Array.isArray(bit)) return bit.every((p) => this.has(p));
-		const BIT = BitField.resolve.call(this, bit);
-		return (this.bitfield & BIT) === BIT;
-	}
-
-	/**
-	 * Gets all given bits that are missing from the bitfield.
-	 */
-	missing(bits: BitFieldResolvable) {
-		if (!Array.isArray(bits)) bits = new BitField(bits).toArray();
-		return bits.filter((p) => !this.has(p));
-	}
-
-	/**
-	 * Freezes these bits, making them immutable.
-	 */
-	freeze(): Readonly<BitField> {
-		return Object.freeze(this);
-	}
-
-	/**
-	 * Adds bits to these ones.
-	 * @param {...BitFieldResolvable} [bits] Bits to add
-	 * @returns {BitField} These bits or new BitField if the instance is frozen.
-	 */
-	add(...bits: BitFieldResolvable[]): BitField {
-		let total = 0n;
-		for (const bit of bits) {
-			total |= BitField.resolve.call(this, bit);
-		}
-		if (Object.isFrozen(this)) return new BitField(this.bitfield | total);
-		this.bitfield |= total;
-		return this;
-	}
-
-	/**
-	 * Removes bits from these.
-	 * @param {...BitFieldResolvable} [bits] Bits to remove
-	 */
-	remove(...bits: BitFieldResolvable[]) {
-		let total = 0n;
-		for (const bit of bits) {
-			total |= BitField.resolve.call(this, bit);
-		}
-		if (Object.isFrozen(this)) return new BitField(this.bitfield & ~total);
-		this.bitfield &= ~total;
-		return this;
-	}
-
-	/**
-	 * Gets an object mapping field names to a {@link boolean} indicating whether the
-	 * bit is available.
-	 * @param {...*} hasParams Additional parameters for the has method, if any
-	 */
-	serialize() {
-		const serialized: Record<string, boolean> = {};
-		for (const [flag, bit] of Object.entries(BitField.FLAGS)) serialized[flag] = this.has(bit);
-		return serialized;
-	}
-
-	/**
-	 * Gets an {@link Array} of bitfield names based on the bits available.
-	 */
-	toArray(): string[] {
-		return Object.keys(BitField.FLAGS).filter((bit) => this.has(bit));
-	}
-
-	toJSON() {
-		return this.bitfield;
-	}
-
-	valueOf() {
-		return this.bitfield;
-	}
-
-	*[Symbol.iterator]() {
-		yield* this.toArray();
-	}
-
-	/**
-	 * Data that can be resolved to give a bitfield. This can be:
-	 * * A bit number (this can be a number literal or a value taken from {@link BitField.FLAGS})
-	 * * An instance of BitField
-	 * * An Array of BitFieldResolvable
-	 * @typedef {number|BitField|BitFieldResolvable[]} BitFieldResolvable
-	 */
-
-	/**
-	 * Resolves bitfields to their numeric form.
-	 * @param {BitFieldResolvable} [bit=0] - bit(s) to resolve
-	 * @returns {number}
-	 */
-	static resolve(bit: BitFieldResolvable = 0n): bigint {
-		// @ts-ignore
-		const FLAGS = this.FLAGS || this.constructor?.FLAGS;
-		if ((typeof bit === "number" || typeof bit === "bigint") && bit >= 0n) return BigInt(bit);
-		if (bit instanceof BitField) return bit.bitfield;
-		if (Array.isArray(bit)) {
-			// @ts-ignore
-			const resolve = this.constructor?.resolve || this.resolve;
-			return bit.map((p) => resolve.call(this, p)).reduce((prev, p) => BigInt(prev) | BigInt(p), 0n);
-		}
-		if (typeof bit === "string" && typeof FLAGS[bit] !== "undefined") return FLAGS[bit];
-		throw new RangeError("BITFIELD_INVALID: " + bit);
-	}
-}
diff --git a/rtc/src/util/Config.ts b/rtc/src/util/Config.ts
deleted file mode 100644
index 78b44315..00000000
--- a/rtc/src/util/Config.ts
+++ /dev/null
@@ -1,284 +0,0 @@
-import { Schema, model, Types, Document } from "mongoose";
-import "missing-native-js-functions";
-import db, { MongooseCache } from "./Database";
-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").findOne({});
-		return this.set((config || {}).merge(defaultOpts));
-	},
-	get: function get() {
-		return config as DefaultOptions;
-	},
-	set: function set(val: any) {
-		return db.collection("config").updateOne({}, { $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: {
-		endpoint: string | null;
-	};
-	cdn: {
-		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: {
-		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: {
-		endpoint: null,
-	},
-	cdn: {
-		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: 5,
-				},
-				channel: {
-					count: 5,
-					window: 5,
-				},
-				auth: {
-					login: {
-						count: 5,
-						window: 60,
-					},
-					register: {
-						count: 2,
-						window: 60 * 60 * 12,
-					},
-				},
-			},
-		},
-	},
-	security: {
-		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");
diff --git a/rtc/src/util/Constants.ts b/rtc/src/util/Constants.ts
deleted file mode 100644
index a9978c51..00000000
--- a/rtc/src/util/Constants.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { VerifyOptions } from "jsonwebtoken";
-
-export const JWTOptions: VerifyOptions = { algorithms: ["HS256"] };
-
-export enum MessageType {
-	DEFAULT = 0,
-	RECIPIENT_ADD = 1,
-	RECIPIENT_REMOVE = 2,
-	CALL = 3,
-	CHANNEL_NAME_CHANGE = 4,
-	CHANNEL_ICON_CHANGE = 5,
-	CHANNEL_PINNED_MESSAGE = 6,
-	GUILD_MEMBER_JOIN = 7,
-	USER_PREMIUM_GUILD_SUBSCRIPTION = 8,
-	USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_1 = 9,
-	USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_2 = 10,
-	USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_3 = 11,
-	CHANNEL_FOLLOW_ADD = 12,
-	GUILD_DISCOVERY_DISQUALIFIED = 14,
-	GUILD_DISCOVERY_REQUALIFIED = 15,
-	GUILD_DISCOVERY_GRACE_PERIOD_INITIAL_WARNING = 16,
-	GUILD_DISCOVERY_GRACE_PERIOD_FINAL_WARNING = 17,
-	THREAD_CREATED = 18,
-	REPLY = 19,
-	APPLICATION_COMMAND = 20,
-	THREAD_STARTER_MESSAGE = 21,
-	GUILD_INVITE_REMINDER = 22,
-}
diff --git a/rtc/src/util/Database.ts b/rtc/src/util/Database.ts
deleted file mode 100644
index 8c6847a8..00000000
--- a/rtc/src/util/Database.ts
+++ /dev/null
@@ -1,151 +0,0 @@
-import "./MongoBigInt";
-import mongoose, { Collection, Connection, LeanDocument } from "mongoose";
-import { ChangeStream, ChangeEvent, Long } from "mongodb";
-import EventEmitter from "events";
-const uri = process.env.MONGO_URL || "mongodb://localhost:27017/fosscord?readPreference=secondaryPreferred";
-import { URL } from "url";
-
-const url = new URL(uri.replace("mongodb://", "http://"));
-
-const connection = mongoose.createConnection(uri, {
-	autoIndex: true,
-	useNewUrlParser: true,
-	useUnifiedTopology: true,
-	useFindAndModify: false,
-});
-console.log(`[Database] connect: mongodb://${url.username}@${url.host}${url.pathname}${url.search}`);
-
-export default <Connection>connection;
-
-function transform<T>(document: T) {
-	// @ts-ignore
-	if (!document || !document.toObject) {
-		try {
-			// @ts-ignore
-			delete document._id;
-			// @ts-ignore
-			delete document.__v;
-		} catch (error) {}
-		return document;
-	}
-	// @ts-ignore
-	return document.toObject({ virtuals: true });
-}
-
-export function toObject<T>(document: T): LeanDocument<T> {
-	// @ts-ignore
-	return Array.isArray(document) ? document.map((x) => transform<T>(x)) : transform(document);
-}
-
-export interface MongooseCache {
-	on(event: "delete", listener: (id: string) => void): this;
-	on(event: "change", listener: (data: any) => void): this;
-	on(event: "insert", listener: (data: any) => void): this;
-	on(event: "close", listener: () => void): this;
-}
-
-export class MongooseCache extends EventEmitter {
-	public stream: ChangeStream;
-	public data: any;
-	public initalizing?: Promise<void>;
-
-	constructor(
-		public collection: Collection,
-		public pipeline: Array<Record<string, unknown>>,
-		public opts: {
-			onlyEvents: boolean;
-			array?: boolean;
-		}
-	) {
-		super();
-		if (this.opts.array == null) this.opts.array = true;
-	}
-
-	init = () => {
-		if (this.initalizing) return this.initalizing;
-		this.initalizing = new Promise(async (resolve, reject) => {
-			// @ts-ignore
-			this.stream = this.collection.watch(this.pipeline, { fullDocument: "updateLookup" });
-
-			this.stream.on("change", this.change);
-			this.stream.on("close", this.destroy);
-			this.stream.on("error", console.error);
-
-			if (!this.opts.onlyEvents) {
-				const arr = await this.collection.aggregate(this.pipeline).toArray();
-				if (this.opts.array) this.data = arr || [];
-				else this.data = arr?.[0];
-			}
-			resolve();
-		});
-		return this.initalizing;
-	};
-
-	changeStream = (pipeline: any) => {
-		this.pipeline = pipeline;
-		this.destroy();
-		this.init();
-	};
-
-	convertResult = (obj: any) => {
-		if (obj instanceof Long) return BigInt(obj.toString());
-		if (typeof obj === "object") {
-			Object.keys(obj).forEach((key) => {
-				obj[key] = this.convertResult(obj[key]);
-			});
-		}
-
-		return obj;
-	};
-
-	change = (doc: ChangeEvent) => {
-		try {
-			switch (doc.operationType) {
-				case "dropDatabase":
-					return this.destroy();
-				case "drop":
-					return this.destroy();
-				case "delete":
-					if (!this.opts.onlyEvents) {
-						if (this.opts.array) {
-							this.data = this.data.filter((x: any) => doc.documentKey?._id?.equals(x._id));
-						} else this.data = null;
-					}
-					return this.emit("delete", doc.documentKey._id.toHexString());
-				case "insert":
-					if (!this.opts.onlyEvents) {
-						if (this.opts.array) this.data.push(doc.fullDocument);
-						else this.data = doc.fullDocument;
-					}
-					return this.emit("insert", doc.fullDocument);
-				case "update":
-				case "replace":
-					if (!this.opts.onlyEvents) {
-						if (this.opts.array) {
-							const i = this.data.findIndex((x: any) => doc.fullDocument?._id?.equals(x._id));
-							if (i == -1) this.data.push(doc.fullDocument);
-							else this.data[i] = doc.fullDocument;
-						} else this.data = doc.fullDocument;
-					}
-
-					return this.emit("change", doc.fullDocument);
-				case "invalidate":
-					return this.destroy();
-				default:
-					return;
-			}
-		} catch (error) {
-			this.emit("error", error);
-		}
-	};
-
-	destroy = () => {
-		this.data = null;
-		this.stream?.off("change", this.change);
-		this.emit("close");
-
-		if (this.stream.isClosed()) return;
-
-		return this.stream.close();
-	};
-}
diff --git a/rtc/src/util/Intents.ts b/rtc/src/util/Intents.ts
deleted file mode 100644
index 943b29cf..00000000
--- a/rtc/src/util/Intents.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { BitField } from "./BitField";
-
-export class Intents extends BitField {
-	static FLAGS = {
-		GUILDS: BigInt(1) << BigInt(0),
-		GUILD_MEMBERS: BigInt(1) << BigInt(1),
-		GUILD_BANS: BigInt(1) << BigInt(2),
-		GUILD_EMOJIS: BigInt(1) << BigInt(3),
-		GUILD_INTEGRATIONS: BigInt(1) << BigInt(4),
-		GUILD_WEBHOOKS: BigInt(1) << BigInt(5),
-		GUILD_INVITES: BigInt(1) << BigInt(6),
-		GUILD_VOICE_STATES: BigInt(1) << BigInt(7),
-		GUILD_PRESENCES: BigInt(1) << BigInt(8),
-		GUILD_MESSAGES: BigInt(1) << BigInt(9),
-		GUILD_MESSAGE_REACTIONS: BigInt(1) << BigInt(10),
-		GUILD_MESSAGE_TYPING: BigInt(1) << BigInt(11),
-		DIRECT_MESSAGES: BigInt(1) << BigInt(12),
-		DIRECT_MESSAGE_REACTIONS: BigInt(1) << BigInt(13),
-		DIRECT_MESSAGE_TYPING: BigInt(1) << BigInt(14),
-	};
-}
diff --git a/rtc/src/util/MessageFlags.ts b/rtc/src/util/MessageFlags.ts
deleted file mode 100644
index c76be4c8..00000000
--- a/rtc/src/util/MessageFlags.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-// https://github.com/discordjs/discord.js/blob/master/src/util/MessageFlags.js
-// Apache License Version 2.0 Copyright 2015 - 2021 Amish Shah
-
-import { BitField } from "./BitField";
-
-export class MessageFlags extends BitField {
-	static FLAGS = {
-		CROSSPOSTED: BigInt(1) << BigInt(0),
-		IS_CROSSPOST: BigInt(1) << BigInt(1),
-		SUPPRESS_EMBEDS: BigInt(1) << BigInt(2),
-		SOURCE_MESSAGE_DELETED: BigInt(1) << BigInt(3),
-		URGENT: BigInt(1) << BigInt(4),
-	};
-}
diff --git a/rtc/src/util/MongoBigInt.ts b/rtc/src/util/MongoBigInt.ts
deleted file mode 100644
index fc451925..00000000
--- a/rtc/src/util/MongoBigInt.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-import mongoose from "mongoose";
-
-class LongSchema extends mongoose.SchemaType {
-	public $conditionalHandlers = {
-		$lt: this.handleSingle,
-		$lte: this.handleSingle,
-		$gt: this.handleSingle,
-		$gte: this.handleSingle,
-		$ne: this.handleSingle,
-		$in: this.handleArray,
-		$nin: this.handleArray,
-		$mod: this.handleArray,
-		$all: this.handleArray,
-		$bitsAnySet: this.handleArray,
-		$bitsAllSet: this.handleArray,
-	};
-
-	handleSingle(val: any) {
-		return this.cast(val, null, null, "handle");
-	}
-
-	handleArray(val: any) {
-		var self = this;
-		return val.map(function (m: any) {
-			return self.cast(m, null, null, "handle");
-		});
-	}
-
-	checkRequired(val: any) {
-		return null != val;
-	}
-
-	cast(val: any, scope?: any, init?: any, type?: string) {
-		if (null === val) return val;
-		if ("" === val) return null;
-		if (typeof val === "bigint") {
-			return mongoose.mongo.Long.fromString(val.toString());
-		}
-
-		if (val instanceof mongoose.mongo.Long) {
-			if (type === "handle" || init == false) return val;
-			return BigInt(val.toString());
-		}
-		if (val instanceof Number || "number" == typeof val) return BigInt(val);
-		if (!Array.isArray(val) && val.toString) return BigInt(val.toString());
-
-		//@ts-ignore
-		throw new SchemaType.CastError("Long", val);
-	}
-
-	castForQuery($conditional: string, value: any) {
-		var handler;
-		if (2 === arguments.length) {
-			// @ts-ignore
-			handler = this.$conditionalHandlers[$conditional];
-			if (!handler) {
-				throw new Error("Can't use " + $conditional + " with Long.");
-			}
-			return handler.call(this, value);
-		} else {
-			return this.cast($conditional, null, null, "query");
-		}
-	}
-}
-
-LongSchema.cast = mongoose.SchemaType.cast;
-LongSchema.set = mongoose.SchemaType.set;
-LongSchema.get = mongoose.SchemaType.get;
-
-declare module "mongoose" {
-	namespace Types {
-		class Long extends mongoose.mongo.Long {}
-	}
-	namespace Schema {
-		namespace Types {
-			class Long extends LongSchema {}
-		}
-	}
-}
-
-mongoose.Schema.Types.Long = LongSchema;
-mongoose.Types.Long = mongoose.mongo.Long;
diff --git a/rtc/src/util/Permissions.ts b/rtc/src/util/Permissions.ts
deleted file mode 100644
index 445e901f..00000000
--- a/rtc/src/util/Permissions.ts
+++ /dev/null
@@ -1,262 +0,0 @@
-// https://github.com/discordjs/discord.js/blob/master/src/util/Permissions.js
-// Apache License Version 2.0 Copyright 2015 - 2021 Amish Shah
-import { MemberDocument, MemberModel } from "../models/Member";
-import { ChannelDocument, ChannelModel } from "../models/Channel";
-import { ChannelPermissionOverwrite } from "../models/Channel";
-import { Role, RoleDocument, RoleModel } from "../models/Role";
-import { BitField } from "./BitField";
-import { GuildDocument, GuildModel } from "../models/Guild";
-// TODO: check role hierarchy permission
-
-var HTTPError: any;
-
-try {
-	HTTPError = require("lambert-server").HTTPError;
-} catch (e) {
-	HTTPError = Error;
-}
-
-export type PermissionResolvable = bigint | number | Permissions | PermissionResolvable[] | PermissionString;
-
-type PermissionString =
-	| "CREATE_INSTANT_INVITE"
-	| "KICK_MEMBERS"
-	| "BAN_MEMBERS"
-	| "ADMINISTRATOR"
-	| "MANAGE_CHANNELS"
-	| "MANAGE_GUILD"
-	| "ADD_REACTIONS"
-	| "VIEW_AUDIT_LOG"
-	| "PRIORITY_SPEAKER"
-	| "STREAM"
-	| "VIEW_CHANNEL"
-	| "SEND_MESSAGES"
-	| "SEND_TTS_MESSAGES"
-	| "MANAGE_MESSAGES"
-	| "EMBED_LINKS"
-	| "ATTACH_FILES"
-	| "READ_MESSAGE_HISTORY"
-	| "MENTION_EVERYONE"
-	| "USE_EXTERNAL_EMOJIS"
-	| "VIEW_GUILD_INSIGHTS"
-	| "CONNECT"
-	| "SPEAK"
-	| "MUTE_MEMBERS"
-	| "DEAFEN_MEMBERS"
-	| "MOVE_MEMBERS"
-	| "USE_VAD"
-	| "CHANGE_NICKNAME"
-	| "MANAGE_NICKNAMES"
-	| "MANAGE_ROLES"
-	| "MANAGE_WEBHOOKS"
-	| "MANAGE_EMOJIS";
-
-const CUSTOM_PERMISSION_OFFSET = BigInt(1) << BigInt(48); // 16 free custom permission bits, and 16 for discord to add new ones
-
-export class Permissions extends BitField {
-	cache: PermissionCache = {};
-
-	static FLAGS = {
-		CREATE_INSTANT_INVITE: BigInt(1) << BigInt(0),
-		KICK_MEMBERS: BigInt(1) << BigInt(1),
-		BAN_MEMBERS: BigInt(1) << BigInt(2),
-		ADMINISTRATOR: BigInt(1) << BigInt(3),
-		MANAGE_CHANNELS: BigInt(1) << BigInt(4),
-		MANAGE_GUILD: BigInt(1) << BigInt(5),
-		ADD_REACTIONS: BigInt(1) << BigInt(6),
-		VIEW_AUDIT_LOG: BigInt(1) << BigInt(7),
-		PRIORITY_SPEAKER: BigInt(1) << BigInt(8),
-		STREAM: BigInt(1) << BigInt(9),
-		VIEW_CHANNEL: BigInt(1) << BigInt(10),
-		SEND_MESSAGES: BigInt(1) << BigInt(11),
-		SEND_TTS_MESSAGES: BigInt(1) << BigInt(12),
-		MANAGE_MESSAGES: BigInt(1) << BigInt(13),
-		EMBED_LINKS: BigInt(1) << BigInt(14),
-		ATTACH_FILES: BigInt(1) << BigInt(15),
-		READ_MESSAGE_HISTORY: BigInt(1) << BigInt(16),
-		MENTION_EVERYONE: BigInt(1) << BigInt(17),
-		USE_EXTERNAL_EMOJIS: BigInt(1) << BigInt(18),
-		VIEW_GUILD_INSIGHTS: BigInt(1) << BigInt(19),
-		CONNECT: BigInt(1) << BigInt(20),
-		SPEAK: BigInt(1) << BigInt(21),
-		MUTE_MEMBERS: BigInt(1) << BigInt(22),
-		DEAFEN_MEMBERS: BigInt(1) << BigInt(23),
-		MOVE_MEMBERS: BigInt(1) << BigInt(24),
-		USE_VAD: BigInt(1) << BigInt(25),
-		CHANGE_NICKNAME: BigInt(1) << BigInt(26),
-		MANAGE_NICKNAMES: BigInt(1) << BigInt(27),
-		MANAGE_ROLES: BigInt(1) << BigInt(28),
-		MANAGE_WEBHOOKS: BigInt(1) << BigInt(29),
-		MANAGE_EMOJIS: BigInt(1) << BigInt(30),
-		/**
-		 * CUSTOM PERMISSIONS ideas:
-		 * - allow user to dm members
-		 * - allow user to pin messages (without MANAGE_MESSAGES)
-		 * - allow user to publish messages (without MANAGE_MESSAGES)
-		 */
-		// CUSTOM_PERMISSION: BigInt(1) << BigInt(0) + CUSTOM_PERMISSION_OFFSET
-	};
-
-	any(permission: PermissionResolvable, checkAdmin = true) {
-		return (checkAdmin && super.any(Permissions.FLAGS.ADMINISTRATOR)) || super.any(permission);
-	}
-
-	/**
-	 * Checks whether the bitfield has a permission, or multiple permissions.
-	 */
-	has(permission: PermissionResolvable, checkAdmin = true) {
-		return (checkAdmin && super.has(Permissions.FLAGS.ADMINISTRATOR)) || super.has(permission);
-	}
-
-	/**
-	 * Checks whether the bitfield has a permission, or multiple permissions, but throws an Error if user fails to match auth criteria.
-	 */
-	hasThrow(permission: PermissionResolvable) {
-		if (this.has(permission) && this.has("VIEW_CHANNEL")) return true;
-		// @ts-ignore
-		throw new HTTPError(`You are missing the following permissions ${permission}`, 403);
-	}
-
-	overwriteChannel(overwrites: ChannelPermissionOverwrite[]) {
-		if (!this.cache) throw new Error("permission chache not available");
-		overwrites = overwrites.filter((x) => {
-			if (x.type === 0 && this.cache.roles?.some((r) => r.id === x.id)) return true;
-			if (x.type === 1 && x.id == this.cache.user_id) return true;
-			return false;
-		});
-		return new Permissions(Permissions.channelPermission(overwrites, this.bitfield));
-	}
-
-	static channelPermission(overwrites: ChannelPermissionOverwrite[], init?: bigint) {
-		// TODO: do not deny any permissions if admin
-		return overwrites.reduce((permission, overwrite) => {
-			// apply disallowed permission
-			// * permission: current calculated permission (e.g. 010)
-			// * deny contains all denied permissions (e.g. 011)
-			// * allow contains all explicitly allowed permisions (e.g. 100)
-			return (permission & ~BigInt(overwrite.deny)) | BigInt(overwrite.allow);
-			// ~ operator inverts deny (e.g. 011 -> 100)
-			// & operator only allows 1 for both ~deny and permission (e.g. 010 & 100 -> 000)
-			// | operators adds both together (e.g. 000 + 100 -> 100)
-		}, init || 0n);
-	}
-
-	static rolePermission(roles: Role[]) {
-		// adds all permissions of all roles together (Bit OR)
-		return roles.reduce((permission, role) => permission | BigInt(role.permissions), 0n);
-	}
-
-	static finalPermission({
-		user,
-		guild,
-		channel,
-	}: {
-		user: { id: string; roles: string[] };
-		guild: { roles: Role[] };
-		channel?: {
-			overwrites?: ChannelPermissionOverwrite[];
-			recipient_ids?: string[] | null;
-			owner_id?: string;
-		};
-	}) {
-		if (user.id === "0") return new Permissions("ADMINISTRATOR"); // system user id
-
-		let roles = guild.roles.filter((x) => user.roles.includes(x.id));
-		let permission = Permissions.rolePermission(roles);
-
-		if (channel?.overwrites) {
-			let overwrites = channel.overwrites.filter((x) => {
-				if (x.type === 0 && user.roles.includes(x.id)) return true;
-				if (x.type === 1 && x.id == user.id) return true;
-				return false;
-			});
-			permission = Permissions.channelPermission(overwrites, permission);
-		}
-
-		if (channel?.recipient_ids) {
-			if (channel?.owner_id === user.id) return new Permissions("ADMINISTRATOR");
-			if (channel.recipient_ids.includes(user.id)) {
-				// Default dm permissions
-				return new Permissions([
-					"VIEW_CHANNEL",
-					"SEND_MESSAGES",
-					"STREAM",
-					"ADD_REACTIONS",
-					"EMBED_LINKS",
-					"ATTACH_FILES",
-					"READ_MESSAGE_HISTORY",
-					"MENTION_EVERYONE",
-					"USE_EXTERNAL_EMOJIS",
-					"CONNECT",
-					"SPEAK",
-					"MANAGE_CHANNELS",
-				]);
-			}
-
-			return new Permissions();
-		}
-
-		return new Permissions(permission);
-	}
-}
-
-export type PermissionCache = {
-	channel?: ChannelDocument | null;
-	member?: MemberDocument | null;
-	guild?: GuildDocument | null;
-	roles?: RoleDocument[] | null;
-	user_id?: string;
-};
-
-export async function getPermission(
-	user_id?: string,
-	guild_id?: string,
-	channel_id?: string,
-	cache: PermissionCache = {}
-) {
-	var { channel, member, guild, roles } = cache;
-
-	if (!user_id) throw new HTTPError("User not found");
-
-	if (channel_id && !channel) {
-		channel = await ChannelModel.findOne(
-			{ id: channel_id },
-			{ permission_overwrites: true, recipient_ids: true, owner_id: true, guild_id: true }
-		).exec();
-		if (!channel) throw new HTTPError("Channel not found", 404);
-		if (channel.guild_id) guild_id = channel.guild_id;
-	}
-
-	if (guild_id) {
-		if (!guild) guild = await GuildModel.findOne({ id: guild_id }, { owner_id: true }).exec();
-		if (!guild) throw new HTTPError("Guild not found");
-		if (guild.owner_id === user_id) return new Permissions(Permissions.FLAGS.ADMINISTRATOR);
-
-		if (!member) member = await MemberModel.findOne({ guild_id, id: user_id }, "roles").exec();
-		if (!member) throw new HTTPError("Member not found");
-
-		if (!roles) roles = await RoleModel.find({ guild_id, id: { $in: member.roles } }).exec();
-	}
-
-	var permission = Permissions.finalPermission({
-		user: {
-			id: user_id,
-			roles: member?.roles || [],
-		},
-		guild: {
-			roles: roles || [],
-		},
-		channel: {
-			overwrites: channel?.permission_overwrites,
-			owner_id: channel?.owner_id,
-			recipient_ids: channel?.recipient_ids,
-		},
-	});
-
-	const obj = new Permissions(permission);
-
-	// pass cache to permission for possible future getPermission calls
-	obj.cache = { guild, member, channel, roles, user_id };
-
-	return obj;
-}
diff --git a/rtc/src/util/RabbitMQ.ts b/rtc/src/util/RabbitMQ.ts
deleted file mode 100644
index 9da41990..00000000
--- a/rtc/src/util/RabbitMQ.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import amqp, { Connection, Channel } from "amqplib";
-import Config from "./Config";
-
-export const RabbitMQ: { connection: Connection | null; channel: Channel | null; init: () => Promise<void> } = {
-	connection: null,
-	channel: null,
-	init: async function () {
-		const host = Config.get().rabbitmq.host;
-		if (!host) return;
-		console.log(`[RabbitMQ] connect: ${host}`);
-		this.connection = await amqp.connect(host, {
-			timeout: 1000 * 60,
-		});
-		console.log(`[RabbitMQ] connected`);
-		this.channel = await this.connection.createChannel();
-		console.log(`[RabbitMQ] channel created`);
-	},
-};
diff --git a/rtc/src/util/Regex.ts b/rtc/src/util/Regex.ts
deleted file mode 100644
index bbd48bca..00000000
--- a/rtc/src/util/Regex.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export const DOUBLE_WHITE_SPACE = /\s\s+/g;
-export const SPECIAL_CHAR = /[@#`:\r\n\t\f\v\p{C}]/gu;
-export const CHANNEL_MENTION = /<#(\d+)>/g;
diff --git a/rtc/src/util/Snowflake.ts b/rtc/src/util/Snowflake.ts
deleted file mode 100644
index 1d725710..00000000
--- a/rtc/src/util/Snowflake.ts
+++ /dev/null
@@ -1,127 +0,0 @@
-// @ts-nocheck
-import cluster from "cluster";
-
-// https://github.com/discordjs/discord.js/blob/master/src/util/Snowflake.js
-// Apache License Version 2.0 Copyright 2015 - 2021 Amish Shah
-("use strict");
-
-// Discord epoch (2015-01-01T00:00:00.000Z)
-
-/**
- * A container for useful snowflake-related methods.
- */
-export class Snowflake {
-	static readonly EPOCH = 1420070400000;
-	static INCREMENT = 0n; // max 4095
-	static processId = BigInt(process.pid % 31); // max 31
-	static workerId = BigInt((cluster.worker?.id || 0) % 31); // max 31
-
-	constructor() {
-		throw new Error(`The ${this.constructor.name} class may not be instantiated.`);
-	}
-
-	/**
-	 * A Twitter snowflake, except the epoch is 2015-01-01T00:00:00.000Z
-	 * ```
-	 * If we have a snowflake '266241948824764416' we can represent it as binary:
-	 *
-	 * 64                                          22     17     12          0
-	 *  000000111011000111100001101001000101000000  00001  00000  000000000000
-	 *       number of ms since Discord epoch       worker  pid    increment
-	 * ```
-	 * @typedef {string} Snowflake
-	 */
-
-	/**
-	 * Transforms a snowflake from a decimal string to a bit string.
-	 * @param  {Snowflake} num Snowflake to be transformed
-	 * @returns {string}
-	 * @private
-	 */
-	static idToBinary(num) {
-		let bin = "";
-		let high = parseInt(num.slice(0, -10)) || 0;
-		let low = parseInt(num.slice(-10));
-		while (low > 0 || high > 0) {
-			bin = String(low & 1) + bin;
-			low = Math.floor(low / 2);
-			if (high > 0) {
-				low += 5000000000 * (high % 2);
-				high = Math.floor(high / 2);
-			}
-		}
-		return bin;
-	}
-
-	/**
-	 * Transforms a snowflake from a bit string to a decimal string.
-	 * @param  {string} num Bit string to be transformed
-	 * @returns {Snowflake}
-	 * @private
-	 */
-	static binaryToID(num) {
-		let dec = "";
-
-		while (num.length > 50) {
-			const high = parseInt(num.slice(0, -32), 2);
-			const low = parseInt((high % 10).toString(2) + num.slice(-32), 2);
-
-			dec = (low % 10).toString() + dec;
-			num =
-				Math.floor(high / 10).toString(2) +
-				Math.floor(low / 10)
-					.toString(2)
-					.padStart(32, "0");
-		}
-
-		num = parseInt(num, 2);
-		while (num > 0) {
-			dec = (num % 10).toString() + dec;
-			num = Math.floor(num / 10);
-		}
-
-		return dec;
-	}
-
-	static generate() {
-		var time = BigInt(Date.now() - Snowflake.EPOCH) << 22n;
-		var worker = Snowflake.workerId << 17n;
-		var process = Snowflake.processId << 12n;
-		var increment = Snowflake.INCREMENT++;
-		return (time | worker | process | increment).toString();
-	}
-
-	/**
-	 * A deconstructed snowflake.
-	 * @typedef {Object} DeconstructedSnowflake
-	 * @property {number} timestamp Timestamp the snowflake was created
-	 * @property {Date} date Date the snowflake was created
-	 * @property {number} workerID Worker ID in the snowflake
-	 * @property {number} processID Process ID in the snowflake
-	 * @property {number} increment Increment in the snowflake
-	 * @property {string} binary Binary representation of the snowflake
-	 */
-
-	/**
-	 * Deconstructs a Discord snowflake.
-	 * @param {Snowflake} snowflake Snowflake to deconstruct
-	 * @returns {DeconstructedSnowflake} Deconstructed snowflake
-	 */
-	static deconstruct(snowflake) {
-		const BINARY = Snowflake.idToBinary(snowflake).toString(2).padStart(64, "0");
-		const res = {
-			timestamp: parseInt(BINARY.substring(0, 42), 2) + Snowflake.EPOCH,
-			workerID: parseInt(BINARY.substring(42, 47), 2),
-			processID: parseInt(BINARY.substring(47, 52), 2),
-			increment: parseInt(BINARY.substring(52, 64), 2),
-			binary: BINARY,
-		};
-		Object.defineProperty(res, "date", {
-			get: function get() {
-				return new Date(this.timestamp);
-			},
-			enumerable: true,
-		});
-		return res;
-	}
-}
diff --git a/rtc/src/util/String.ts b/rtc/src/util/String.ts
deleted file mode 100644
index 55f11e8d..00000000
--- a/rtc/src/util/String.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { SPECIAL_CHAR } from "./Regex";
-
-export function trimSpecial(str?: string): string {
-	// @ts-ignore
-	if (!str) return;
-	return str.replace(SPECIAL_CHAR, "").trim();
-}
diff --git a/rtc/src/util/UserFlags.ts b/rtc/src/util/UserFlags.ts
deleted file mode 100644
index 72394eff..00000000
--- a/rtc/src/util/UserFlags.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-// https://github.com/discordjs/discord.js/blob/master/src/util/UserFlags.js
-// Apache License Version 2.0 Copyright 2015 - 2021 Amish Shah
-
-import { BitField } from "./BitField";
-
-export class UserFlags extends BitField {
-	static FLAGS = {
-		DISCORD_EMPLOYEE: BigInt(1) << BigInt(0),
-		PARTNERED_SERVER_OWNER: BigInt(1) << BigInt(1),
-		HYPESQUAD_EVENTS: BigInt(1) << BigInt(2),
-		BUGHUNTER_LEVEL_1: BigInt(1) << BigInt(3),
-		HOUSE_BRAVERY: BigInt(1) << BigInt(6),
-		HOUSE_BRILLIANCE: BigInt(1) << BigInt(7),
-		HOUSE_BALANCE: BigInt(1) << BigInt(8),
-		EARLY_SUPPORTER: BigInt(1) << BigInt(9),
-		TEAM_USER: BigInt(1) << BigInt(10),
-		SYSTEM: BigInt(1) << BigInt(12),
-		BUGHUNTER_LEVEL_2: BigInt(1) << BigInt(14),
-		VERIFIED_BOT: BigInt(1) << BigInt(16),
-		EARLY_VERIFIED_BOT_DEVELOPER: BigInt(1) << BigInt(17),
-	};
-}
diff --git a/rtc/src/util/checkToken.ts b/rtc/src/util/checkToken.ts
deleted file mode 100644
index 91bf08d5..00000000
--- a/rtc/src/util/checkToken.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { JWTOptions } from "./Constants";
-import jwt from "jsonwebtoken";
-import { UserModel } from "../models";
-
-export function checkToken(token: string, jwtSecret: string): Promise<any> {
-	return new Promise((res, rej) => {
-		token = token.replace("Bot ", ""); // TODO: proper bot support
-		jwt.verify(token, jwtSecret, JWTOptions, async (err, decoded: any) => {
-			if (err || !decoded) return rej("Invalid Token");
-
-			const user = await UserModel.findOne(
-				{ id: decoded.id },
-				{ "user_data.valid_tokens_since": true, bot: true, disabled: true, deleted: true }
-			).exec();
-			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 (user.disabled) return rej("User disabled");
-			if (user.deleted) return rej("User not found");
-
-			return res({ decoded, user });
-		});
-	});
-}
diff --git a/rtc/src/util/index.ts b/rtc/src/util/index.ts
deleted file mode 100644
index 7523a6ad..00000000
--- a/rtc/src/util/index.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-export * from "./String";
-export * from "./BitField";
-export * from "./Intents";
-export * from "./MessageFlags";
-export * from "./Permissions";
-export * from "./Snowflake";
-export * from "./UserFlags";
-export * from "./toBigInt";
-export * from "./RabbitMQ";
diff --git a/rtc/src/util/toBigInt.ts b/rtc/src/util/toBigInt.ts
deleted file mode 100644
index d57c4568..00000000
--- a/rtc/src/util/toBigInt.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export default function toBigInt(string: String): BigInt {
-	return BigInt(string);
-}
diff --git a/util/package.json b/util/package.json
index 0478fe69..c2b08a3d 100644
--- a/util/package.json
+++ b/util/package.json
@@ -1,13 +1,12 @@
 {
-	"name": "@fosscord/server-util",
+	"name": "@fosscord/util",
 	"version": "1.3.52",
-	"description": "Utility functions for the all server repositories",
+	"description": "Utility functions and database models for fosscord",
 	"main": "dist/index.js",
 	"types": "dist/index.d.ts",
 	"scripts": {
-		"test": "echo \"Error: no test specified\" && exit 1",
-		"build": "tsc -b .",
-		"prepublish": "npm run build"
+		"link": "npm run build && npm link",
+		"build": "tsc -b ."
 	},
 	"repository": {
 		"type": "git",
@@ -38,7 +37,7 @@
 		"jsonwebtoken": "^8.5.1",
 		"missing-native-js-functions": "^1.2.2",
 		"mongodb": "^3.6.9",
-		"mongoose": "^5.12.3",
+		"mongoose": "^5.13.7",
 		"mongoose-autopopulate": "^0.12.3",
 		"typescript": "^4.1.3"
 	},
diff --git a/util/src/models/index.ts b/util/src/models/index.ts
index d0a46bf9..db74ef40 100644
--- a/util/src/models/index.ts
+++ b/util/src/models/index.ts
@@ -12,6 +12,9 @@ type UpdateAggregationStage =
 type EnforceDocument<T, TMethods> = T extends Document ? T : T & Document & TMethods;
 
 declare module "mongoose" {
+	interface SchemaOptions {
+		removeResponse?: string[];
+	}
 	interface Model<T, TQueryHelpers = {}, TMethods = {}> {
 		// removed null -> always return document -> throw error if it doesn't exist
 		findOne(
diff --git a/util/src/util/Config.ts b/util/src/util/Config.ts
index 78b44315..b4648668 100644
--- a/util/src/util/Config.ts
+++ b/util/src/util/Config.ts
@@ -1,6 +1,6 @@
 import { Schema, model, Types, Document } from "mongoose";
 import "missing-native-js-functions";
-import db, { MongooseCache } from "./Database";
+import db from "./Database";
 import { Snowflake } from "./Snowflake";
 import crypto from "crypto";
 
@@ -15,6 +15,7 @@ export default {
 		return config as DefaultOptions;
 	},
 	set: function set(val: any) {
+		config = val.merge(config);
 		return db.collection("config").updateOne({}, { $set: val }, { upsert: true });
 	},
 };
diff --git a/util/src/util/Database.ts b/util/src/util/Database.ts
index 8c6847a8..233152f1 100644
--- a/util/src/util/Database.ts
+++ b/util/src/util/Database.ts
@@ -14,6 +14,9 @@ const connection = mongoose.createConnection(uri, {
 	useFindAndModify: false,
 });
 console.log(`[Database] connect: mongodb://${url.username}@${url.host}${url.pathname}${url.search}`);
+connection.once("open", () => {
+	console.log("[Database] connected");
+});
 
 export default <Connection>connection;
 
diff --git a/util/src/util/Event.ts b/util/src/util/Event.ts
new file mode 100644
index 00000000..13dd797a
--- /dev/null
+++ b/util/src/util/Event.ts
@@ -0,0 +1,94 @@
+import { Channel, ConsumeMessage } from "amqplib";
+import { EVENT, Event, EventModel } from "../models";
+import { RabbitMQ } from "./RabbitMQ";
+import EventEmitter from "events";
+const events = new EventEmitter();
+
+export async function emitEvent(payload: Omit<Event, "created_at">) {
+	const id = (payload.channel_id || payload.user_id || payload.guild_id) as string;
+	if (!id) console.error("event doesn't contain any id", payload);
+
+	if (RabbitMQ.connection) {
+		const data = typeof payload.data === "object" ? JSON.stringify(payload.data) : payload.data; // use rabbitmq for event transmission
+		await RabbitMQ.channel?.assertExchange(id, "fanout", { durable: false });
+
+		// assertQueue isn't needed, because a queue will automatically created if it doesn't exist
+		const successful = RabbitMQ.channel?.publish(id, "", Buffer.from(`${data}`), { type: payload.event });
+		if (!successful) throw new Error("failed to send event");
+	} else {
+		events.emit(id, payload);
+	}
+}
+
+export async function initEvent() {
+	await RabbitMQ.init(); // does nothing if rabbitmq is not setup
+	if (RabbitMQ.connection) {
+	} else {
+		// use event emitter
+	}
+}
+
+export interface EventOpts extends Event {
+	acknowledge?: Function;
+	channel?: Channel;
+	cancel: Function;
+}
+
+export interface ListenEventOpts {
+	channel?: Channel;
+	acknowledge?: boolean;
+}
+
+export async function listenEvent(event: string, callback: (event: EventOpts) => any, opts?: ListenEventOpts) {
+	if (RabbitMQ.connection) {
+		// @ts-ignore
+		return rabbitListen(opts?.channel || RabbitMQ.channel, event, callback, { acknowledge: opts?.acknowledge });
+	} else {
+		const cancel = () => events.removeListener(event, callback);
+		events.addListener(event, (opts) => callback({ ...opts, cancel }));
+
+		return cancel;
+	}
+}
+
+async function rabbitListen(
+	channel: Channel,
+	id: string,
+	callback: (event: EventOpts) => any,
+	opts?: { acknowledge?: boolean }
+) {
+	await channel.assertExchange(id, "fanout", { durable: false });
+	const q = await channel.assertQueue("", { exclusive: true, autoDelete: true });
+
+	const cancel = () => {
+		channel.cancel(q.queue);
+		channel.unbindQueue(q.queue, id, "");
+	};
+
+	channel.bindQueue(q.queue, id, "");
+	channel.consume(
+		q.queue,
+		(opts) => {
+			if (!opts) return;
+
+			const data = JSON.parse(opts.content.toString());
+			const event = opts.properties.type as EVENT;
+
+			callback({
+				event,
+				data,
+				acknowledge() {
+					channel.ack(opts);
+				},
+				channel,
+				cancel,
+			});
+			// rabbitCh.ack(opts);
+		},
+		{
+			noAck: !opts?.acknowledge,
+		}
+	);
+
+	return cancel;
+}
diff --git a/util/src/util/index.ts b/util/src/util/index.ts
index 7523a6ad..0aad15f2 100644
--- a/util/src/util/index.ts
+++ b/util/src/util/index.ts
@@ -7,3 +7,4 @@ export * from "./Snowflake";
 export * from "./UserFlags";
 export * from "./toBigInt";
 export * from "./RabbitMQ";
+export * from "./Event";
diff --git a/webrtc/package.json b/webrtc/package.json
index 54c043ee..8163ac57 100644
--- a/webrtc/package.json
+++ b/webrtc/package.json
@@ -4,6 +4,7 @@
 	"description": "A javascript fosscord webrtc server for voice and video communication",
 	"main": "index.js",
 	"scripts": {
+		"postinstall": "npm link @fosscord/util",
 		"test": "npm run build && node dist/test.js",
 		"build": "tsc -b .",
 		"start": "npm run build && node dist/start.js"
diff --git a/webrtc/src/Server.ts b/webrtc/src/Server.ts
index bb82e659..41ca65d1 100644
--- a/webrtc/src/Server.ts
+++ b/webrtc/src/Server.ts
@@ -1,6 +1,6 @@
 import { Server as WebSocketServer } from "ws";
-import { Config, db } from "@fosscord/server-util";
-import mediasoup from "mediasoup"
+import { Config, db } from "@fosscord/util";
+import mediasoup from "mediasoup";
 
 var port = Number(process.env.PORT);
 if (isNaN(port)) port = 3004;
@@ -30,7 +30,6 @@ export class Server {
 				);
 			});
 		});
-
 	}
 
 	async listen(): Promise<void> {