summary refs log tree commit diff
diff options
context:
space:
mode:
authorMadeline <46743919+MaddyUnderStars@users.noreply.github.com>2022-07-21 16:28:41 +1000
committerMadeline <46743919+MaddyUnderStars@users.noreply.github.com>2022-07-21 16:53:32 +1000
commit0363b418907a0b007bf9bc6e158ac8fd36e39924 (patch)
tree41d3e636de989292283e978c554e930195fe8f3d
parentPrevent demo user from enabling 2FA (diff)
downloadserver-0363b418907a0b007bf9bc6e158ac8fd36e39924.tar.xz
Added simple response time measurement for grafana
-rw-r--r--slowcord/README.md (renamed from slowcord/login/README.md)0
-rw-r--r--slowcord/login/package.json6
-rw-r--r--slowcord/status/.env.template6
-rw-r--r--slowcord/status/package-lock.json891
-rw-r--r--slowcord/status/package.json30
-rw-r--r--slowcord/status/src/index.ts91
-rw-r--r--slowcord/status/tsconfig.json99
7 files changed, 1120 insertions, 3 deletions
diff --git a/slowcord/login/README.md b/slowcord/README.md
index 892b5763..892b5763 100644
--- a/slowcord/login/README.md
+++ b/slowcord/README.md
diff --git a/slowcord/login/package.json b/slowcord/login/package.json
index 9ee62b2c..b458a875 100644
--- a/slowcord/login/package.json
+++ b/slowcord/login/package.json
@@ -1,7 +1,7 @@
 {
-	"name": "slowcord",
+	"name": "slowcord-login",
 	"version": "1.0.0",
-	"description": "Slowcord additional services",
+	"description": "Slowcord login service",
 	"main": "build/index.js",
 	"scripts": {
 		"build": "tsc -b",
@@ -11,7 +11,7 @@
 		"type": "git",
 		"url": "git+https://github.com/maddyunderstars/fosscord-server.git"
 	},
-	"author": "",
+	"author": "MaddyUnderStars",
 	"license": "AGPL-3.0-only",
 	"bugs": {
 		"url": "https://github.com/maddyunderstars/fosscord-server/issues"
diff --git a/slowcord/status/.env.template b/slowcord/status/.env.template
new file mode 100644
index 00000000..e15dc56a
--- /dev/null
+++ b/slowcord/status/.env.template
@@ -0,0 +1,6 @@
+DATABASE=
+INSTANCE_API=
+INSTANCE_CDN=
+INSTANCE_TOKEN=
+MEASURE_INTERVAL=1000
+RETENTION_DAYS=30
\ No newline at end of file
diff --git a/slowcord/status/package-lock.json b/slowcord/status/package-lock.json
new file mode 100644
index 00000000..a4f449ab
--- /dev/null
+++ b/slowcord/status/package-lock.json
@@ -0,0 +1,891 @@
+{
+	"name": "slowcord-status",
+	"version": "1.0.0",
+	"lockfileVersion": 2,
+	"requires": true,
+	"packages": {
+		"": {
+			"name": "slowcord-status",
+			"version": "1.0.0",
+			"license": "AGPL-3.0-only",
+			"dependencies": {
+				"dotenv": "^16.0.1",
+				"fosscord-gopnik": "^1.0.0",
+				"mysql2": "^2.3.3",
+				"node-fetch": "^3.2.9"
+			},
+			"devDependencies": {
+				"@types/node": "^18.0.6"
+			}
+		},
+		"../../util": {
+			"name": "@fosscord/util",
+			"version": "1.0.0",
+			"extraneous": true,
+			"hasInstallScript": true,
+			"license": "AGPL-3.0-only",
+			"dependencies": {
+				"amqplib": "^0.8.0",
+				"form-data": "^4.0.0",
+				"jsonwebtoken": "^8.5.1",
+				"lambert-server": "^1.2.12",
+				"missing-native-js-functions": "^1.2.18",
+				"multer": "^1.4.3",
+				"node-fetch": "^2.6.2",
+				"patch-package": "^6.4.7",
+				"pg": "^8.7.1",
+				"picocolors": "^1.0.0",
+				"proxy-agent": "^5.0.0",
+				"reflect-metadata": "^0.1.13",
+				"typeorm": "^0.2.37",
+				"typescript": "^4.4.2",
+				"typescript-json-schema": "^0.50.1"
+			},
+			"devDependencies": {
+				"@types/amqplib": "^0.8.1",
+				"@types/jsonwebtoken": "^8.5.0",
+				"@types/multer": "^1.4.7",
+				"@types/node": "^14.17.9",
+				"@types/node-fetch": "^2.5.12",
+				"jest": "^27.0.6",
+				"ts-node": "^10.2.1"
+			}
+		},
+		"node_modules/@discordjs/builders": {
+			"version": "0.16.0",
+			"resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.16.0.tgz",
+			"integrity": "sha512-9/NCiZrLivgRub2/kBc0Vm5pMBE5AUdYbdXsLu/yg9ANgvnaJ0bZKTY8yYnLbsEc/LYUP79lEIdC73qEYhWq7A==",
+			"deprecated": "no longer supported",
+			"dependencies": {
+				"@sapphire/shapeshift": "^3.5.1",
+				"discord-api-types": "^0.36.2",
+				"fast-deep-equal": "^3.1.3",
+				"ts-mixer": "^6.0.1",
+				"tslib": "^2.4.0"
+			},
+			"engines": {
+				"node": ">=16.9.0"
+			}
+		},
+		"node_modules/@discordjs/builders/node_modules/discord-api-types": {
+			"version": "0.36.2",
+			"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.36.2.tgz",
+			"integrity": "sha512-TunPAvzwneK/m5fr4hxH3bMsrtI22nr9yjfHyo5NBGMjpsAauGNiGCmwoFf0oO3jSd2mZiKUvZwCKDaB166u2Q=="
+		},
+		"node_modules/@discordjs/collection": {
+			"version": "0.7.0",
+			"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.7.0.tgz",
+			"integrity": "sha512-R5i8Wb8kIcBAFEPLLf7LVBQKBDYUL+ekb23sOgpkpyGT+V4P7V83wTxcsqmX+PbqHt4cEHn053uMWfRqh/Z/nA==",
+			"deprecated": "no longer supported",
+			"engines": {
+				"node": ">=16.9.0"
+			}
+		},
+		"node_modules/@sapphire/async-queue": {
+			"version": "1.3.1",
+			"resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.3.1.tgz",
+			"integrity": "sha512-FFTlPOWZX1kDj9xCAsRzH5xEJfawg1lNoYAA+ecOWJMHOfiZYb1uXOI3ne9U4UILSEPwfE68p3T9wUHwIQfR0g==",
+			"engines": {
+				"node": ">=v14.0.0",
+				"npm": ">=7.0.0"
+			}
+		},
+		"node_modules/@sapphire/shapeshift": {
+			"version": "3.5.1",
+			"resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.5.1.tgz",
+			"integrity": "sha512-7JFsW5IglyOIUQI1eE0g6h06D/Far6HqpcowRScgCiLSqTf3hhkPWCWotVTtVycnDCMYIwPeaw6IEPBomKC8pA==",
+			"dependencies": {
+				"fast-deep-equal": "^3.1.3",
+				"lodash.uniqwith": "^4.5.0"
+			},
+			"engines": {
+				"node": ">=v14.0.0",
+				"npm": ">=7.0.0"
+			}
+		},
+		"node_modules/@types/node": {
+			"version": "18.0.6",
+			"resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.6.tgz",
+			"integrity": "sha512-/xUq6H2aQm261exT6iZTMifUySEt4GR5KX8eYyY+C4MSNPqSh9oNIP7tz2GLKTlFaiBbgZNxffoR3CVRG+cljw=="
+		},
+		"node_modules/@types/node-fetch": {
+			"version": "2.6.2",
+			"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz",
+			"integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==",
+			"dependencies": {
+				"@types/node": "*",
+				"form-data": "^3.0.0"
+			}
+		},
+		"node_modules/@types/node-fetch/node_modules/form-data": {
+			"version": "3.0.1",
+			"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
+			"integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
+			"dependencies": {
+				"asynckit": "^0.4.0",
+				"combined-stream": "^1.0.8",
+				"mime-types": "^2.1.12"
+			},
+			"engines": {
+				"node": ">= 6"
+			}
+		},
+		"node_modules/@types/ws": {
+			"version": "8.5.3",
+			"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz",
+			"integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==",
+			"dependencies": {
+				"@types/node": "*"
+			}
+		},
+		"node_modules/asynckit": {
+			"version": "0.4.0",
+			"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+			"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
+		},
+		"node_modules/combined-stream": {
+			"version": "1.0.8",
+			"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+			"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+			"dependencies": {
+				"delayed-stream": "~1.0.0"
+			},
+			"engines": {
+				"node": ">= 0.8"
+			}
+		},
+		"node_modules/data-uri-to-buffer": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
+			"integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==",
+			"engines": {
+				"node": ">= 12"
+			}
+		},
+		"node_modules/delayed-stream": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+			"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+			"engines": {
+				"node": ">=0.4.0"
+			}
+		},
+		"node_modules/denque": {
+			"version": "2.1.0",
+			"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
+			"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
+			"engines": {
+				"node": ">=0.10"
+			}
+		},
+		"node_modules/discord-api-types": {
+			"version": "0.33.5",
+			"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.33.5.tgz",
+			"integrity": "sha512-dvO5M52v7m7Dy96+XUnzXNsQ/0npsYpU6dL205kAtEDueswoz3aU3bh1UMoK4cQmcGtB1YRyLKqp+DXi05lzFg=="
+		},
+		"node_modules/discord.js": {
+			"version": "13.9.0",
+			"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.9.0.tgz",
+			"integrity": "sha512-QNscX8lQ2FwHuAd/NptQYc43oMUVijugir/vRbsTSgySidg8pcGQVqtRg8urqY3cbCOCZfNAMD/lR+SM7uijsA==",
+			"dependencies": {
+				"@discordjs/builders": "^0.16.0",
+				"@discordjs/collection": "^0.7.0",
+				"@sapphire/async-queue": "^1.3.1",
+				"@types/node-fetch": "^2.6.2",
+				"@types/ws": "^8.5.3",
+				"discord-api-types": "^0.33.3",
+				"form-data": "^4.0.0",
+				"node-fetch": "^2.6.7",
+				"ws": "^8.8.1"
+			},
+			"engines": {
+				"node": ">=16.6.0",
+				"npm": ">=7.0.0"
+			}
+		},
+		"node_modules/discord.js/node_modules/node-fetch": {
+			"version": "2.6.7",
+			"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+			"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+			"dependencies": {
+				"whatwg-url": "^5.0.0"
+			},
+			"engines": {
+				"node": "4.x || >=6.0.0"
+			},
+			"peerDependencies": {
+				"encoding": "^0.1.0"
+			},
+			"peerDependenciesMeta": {
+				"encoding": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/dotenv": {
+			"version": "16.0.1",
+			"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz",
+			"integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==",
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/encoding": {
+			"version": "0.1.13",
+			"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
+			"integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
+			"optional": true,
+			"peer": true,
+			"dependencies": {
+				"iconv-lite": "^0.6.2"
+			}
+		},
+		"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/fetch-blob": {
+			"version": "3.2.0",
+			"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
+			"integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
+			"funding": [
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/jimmywarting"
+				},
+				{
+					"type": "paypal",
+					"url": "https://paypal.me/jimmywarting"
+				}
+			],
+			"dependencies": {
+				"node-domexception": "^1.0.0",
+				"web-streams-polyfill": "^3.0.3"
+			},
+			"engines": {
+				"node": "^12.20 || >= 14.13"
+			}
+		},
+		"node_modules/form-data": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+			"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+			"dependencies": {
+				"asynckit": "^0.4.0",
+				"combined-stream": "^1.0.8",
+				"mime-types": "^2.1.12"
+			},
+			"engines": {
+				"node": ">= 6"
+			}
+		},
+		"node_modules/formdata-polyfill": {
+			"version": "4.0.10",
+			"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
+			"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
+			"dependencies": {
+				"fetch-blob": "^3.1.2"
+			},
+			"engines": {
+				"node": ">=12.20.0"
+			}
+		},
+		"node_modules/fosscord-gopnik": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/fosscord-gopnik/-/fosscord-gopnik-1.0.0.tgz",
+			"integrity": "sha512-cCJhXTVOEDEhhSOwceYsptU3f97GOVOAVNJ4UFMiQESp4wnYE0GKnlYYYs6gMkZounxPEv0t22kSHdajx6Ed/w==",
+			"dependencies": {
+				"discord.js": "^13.5.1"
+			}
+		},
+		"node_modules/generate-function": {
+			"version": "2.3.1",
+			"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz",
+			"integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==",
+			"dependencies": {
+				"is-property": "^1.0.2"
+			}
+		},
+		"node_modules/iconv-lite": {
+			"version": "0.6.3",
+			"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+			"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+			"dependencies": {
+				"safer-buffer": ">= 2.1.2 < 3.0.0"
+			},
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/is-property": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
+			"integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g=="
+		},
+		"node_modules/lodash.uniqwith": {
+			"version": "4.5.0",
+			"resolved": "https://registry.npmjs.org/lodash.uniqwith/-/lodash.uniqwith-4.5.0.tgz",
+			"integrity": "sha512-7lYL8bLopMoy4CTICbxygAUq6CdRJ36vFc80DucPueUee+d5NBRxz3FdT9Pes/HEx5mPoT9jwnsEJWz1N7uq7Q=="
+		},
+		"node_modules/long": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
+			"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
+		},
+		"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/mime-db": {
+			"version": "1.52.0",
+			"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+			"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+			"engines": {
+				"node": ">= 0.6"
+			}
+		},
+		"node_modules/mime-types": {
+			"version": "2.1.35",
+			"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+			"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+			"dependencies": {
+				"mime-db": "1.52.0"
+			},
+			"engines": {
+				"node": ">= 0.6"
+			}
+		},
+		"node_modules/mysql2": {
+			"version": "2.3.3",
+			"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.3.3.tgz",
+			"integrity": "sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA==",
+			"dependencies": {
+				"denque": "^2.0.1",
+				"generate-function": "^2.3.1",
+				"iconv-lite": "^0.6.3",
+				"long": "^4.0.0",
+				"lru-cache": "^6.0.0",
+				"named-placeholders": "^1.1.2",
+				"seq-queue": "^0.0.5",
+				"sqlstring": "^2.3.2"
+			},
+			"engines": {
+				"node": ">= 8.0"
+			}
+		},
+		"node_modules/mysql2/node_modules/sqlstring": {
+			"version": "2.3.3",
+			"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz",
+			"integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==",
+			"engines": {
+				"node": ">= 0.6"
+			}
+		},
+		"node_modules/named-placeholders": {
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz",
+			"integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==",
+			"dependencies": {
+				"lru-cache": "^4.1.3"
+			},
+			"engines": {
+				"node": ">=6.0.0"
+			}
+		},
+		"node_modules/named-placeholders/node_modules/lru-cache": {
+			"version": "4.1.5",
+			"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
+			"integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
+			"dependencies": {
+				"pseudomap": "^1.0.2",
+				"yallist": "^2.1.2"
+			}
+		},
+		"node_modules/named-placeholders/node_modules/yallist": {
+			"version": "2.1.2",
+			"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+			"integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A=="
+		},
+		"node_modules/node-domexception": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
+			"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
+			"funding": [
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/jimmywarting"
+				},
+				{
+					"type": "github",
+					"url": "https://paypal.me/jimmywarting"
+				}
+			],
+			"engines": {
+				"node": ">=10.5.0"
+			}
+		},
+		"node_modules/node-fetch": {
+			"version": "3.2.9",
+			"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.9.tgz",
+			"integrity": "sha512-/2lI+DBecVvVm9tDhjziTVjo2wmTsSxSk58saUYP0P/fRJ3xxtfMDY24+CKTkfm0Dlhyn3CSXNL0SoRiCZ8Rzg==",
+			"dependencies": {
+				"data-uri-to-buffer": "^4.0.0",
+				"fetch-blob": "^3.1.4",
+				"formdata-polyfill": "^4.0.10"
+			},
+			"engines": {
+				"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/node-fetch"
+			}
+		},
+		"node_modules/pseudomap": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+			"integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ=="
+		},
+		"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/seq-queue": {
+			"version": "0.0.5",
+			"resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz",
+			"integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="
+		},
+		"node_modules/tr46": {
+			"version": "0.0.3",
+			"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+			"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
+		},
+		"node_modules/ts-mixer": {
+			"version": "6.0.1",
+			"resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.1.tgz",
+			"integrity": "sha512-hvE+ZYXuINrx6Ei6D6hz+PTim0Uf++dYbK9FFifLNwQj+RwKquhQpn868yZsCtJYiclZF1u8l6WZxxKi+vv7Rg=="
+		},
+		"node_modules/tslib": {
+			"version": "2.4.0",
+			"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+			"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+		},
+		"node_modules/web-streams-polyfill": {
+			"version": "3.2.1",
+			"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
+			"integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==",
+			"engines": {
+				"node": ">= 8"
+			}
+		},
+		"node_modules/webidl-conversions": {
+			"version": "3.0.1",
+			"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+			"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
+		},
+		"node_modules/whatwg-url": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+			"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+			"dependencies": {
+				"tr46": "~0.0.3",
+				"webidl-conversions": "^3.0.0"
+			}
+		},
+		"node_modules/ws": {
+			"version": "8.8.1",
+			"resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz",
+			"integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==",
+			"engines": {
+				"node": ">=10.0.0"
+			},
+			"peerDependencies": {
+				"bufferutil": "^4.0.1",
+				"utf-8-validate": "^5.0.2"
+			},
+			"peerDependenciesMeta": {
+				"bufferutil": {
+					"optional": true
+				},
+				"utf-8-validate": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/yallist": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+			"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+		}
+	},
+	"dependencies": {
+		"@discordjs/builders": {
+			"version": "0.16.0",
+			"resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.16.0.tgz",
+			"integrity": "sha512-9/NCiZrLivgRub2/kBc0Vm5pMBE5AUdYbdXsLu/yg9ANgvnaJ0bZKTY8yYnLbsEc/LYUP79lEIdC73qEYhWq7A==",
+			"requires": {
+				"@sapphire/shapeshift": "^3.5.1",
+				"discord-api-types": "^0.36.2",
+				"fast-deep-equal": "^3.1.3",
+				"ts-mixer": "^6.0.1",
+				"tslib": "^2.4.0"
+			},
+			"dependencies": {
+				"discord-api-types": {
+					"version": "0.36.2",
+					"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.36.2.tgz",
+					"integrity": "sha512-TunPAvzwneK/m5fr4hxH3bMsrtI22nr9yjfHyo5NBGMjpsAauGNiGCmwoFf0oO3jSd2mZiKUvZwCKDaB166u2Q=="
+				}
+			}
+		},
+		"@discordjs/collection": {
+			"version": "0.7.0",
+			"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.7.0.tgz",
+			"integrity": "sha512-R5i8Wb8kIcBAFEPLLf7LVBQKBDYUL+ekb23sOgpkpyGT+V4P7V83wTxcsqmX+PbqHt4cEHn053uMWfRqh/Z/nA=="
+		},
+		"@sapphire/async-queue": {
+			"version": "1.3.1",
+			"resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.3.1.tgz",
+			"integrity": "sha512-FFTlPOWZX1kDj9xCAsRzH5xEJfawg1lNoYAA+ecOWJMHOfiZYb1uXOI3ne9U4UILSEPwfE68p3T9wUHwIQfR0g=="
+		},
+		"@sapphire/shapeshift": {
+			"version": "3.5.1",
+			"resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.5.1.tgz",
+			"integrity": "sha512-7JFsW5IglyOIUQI1eE0g6h06D/Far6HqpcowRScgCiLSqTf3hhkPWCWotVTtVycnDCMYIwPeaw6IEPBomKC8pA==",
+			"requires": {
+				"fast-deep-equal": "^3.1.3",
+				"lodash.uniqwith": "^4.5.0"
+			}
+		},
+		"@types/node": {
+			"version": "18.0.6",
+			"resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.6.tgz",
+			"integrity": "sha512-/xUq6H2aQm261exT6iZTMifUySEt4GR5KX8eYyY+C4MSNPqSh9oNIP7tz2GLKTlFaiBbgZNxffoR3CVRG+cljw=="
+		},
+		"@types/node-fetch": {
+			"version": "2.6.2",
+			"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz",
+			"integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==",
+			"requires": {
+				"@types/node": "*",
+				"form-data": "^3.0.0"
+			},
+			"dependencies": {
+				"form-data": {
+					"version": "3.0.1",
+					"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
+					"integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
+					"requires": {
+						"asynckit": "^0.4.0",
+						"combined-stream": "^1.0.8",
+						"mime-types": "^2.1.12"
+					}
+				}
+			}
+		},
+		"@types/ws": {
+			"version": "8.5.3",
+			"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz",
+			"integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==",
+			"requires": {
+				"@types/node": "*"
+			}
+		},
+		"asynckit": {
+			"version": "0.4.0",
+			"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+			"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
+		},
+		"combined-stream": {
+			"version": "1.0.8",
+			"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+			"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+			"requires": {
+				"delayed-stream": "~1.0.0"
+			}
+		},
+		"data-uri-to-buffer": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
+			"integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA=="
+		},
+		"delayed-stream": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+			"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
+		},
+		"denque": {
+			"version": "2.1.0",
+			"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
+			"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="
+		},
+		"discord-api-types": {
+			"version": "0.33.5",
+			"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.33.5.tgz",
+			"integrity": "sha512-dvO5M52v7m7Dy96+XUnzXNsQ/0npsYpU6dL205kAtEDueswoz3aU3bh1UMoK4cQmcGtB1YRyLKqp+DXi05lzFg=="
+		},
+		"discord.js": {
+			"version": "13.9.0",
+			"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.9.0.tgz",
+			"integrity": "sha512-QNscX8lQ2FwHuAd/NptQYc43oMUVijugir/vRbsTSgySidg8pcGQVqtRg8urqY3cbCOCZfNAMD/lR+SM7uijsA==",
+			"requires": {
+				"@discordjs/builders": "^0.16.0",
+				"@discordjs/collection": "^0.7.0",
+				"@sapphire/async-queue": "^1.3.1",
+				"@types/node-fetch": "^2.6.2",
+				"@types/ws": "^8.5.3",
+				"discord-api-types": "^0.33.3",
+				"form-data": "^4.0.0",
+				"node-fetch": "^2.6.7",
+				"ws": "^8.8.1"
+			},
+			"dependencies": {
+				"node-fetch": {
+					"version": "2.6.7",
+					"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+					"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+					"requires": {
+						"whatwg-url": "^5.0.0"
+					}
+				}
+			}
+		},
+		"dotenv": {
+			"version": "16.0.1",
+			"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz",
+			"integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ=="
+		},
+		"encoding": {
+			"version": "0.1.13",
+			"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
+			"integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
+			"optional": true,
+			"peer": true,
+			"requires": {
+				"iconv-lite": "^0.6.2"
+			}
+		},
+		"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=="
+		},
+		"fetch-blob": {
+			"version": "3.2.0",
+			"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
+			"integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
+			"requires": {
+				"node-domexception": "^1.0.0",
+				"web-streams-polyfill": "^3.0.3"
+			}
+		},
+		"form-data": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+			"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+			"requires": {
+				"asynckit": "^0.4.0",
+				"combined-stream": "^1.0.8",
+				"mime-types": "^2.1.12"
+			}
+		},
+		"formdata-polyfill": {
+			"version": "4.0.10",
+			"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
+			"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
+			"requires": {
+				"fetch-blob": "^3.1.2"
+			}
+		},
+		"fosscord-gopnik": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/fosscord-gopnik/-/fosscord-gopnik-1.0.0.tgz",
+			"integrity": "sha512-cCJhXTVOEDEhhSOwceYsptU3f97GOVOAVNJ4UFMiQESp4wnYE0GKnlYYYs6gMkZounxPEv0t22kSHdajx6Ed/w==",
+			"requires": {
+				"discord.js": "^13.5.1"
+			}
+		},
+		"generate-function": {
+			"version": "2.3.1",
+			"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz",
+			"integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==",
+			"requires": {
+				"is-property": "^1.0.2"
+			}
+		},
+		"iconv-lite": {
+			"version": "0.6.3",
+			"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+			"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+			"requires": {
+				"safer-buffer": ">= 2.1.2 < 3.0.0"
+			}
+		},
+		"is-property": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
+			"integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g=="
+		},
+		"lodash.uniqwith": {
+			"version": "4.5.0",
+			"resolved": "https://registry.npmjs.org/lodash.uniqwith/-/lodash.uniqwith-4.5.0.tgz",
+			"integrity": "sha512-7lYL8bLopMoy4CTICbxygAUq6CdRJ36vFc80DucPueUee+d5NBRxz3FdT9Pes/HEx5mPoT9jwnsEJWz1N7uq7Q=="
+		},
+		"long": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
+			"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
+		},
+		"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"
+			}
+		},
+		"mime-db": {
+			"version": "1.52.0",
+			"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+			"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
+		},
+		"mime-types": {
+			"version": "2.1.35",
+			"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+			"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+			"requires": {
+				"mime-db": "1.52.0"
+			}
+		},
+		"mysql2": {
+			"version": "2.3.3",
+			"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.3.3.tgz",
+			"integrity": "sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA==",
+			"requires": {
+				"denque": "^2.0.1",
+				"generate-function": "^2.3.1",
+				"iconv-lite": "^0.6.3",
+				"long": "^4.0.0",
+				"lru-cache": "^6.0.0",
+				"named-placeholders": "^1.1.2",
+				"seq-queue": "^0.0.5",
+				"sqlstring": "^2.3.2"
+			},
+			"dependencies": {
+				"sqlstring": {
+					"version": "2.3.3",
+					"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz",
+					"integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg=="
+				}
+			}
+		},
+		"named-placeholders": {
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz",
+			"integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==",
+			"requires": {
+				"lru-cache": "^4.1.3"
+			},
+			"dependencies": {
+				"lru-cache": {
+					"version": "4.1.5",
+					"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
+					"integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
+					"requires": {
+						"pseudomap": "^1.0.2",
+						"yallist": "^2.1.2"
+					}
+				},
+				"yallist": {
+					"version": "2.1.2",
+					"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+					"integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A=="
+				}
+			}
+		},
+		"node-domexception": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
+			"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="
+		},
+		"node-fetch": {
+			"version": "3.2.9",
+			"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.9.tgz",
+			"integrity": "sha512-/2lI+DBecVvVm9tDhjziTVjo2wmTsSxSk58saUYP0P/fRJ3xxtfMDY24+CKTkfm0Dlhyn3CSXNL0SoRiCZ8Rzg==",
+			"requires": {
+				"data-uri-to-buffer": "^4.0.0",
+				"fetch-blob": "^3.1.4",
+				"formdata-polyfill": "^4.0.10"
+			}
+		},
+		"pseudomap": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+			"integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ=="
+		},
+		"safer-buffer": {
+			"version": "2.1.2",
+			"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+			"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+		},
+		"seq-queue": {
+			"version": "0.0.5",
+			"resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz",
+			"integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="
+		},
+		"tr46": {
+			"version": "0.0.3",
+			"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+			"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
+		},
+		"ts-mixer": {
+			"version": "6.0.1",
+			"resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.1.tgz",
+			"integrity": "sha512-hvE+ZYXuINrx6Ei6D6hz+PTim0Uf++dYbK9FFifLNwQj+RwKquhQpn868yZsCtJYiclZF1u8l6WZxxKi+vv7Rg=="
+		},
+		"tslib": {
+			"version": "2.4.0",
+			"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+			"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+		},
+		"web-streams-polyfill": {
+			"version": "3.2.1",
+			"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
+			"integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q=="
+		},
+		"webidl-conversions": {
+			"version": "3.0.1",
+			"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+			"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
+		},
+		"whatwg-url": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+			"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+			"requires": {
+				"tr46": "~0.0.3",
+				"webidl-conversions": "^3.0.0"
+			}
+		},
+		"ws": {
+			"version": "8.8.1",
+			"resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz",
+			"integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==",
+			"requires": {}
+		},
+		"yallist": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+			"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+		}
+	}
+}
diff --git a/slowcord/status/package.json b/slowcord/status/package.json
new file mode 100644
index 00000000..c6af6f65
--- /dev/null
+++ b/slowcord/status/package.json
@@ -0,0 +1,30 @@
+{
+	"name": "slowcord-status",
+	"version": "1.0.0",
+	"description": "Slowcord status service",
+	"main": "build/index.js",
+	"scripts": {
+		"build": "tsc -b",
+		"start": "node build/index.js"
+	},
+	"repository": {
+		"type": "git",
+		"url": "git+https://github.com/maddyunderstars/fosscord-server.git"
+	},
+	"bugs": {
+		"url": "https://github.com/maddyunderstars/fosscord-server/issues"
+	},
+	"homepage": "https://github.com/maddyunderstars/fosscord-server#readme",
+	"author": "MaddyUnderStars",
+	"license": "AGPL-3.0-only",
+	"devDependencies": {
+		"@types/node": "^18.0.6"
+	},
+	"dependencies": {
+		"dotenv": "^16.0.1",
+		"fosscord-gopnik": "^1.0.0",
+		"mysql2": "^2.3.3",
+		"node-fetch": "^3.2.9"
+	},
+	"type": "module"
+}
diff --git a/slowcord/status/src/index.ts b/slowcord/status/src/index.ts
new file mode 100644
index 00000000..a4d911ad
--- /dev/null
+++ b/slowcord/status/src/index.ts
@@ -0,0 +1,91 @@
+import "dotenv/config";
+import fetch from "node-fetch";
+import Fosscord from "fosscord-gopnik";
+import mysql from "mysql2";
+
+const dbConn = mysql.createConnection(process.env.DATABASE as string);
+const executePromise = (sql: string, args: any[]) => new Promise((resolve, reject) => dbConn.execute(sql, args, (err, res) => { if (err) reject(err); else resolve(res); }));
+
+const instance = {
+	api: process.env.INSTANCE_API as string,
+	cdn: process.env.INSTANCE_CDN as string,
+	token: process.env.INSTANCE_TOKEN as string,
+};
+
+const client = new Fosscord.Client({
+	intents: [],
+	http: {
+		api: instance.api,
+		cdn: instance.cdn
+	}
+});
+
+client.on("ready", () => {
+	console.log(`Ready on gateway as ${client.user!.tag}`);
+
+	const gatewayMeasure = async (name: string) => {
+		const time = Math.max(client.ws.ping, 0);
+		await savePerf(time, name, null);
+		console.log(`${name} took ${time}ms`);
+		setTimeout(gatewayMeasure, parseInt(process.env.MEASURE_INTERVAL as string), name);
+	};
+
+	gatewayMeasure("websocketPing")
+});
+
+client.on("error", (error) => {
+	console.log(`Gateway error`, error);
+});
+
+client.on("warn", (msg) => {
+	console.log(`Gateway warning:`, msg);
+});
+
+const savePerf = async (time: number, name: string, error: string | null) => {
+	try {
+		await executePromise("INSERT INTO performance (value, endpoint, timestamp, error) VALUES (?, ?, ?, ?)", [time, name, new Date(), error]);
+		await executePromise("DELETE FROM performance WHERE DATE(timestamp) < now() - interval ? DAY", [process.env.RETENTION_DAYS]);
+	}
+	catch (e) {
+		console.error(e);
+	}
+};
+
+const measureApi = async (name: string, path: string, body?: object) => {
+	const start = Date.now();
+
+	let error: Error | null = null;
+	try {
+		const res = await fetch(path, {
+			headers: {
+				"Content-Type": "application/json",
+				"Authorization": instance.token,
+			},
+			body: body ? JSON.stringify(body) : undefined,
+		});
+		await res.json();
+	}
+	catch (e) {
+		error = e as Error;
+	}
+
+	const time = Date.now() - start;
+	console.log(`${name} took ${time}ms ${(error ? "with error" : "")}`, error ?? "");
+
+	await savePerf(time, name, error?.message ?? null);
+
+	setTimeout(measureApi, parseInt(process.env.MEASURE_INTERVAL as string), name, path, body);
+};
+
+const app = async () => {
+	await new Promise((resolve) => dbConn.connect(resolve));
+	console.log("Connected to db");
+	await client.login(instance.token);
+
+	console.log(`Monitoring performance for instance at ${new URL(instance.api).hostname}`);
+
+	measureApi("ping", `${instance.api}/ping`);
+	measureApi("users/@me", `${instance.api}/users/@me`);
+};
+
+app();
\ No newline at end of file
diff --git a/slowcord/status/tsconfig.json b/slowcord/status/tsconfig.json
new file mode 100644
index 00000000..6d6ec56d
--- /dev/null
+++ b/slowcord/status/tsconfig.json
@@ -0,0 +1,99 @@
+{
+	"exclude": [
+		"node_modules"
+	],
+	"include": [
+		"src/**/*.ts"
+	],
+	"compilerOptions": {
+		/* Visit https://aka.ms/tsconfig.json to read more about this file */
+		/* Projects */
+		// "incremental": true,                              /* Enable incremental compilation */
+		// "composite": true,                                /* Enable constraints that allow a TypeScript project to be used with project references. */
+		// "tsBuildInfoFile": "./",                          /* Specify the folder for .tsbuildinfo incremental compilation files. */
+		// "disableSourceOfProjectReferenceRedirect": true,  /* Disable preferring source files instead of declaration files when referencing composite projects */
+		// "disableSolutionSearching": true,                 /* Opt a project out of multi-project reference checking when editing. */
+		// "disableReferencedProjectLoad": true,             /* Reduce the number of projects loaded automatically by TypeScript. */
+		/* Language and Environment */
+		"target": "ES6", 								 /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
+		"lib": ["ES2021"],                                        /* Specify a set of bundled library declaration files that describe the target runtime environment. */
+		// "jsx": "preserve",                                /* Specify what JSX code is generated. */
+		"experimentalDecorators": true,                   /* Enable experimental support for TC39 stage 2 draft decorators. */
+		// "emitDecoratorMetadata": true,                    /* Emit design-type metadata for decorated declarations in source files. */
+		// "jsxFactory": "",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
+		// "jsxFragmentFactory": "",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
+		// "jsxImportSource": "",                            /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
+		// "reactNamespace": "",                             /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
+		// "noLib": true,                                    /* Disable including any library files, including the default lib.d.ts. */
+		// "useDefineForClassFields": true,                  /* Emit ECMAScript-standard-compliant class fields. */
+		/* Modules */
+		"module": "ES2020", 								 /* Specify what module code is generated. */
+		// "rootDir": "./",                                  /* Specify the root folder within your source files. */
+		"moduleResolution": "node",                       /* Specify how TypeScript looks up a file from a given module specifier. */
+		// "baseUrl": "./",                                  /* Specify the base directory to resolve non-relative module names. */
+		// "paths": {},                                      /* Specify a set of entries that re-map imports to additional lookup locations. */
+		// "rootDirs": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */
+		// "typeRoots": [],                                  /* Specify multiple folders that act like `./node_modules/@types`. */
+		"types": ["node"],                                      /* Specify type package names to be included without being referenced in a source file. */
+		// "allowUmdGlobalAccess": true,                     /* Allow accessing UMD globals from modules. */
+		// "resolveJsonModule": true,                        /* Enable importing .json files */
+		// "noResolve": true,                                /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
+		/* JavaScript Support */
+		// "allowJs": true,                                  /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
+		// "checkJs": true,                                  /* Enable error reporting in type-checked JavaScript files. */
+		// "maxNodeModuleJsDepth": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
+		/* Emit */
+		// "declaration": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
+		// "declarationMap": true,                           /* Create sourcemaps for d.ts files. */
+		// "emitDeclarationOnly": true,                      /* Only output d.ts files and not JavaScript files. */
+		"sourceMap": true,                                /* Create source map files for emitted JavaScript files. */
+		// "outFile": "./",                                  /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
+		"outDir": "./build",                                   /* Specify an output folder for all emitted files. */
+		// "removeComments": true,                           /* Disable emitting comments. */
+		// "noEmit": true,                                   /* Disable emitting files from a compilation. */
+		// "importHelpers": true,                            /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
+		// "importsNotUsedAsValues": "remove",               /* Specify emit/checking behavior for imports that are only used for types */
+		// "downlevelIteration": true,                       /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
+		// "sourceRoot": "",                                 /* Specify the root path for debuggers to find the reference source code. */
+		// "mapRoot": "",                                    /* Specify the location where debugger should locate map files instead of generated locations. */
+		// "inlineSourceMap": true,                          /* Include sourcemap files inside the emitted JavaScript. */
+		// "inlineSources": true,                            /* Include source code in the sourcemaps inside the emitted JavaScript. */
+		// "emitBOM": true,                                  /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
+		// "newLine": "crlf",                                /* Set the newline character for emitting files. */
+		// "stripInternal": true,                            /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
+		// "noEmitHelpers": true,                            /* Disable generating custom helper functions like `__extends` in compiled output. */
+		// "noEmitOnError": true,                            /* Disable emitting files if any type checking errors are reported. */
+		// "preserveConstEnums": true,                       /* Disable erasing `const enum` declarations in generated code. */
+		// "declarationDir": "./",                           /* Specify the output directory for generated declaration files. */
+		// "preserveValueImports": true,                     /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
+		/* Interop Constraints */
+		// "isolatedModules": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */
+		// "allowSyntheticDefaultImports": true,             /* Allow 'import x from y' when a module doesn't have a default export. */
+		"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
+		// "preserveSymlinks": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
+		"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
+		/* Type Checking */
+		"strict": true, /* Enable all strict type-checking options. */
+		// "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied `any` type.. */
+		// "strictNullChecks": true,                         /* When type checking, take into account `null` and `undefined`. */
+		// "strictFunctionTypes": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
+		// "strictBindCallApply": true,                      /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
+		"strictPropertyInitialization": false,               /* Check for class properties that are declared but not set in the constructor. */
+		// "noImplicitThis": true,                           /* Enable error reporting when `this` is given the type `any`. */
+		// "useUnknownInCatchVariables": true,               /* Type catch clause variables as 'unknown' instead of 'any'. */
+		// "alwaysStrict": true,                             /* Ensure 'use strict' is always emitted. */
+		// "noUnusedLocals": true,                           /* Enable error reporting when a local variables aren't read. */
+		// "noUnusedParameters": true,                       /* Raise an error when a function parameter isn't read */
+		// "exactOptionalPropertyTypes": true,               /* Interpret optional property types as written, rather than adding 'undefined'. */
+		// "noImplicitReturns": true,                        /* Enable error reporting for codepaths that do not explicitly return in a function. */
+		// "noFallthroughCasesInSwitch": true,               /* Enable error reporting for fallthrough cases in switch statements. */
+		// "noUncheckedIndexedAccess": true,                 /* Include 'undefined' in index signature results */
+		// "noImplicitOverride": true,                       /* Ensure overriding members in derived classes are marked with an override modifier. */
+		// "noPropertyAccessFromIndexSignature": true,       /* Enforces using indexed accessors for keys declared using an indexed type */
+		// "allowUnusedLabels": true,                        /* Disable error reporting for unused labels. */
+		// "allowUnreachableCode": true,                     /* Disable error reporting for unreachable code. */
+		/* Completeness */
+		// "skipDefaultLibCheck": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */
+		"skipLibCheck": true /* Skip type checking all .d.ts files. */
+	}
+}
\ No newline at end of file