diff --git a/api/.dockerignore b/api/.dockerignore
new file mode 100644
index 00000000..b512c09d
--- /dev/null
+++ b/api/.dockerignore
@@ -0,0 +1 @@
+node_modules
\ No newline at end of file
diff --git a/api/.gitignore b/api/.gitignore
new file mode 100644
index 00000000..9a734d3c
--- /dev/null
+++ b/api/.gitignore
@@ -0,0 +1,51 @@
+# Environmente File
+.env
+
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# Gradle
+/build/
+/.gradle/
+/out/
+gradle.properties
+/node_modules/
+
+# IntelliJ IDEA
+/.idea/
+*.iml
+*.ipr
+*.iws
+
+# Eclipse
+.classpath
+.project
+.settings/
+/bin/
+
+# Logging Stuff
+/logs/
+
+# Mac Stuff
+.DS_Store
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
\ No newline at end of file
diff --git a/api/Dockerfile b/api/Dockerfile
new file mode 100644
index 00000000..45b3de70
--- /dev/null
+++ b/api/Dockerfile
@@ -0,0 +1,6 @@
+FROM node:16-slim
+WORKDIR /app
+COPY package.json /app
+RUN npm install
+COPY . /app
+CMD ["npm", "start"]
\ No newline at end of file
diff --git a/api/app.js b/api/app.js
new file mode 100644
index 00000000..04a71364
--- /dev/null
+++ b/api/app.js
@@ -0,0 +1,109 @@
+// - [ ] Changed Port
+// - [ ] Changed MySQL Info and Port
+// - [ ] Changed Token
+
+// Load Our App Server Using Express
+const express = require('express');
+const app = express();
+const morgan = require('morgan');
+const body_parser = require('body-parser');
+const checkType = require('./middleware/check-type');
+const server_port = 5100;
+
+// Body Parser - Extracts JSON Data
+app.use(body_parser.urlencoded({extended: false}));
+app.use(body_parser.json());
+
+// Now serving everything in the public directory.
+app.use(express.static('./public'));
+
+// app.use(morgan('combined'));
+app.use(morgan('short'));
+
+// Base Directory
+app.get("/", (request, response, next) => {
+ console.log("Responding to Route");
+ response.send("Hello from beanbeanjuice!");
+});
+
+// Preventing CORS Errors
+app.use((request, response, next) => {
+ response.header('Access-Control-Allow-Origin', '*');
+ response.header('Access-Control-Allow-Headers',
+ "Origin, X-Requested-With, Content-Type, Accept, Authorization"
+ );
+
+ if (request.method === 'OPTIONS') {
+ response.header('Access-Control-Allow-Methods', 'PUT, POST, PATCH, DELETE, GET');
+ return response.status(200).json({});
+ }
+ next();
+});
+
+const cafe_api_url = "/cafe/api/v1"
+const cafe_user_router = require('./routes/cafe/user.js');
+app.use(cafe_api_url, cafe_user_router);
+
+const cafe_bot_api_url = "/cafeBot/api/v1";
+const beanCoins_router = require('./routes/cafeBot/beanCoins.js');
+const birthdays_router = require('./routes/cafeBot/birthdays.js');
+const cafe_router = require('./routes/cafeBot/cafe.js');
+const cafeBot_router = require('./routes/cafeBot/cafeBot.js');
+const codes_router = require('./routes/cafeBot/codes.js');
+const counting_router = require('./routes/cafeBot/counting.js');
+const guild_twitch_router = require('./routes/cafeBot/guild_twitch.js');
+const guilds_router = require('./routes/cafeBot/guilds.js');
+const interactions_router = require('./routes/cafeBot/interactions.js');
+const minigames_router = require('./routes/cafeBot/minigames.js');
+const polls_router = require('./routes/cafeBot/polls.js');
+const raffles_router = require('./routes/cafeBot/raffles.js');
+const voice_binds_router = require('./routes/cafeBot/voice_binds.js');
+const welcomes_router = require('./routes/cafeBot/welcomes.js');
+const goodbyes_router = require('./routes/cafeBot/goodbyes.js');
+const words_router = require('./routes/cafeBot/words.js');
+app.use(cafe_bot_api_url, beanCoins_router);
+app.use(cafe_bot_api_url, birthdays_router);
+app.use(cafe_bot_api_url, cafe_router);
+app.use(cafe_bot_api_url, cafeBot_router);
+app.use(cafe_bot_api_url, codes_router);
+app.use(cafe_bot_api_url, counting_router);
+app.use(cafe_bot_api_url, guild_twitch_router);
+app.use(cafe_bot_api_url, guilds_router);
+app.use(cafe_bot_api_url, interactions_router);
+app.use(cafe_bot_api_url, minigames_router);
+app.use(cafe_bot_api_url, polls_router);
+app.use(cafe_bot_api_url, raffles_router);
+app.use(cafe_bot_api_url, voice_binds_router);
+app.use(cafe_bot_api_url, welcomes_router);
+app.use(cafe_bot_api_url, goodbyes_router);
+app.use(cafe_bot_api_url, words_router);
+
+const interaction_pictures_router = require('./routes/cafeBot/interaction_pictures/interaction_pictures.js');
+app.use(cafe_bot_api_url, interaction_pictures_router);
+
+const boggle_api_url = "/boggle/api/v1"
+const boggle_game_router = require('./routes/boggle/game.js');
+const boggle_user_settings_router = require('./routes/boggle/settings.js');
+app.use(boggle_api_url, boggle_game_router);
+app.use(boggle_api_url, boggle_user_settings_router);
+
+// Catches Errors that Have No Routes
+app.use((request, response, next) => {
+ console.log("There has been an error. Route not found.");
+ const error = new Error("Route Not Found");
+ error.status = 404;
+ next(error);
+});
+
+// Catches ALL Errors
+app.use((error, request, response, next) => {
+ response.status(error.status || 500);
+ response.json({
+ message: error.message
+ });
+});
+
+// Ping @ localhost:5101
+app.listen(server_port, () => {
+ console.log("Server is up on " + checkType.RELEASE_TYPE + " and listening on port: " + server_port);
+});
diff --git a/api/middleware/check-admin.js b/api/middleware/check-admin.js
new file mode 100644
index 00000000..a0fc5ed5
--- /dev/null
+++ b/api/middleware/check-admin.js
@@ -0,0 +1,17 @@
+module.exports = (request, response, next) => {
+ try {
+ user_type = request.user_data.user_type;
+
+ if (user_type === 'ADMIN') {
+ next();
+ } else {
+ response.status(401).json({
+ message: "Authentication Failed"
+ });
+ }
+ } catch (error) {
+ return response.status(401).json({
+ message: "Authentication Failed"
+ });
+ }
+};
diff --git a/api/middleware/check-auth.js b/api/middleware/check-auth.js
new file mode 100644
index 00000000..78073046
--- /dev/null
+++ b/api/middleware/check-auth.js
@@ -0,0 +1,17 @@
+const jwt = require('jsonwebtoken');
+const checkType = require('../middleware/check-type');
+
+const TOKEN = checkType.TOKEN;
+
+module.exports = (request, response, next) => {
+ try {
+ const token = request.headers.authorization;
+ const decoded_token = jwt.verify(token, TOKEN);
+ request.user_data = decoded_token;
+ next(); // Called if successfully authenticated.
+ } catch (error) {
+ return response.status(401).json({
+ message: "Authentication Failed"
+ });
+ }
+};
diff --git a/api/middleware/check-type.js b/api/middleware/check-type.js
new file mode 100644
index 00000000..85cede1a
--- /dev/null
+++ b/api/middleware/check-type.js
@@ -0,0 +1,24 @@
+require('dotenv').config();
+
+const RELEASE_TYPE = process.env.API_REQUEST_LOCATION;
+
+if (RELEASE_TYPE === undefined) {
+ throw new Error('RELEASE_TYPE should be `BETA` or `RELEASE`.');
+}
+
+const TOKEN = process.env.JWT_TOKEN;
+
+function getMySQLData() {
+ return {
+ "url": process.env.MYSQL_URL,
+ "port": process.env.MYSQL_PORT,
+ "user": process.env.MYSQL_USER,
+ "password": process.env.MYSQL_PASSWORD
+ }
+}
+
+module.exports = {
+ getMySQLData,
+ RELEASE_TYPE,
+ TOKEN
+}
diff --git a/api/package-lock.json b/api/package-lock.json
new file mode 100644
index 00000000..e5de6943
--- /dev/null
+++ b/api/package-lock.json
@@ -0,0 +1,3316 @@
+{
+ "name": "cafe-api",
+ "version": "1.1.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "cafe-api",
+ "version": "1.1.0",
+ "license": "ISC",
+ "dependencies": {
+ "bcrypt": "^5.0.1",
+ "body-parser": "^1.19.0",
+ "dotenv": "^10.0.0",
+ "express": "^4.17.1",
+ "jsonwebtoken": "^9.0.2",
+ "morgan": "^1.10.0",
+ "mysql2": "^3.11.0",
+ "nodemon": "^3.1.4"
+ }
+ },
+ "node_modules/@mapbox/node-pre-gyp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz",
+ "integrity": "sha512-4srsKPXWlIxp5Vbqz5uLfBN+du2fJChBoYn/f2h991WLdk7jUvcSk/McVLSv/X+xQIPI8eGD5GjrnygdyHnhPA==",
+ "dependencies": {
+ "detect-libc": "^1.0.3",
+ "https-proxy-agent": "^5.0.0",
+ "make-dir": "^3.1.0",
+ "node-fetch": "^2.6.1",
+ "nopt": "^5.0.0",
+ "npmlog": "^4.1.2",
+ "rimraf": "^3.0.2",
+ "semver": "^7.3.4",
+ "tar": "^6.1.0"
+ },
+ "bin": {
+ "node-pre-gyp": "bin/node-pre-gyp"
+ }
+ },
+ "node_modules/abbrev": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
+ },
+ "node_modules/accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ },
+ "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/ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
+ "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/aproba": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+ "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
+ },
+ "node_modules/are-we-there-yet": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
+ "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
+ "dependencies": {
+ "delegates": "^1.0.0",
+ "readable-stream": "^2.0.6"
+ }
+ },
+ "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/aws-ssl-profiles": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.1.tgz",
+ "integrity": "sha512-+H+kuK34PfMaI9PNU/NSjBKL5hh/KDM9J72kwYeYEm0A8B1AC4fuCy3qsjnA7lxklgyXsB68yn8Z2xoZEjgwCQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6.0.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/basic-auth": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
+ "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
+ "dependencies": {
+ "safe-buffer": "5.1.2"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/bcrypt": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.0.1.tgz",
+ "integrity": "sha512-9BTgmrhZM2t1bNuDtrtIMVSmmxZBrJ71n8Wg+YgdjHuIWYF7SjjmCPZFB+/5i/o/PIeRpwVJR3P+NrpIItUjqw==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@mapbox/node-pre-gyp": "^1.0.0",
+ "node-addon-api": "^3.1.0"
+ },
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/body-parser": {
+ "version": "1.20.2",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
+ "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "content-type": "~1.0.5",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "on-finished": "2.4.1",
+ "qs": "6.11.0",
+ "raw-body": "2.5.2",
+ "type-is": "~1.6.18",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/body-parser/node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "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/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "license": "MIT",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "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/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
+ "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
+ "license": "MIT",
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "set-function-length": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
+ "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==",
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/chownr": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
+ "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/code-point-at": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "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/console-control-strings": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+ "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
+ },
+ "node_modules/content-disposition": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "5.2.1"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-disposition/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==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
+ "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
+ "license": "MIT",
+ "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/define-data-property": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+ "license": "MIT",
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/delegates": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+ "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
+ },
+ "node_modules/denque": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
+ "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/destroy": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/detect-libc": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+ "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
+ "bin": {
+ "detect-libc": "bin/detect-libc.js"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/dotenv": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
+ "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/ecdsa-sig-formatter": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+ "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+ },
+ "node_modules/encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
+ "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
+ "license": "MIT",
+ "dependencies": {
+ "get-intrinsic": "^1.2.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+ "license": "MIT"
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/express": {
+ "version": "4.19.2",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
+ "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
+ "license": "MIT",
+ "dependencies": {
+ "accepts": "~1.3.8",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.20.2",
+ "content-disposition": "0.5.4",
+ "content-type": "~1.0.4",
+ "cookie": "0.6.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "1.2.0",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.7",
+ "qs": "6.11.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.2.1",
+ "send": "0.18.0",
+ "serve-static": "1.15.0",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/express/node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/express/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==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "license": "MIT",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
+ "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "statuses": "2.0.1",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/finalhandler/node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.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": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fs-minipass": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
+ "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
+ "dependencies": {
+ "minipass": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "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/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/gauge": {
+ "version": "2.7.4",
+ "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
+ "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+ "dependencies": {
+ "aproba": "^1.0.3",
+ "console-control-strings": "^1.0.0",
+ "has-unicode": "^2.0.0",
+ "object-assign": "^4.1.0",
+ "signal-exit": "^3.0.0",
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1",
+ "wide-align": "^1.1.0"
+ }
+ },
+ "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/get-intrinsic": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
+ "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "has-proto": "^1.0.1",
+ "has-symbols": "^1.0.3",
+ "hasown": "^2.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+ "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+ "license": "MIT",
+ "dependencies": {
+ "get-intrinsic": "^1.1.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/has-property-descriptors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "license": "MIT",
+ "dependencies": {
+ "es-define-property": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-proto": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
+ "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-unicode": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+ "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "license": "MIT",
+ "dependencies": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "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==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ignore-by-default": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
+ "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk="
+ },
+ "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.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "license": "ISC"
+ },
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "dependencies": {
+ "number-is-nan": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+ "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-property": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
+ "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ="
+ },
+ "node_modules/isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+ },
+ "node_modules/jsonwebtoken": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
+ "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
+ "license": "MIT",
+ "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": "^7.5.4"
+ },
+ "engines": {
+ "node": ">=12",
+ "npm": ">=6"
+ }
+ },
+ "node_modules/jsonwebtoken/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
+ "node_modules/jwa": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
+ "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
+ "dependencies": {
+ "buffer-equal-constant-time": "1.0.1",
+ "ecdsa-sig-formatter": "1.0.11",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/jws": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
+ "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+ "dependencies": {
+ "jwa": "^1.4.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/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/long": {
+ "version": "5.2.3",
+ "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
+ "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/lru-cache": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-8.0.5.tgz",
+ "integrity": "sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=16.14"
+ }
+ },
+ "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.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "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/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==",
+ "license": "MIT",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "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==",
+ "license": "MIT",
+ "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==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minipass": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz",
+ "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==",
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/minizlib": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
+ "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
+ "dependencies": {
+ "minipass": "^3.0.0",
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "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/morgan": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz",
+ "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==",
+ "dependencies": {
+ "basic-auth": "~2.0.1",
+ "debug": "2.6.9",
+ "depd": "~2.0.0",
+ "on-finished": "~2.3.0",
+ "on-headers": "~1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ },
+ "node_modules/mysql2": {
+ "version": "3.11.0",
+ "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.11.0.tgz",
+ "integrity": "sha512-J9phbsXGvTOcRVPR95YedzVSxJecpW5A5+cQ57rhHIFXteTP10HCs+VBjS7DHIKfEaI1zQ5tlVrquCd64A6YvA==",
+ "license": "MIT",
+ "dependencies": {
+ "aws-ssl-profiles": "^1.1.1",
+ "denque": "^2.1.0",
+ "generate-function": "^2.3.1",
+ "iconv-lite": "^0.6.3",
+ "long": "^5.2.1",
+ "lru-cache": "^8.0.0",
+ "named-placeholders": "^1.1.3",
+ "seq-queue": "^0.0.5",
+ "sqlstring": "^2.3.2"
+ },
+ "engines": {
+ "node": ">= 8.0"
+ }
+ },
+ "node_modules/mysql2/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/mysql2/node_modules/sqlstring": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.2.tgz",
+ "integrity": "sha512-vF4ZbYdKS8OnoJAWBmMxCQDkiEBkGQYU7UZPtL8flbDRSNkhaXvRJ279ZtI6M+zDaQovVU4tuRgzK5fVhvFAhg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/named-placeholders": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz",
+ "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==",
+ "license": "MIT",
+ "dependencies": {
+ "lru-cache": "^7.14.1"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/named-placeholders/node_modules/lru-cache": {
+ "version": "7.18.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
+ "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/node-addon-api": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz",
+ "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A=="
+ },
+ "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/nodemon": {
+ "version": "3.1.4",
+ "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.4.tgz",
+ "integrity": "sha512-wjPBbFhtpJwmIeY2yP7QF+UKzPfltVGtfce1g/bB15/8vCGZj8uxD62b/b9M9/WVgme0NZudpownKN+c0plXlQ==",
+ "license": "MIT",
+ "dependencies": {
+ "chokidar": "^3.5.2",
+ "debug": "^4",
+ "ignore-by-default": "^1.0.1",
+ "minimatch": "^3.1.2",
+ "pstree.remy": "^1.1.8",
+ "semver": "^7.5.3",
+ "simple-update-notifier": "^2.0.0",
+ "supports-color": "^5.5.0",
+ "touch": "^3.1.0",
+ "undefsafe": "^2.0.5"
+ },
+ "bin": {
+ "nodemon": "bin/nodemon.js"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/nodemon"
+ }
+ },
+ "node_modules/nodemon/node_modules/debug": {
+ "version": "4.3.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
+ "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/nodemon/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==",
+ "license": "MIT"
+ },
+ "node_modules/nopt": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
+ "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
+ "dependencies": {
+ "abbrev": "1"
+ },
+ "bin": {
+ "nopt": "bin/nopt.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npmlog": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
+ "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+ "dependencies": {
+ "are-we-there-yet": "~1.1.2",
+ "console-control-strings": "~1.1.0",
+ "gauge": "~2.7.3",
+ "set-blocking": "~2.0.0"
+ }
+ },
+ "node_modules/number-is-nan": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz",
+ "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/on-headers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
+ "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
+ "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/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.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/picomatch": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
+ "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "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/pstree.remy": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
+ "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w=="
+ },
+ "node_modules/qs": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+ "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.0.4"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
+ "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "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/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "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/semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/send": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
+ "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/send/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT"
+ },
+ "node_modules/send/node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/seq-queue": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz",
+ "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4="
+ },
+ "node_modules/serve-static": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
+ "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
+ "license": "MIT",
+ "dependencies": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.18.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
+ },
+ "node_modules/set-function-length": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+ "license": "MIT",
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "gopd": "^1.0.1",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+ "license": "ISC"
+ },
+ "node_modules/side-channel": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
+ "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.4",
+ "object-inspect": "^1.13.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/signal-exit": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
+ "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA=="
+ },
+ "node_modules/simple-update-notifier": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
+ "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
+ "license": "MIT",
+ "dependencies": {
+ "semver": "^7.5.3"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "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-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "dependencies": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dependencies": {
+ "ansi-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/tar": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
+ "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
+ "license": "ISC",
+ "dependencies": {
+ "chownr": "^2.0.0",
+ "fs-minipass": "^2.0.0",
+ "minipass": "^5.0.0",
+ "minizlib": "^2.1.1",
+ "mkdirp": "^1.0.3",
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/tar/node_modules/minipass": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
+ "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "license": "MIT",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/touch": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
+ "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
+ "dependencies": {
+ "nopt": "~1.0.10"
+ },
+ "bin": {
+ "nodetouch": "bin/nodetouch.js"
+ }
+ },
+ "node_modules/touch/node_modules/nopt": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
+ "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=",
+ "dependencies": {
+ "abbrev": "1"
+ },
+ "bin": {
+ "nopt": "bin/nopt.js"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
+ },
+ "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/undefsafe": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
+ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA=="
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "license": "MIT",
+ "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/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/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/wide-align": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
+ "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
+ "dependencies": {
+ "string-width": "^1.0.2 || 2"
+ }
+ },
+ "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=="
+ }
+ },
+ "dependencies": {
+ "@mapbox/node-pre-gyp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz",
+ "integrity": "sha512-4srsKPXWlIxp5Vbqz5uLfBN+du2fJChBoYn/f2h991WLdk7jUvcSk/McVLSv/X+xQIPI8eGD5GjrnygdyHnhPA==",
+ "requires": {
+ "detect-libc": "^1.0.3",
+ "https-proxy-agent": "^5.0.0",
+ "make-dir": "^3.1.0",
+ "node-fetch": "^2.6.1",
+ "nopt": "^5.0.0",
+ "npmlog": "^4.1.2",
+ "rimraf": "^3.0.2",
+ "semver": "^7.3.4",
+ "tar": "^6.1.0"
+ }
+ },
+ "abbrev": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
+ },
+ "accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "requires": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ }
+ },
+ "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=="
+ }
+ }
+ },
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+ },
+ "anymatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
+ "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
+ "requires": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ }
+ },
+ "aproba": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+ "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
+ },
+ "are-we-there-yet": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
+ "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
+ "requires": {
+ "delegates": "^1.0.0",
+ "readable-stream": "^2.0.6"
+ }
+ },
+ "array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+ },
+ "aws-ssl-profiles": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.1.tgz",
+ "integrity": "sha512-+H+kuK34PfMaI9PNU/NSjBKL5hh/KDM9J72kwYeYEm0A8B1AC4fuCy3qsjnA7lxklgyXsB68yn8Z2xoZEjgwCQ=="
+ },
+ "balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+ },
+ "basic-auth": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
+ "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
+ "requires": {
+ "safe-buffer": "5.1.2"
+ }
+ },
+ "bcrypt": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.0.1.tgz",
+ "integrity": "sha512-9BTgmrhZM2t1bNuDtrtIMVSmmxZBrJ71n8Wg+YgdjHuIWYF7SjjmCPZFB+/5i/o/PIeRpwVJR3P+NrpIItUjqw==",
+ "requires": {
+ "@mapbox/node-pre-gyp": "^1.0.0",
+ "node-addon-api": "^3.1.0"
+ }
+ },
+ "binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="
+ },
+ "body-parser": {
+ "version": "1.20.2",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
+ "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
+ "requires": {
+ "bytes": "3.1.2",
+ "content-type": "~1.0.5",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "on-finished": "2.4.1",
+ "qs": "6.11.0",
+ "raw-body": "2.5.2",
+ "type-is": "~1.6.18",
+ "unpipe": "1.0.0"
+ },
+ "dependencies": {
+ "on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ }
+ }
+ },
+ "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"
+ }
+ },
+ "braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "requires": {
+ "fill-range": "^7.1.1"
+ }
+ },
+ "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="
+ },
+ "bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
+ },
+ "call-bind": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
+ "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
+ "requires": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "set-function-length": "^1.2.1"
+ }
+ },
+ "chokidar": {
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
+ "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==",
+ "requires": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "fsevents": "~2.3.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ }
+ },
+ "chownr": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
+ "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="
+ },
+ "code-point-at": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+ },
+ "console-control-strings": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+ "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
+ },
+ "content-disposition": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+ "requires": {
+ "safe-buffer": "5.2.1"
+ },
+ "dependencies": {
+ "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=="
+ }
+ }
+ },
+ "content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="
+ },
+ "cookie": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
+ "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw=="
+ },
+ "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"
+ }
+ },
+ "define-data-property": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+ "requires": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.0.1"
+ }
+ },
+ "delegates": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+ "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
+ },
+ "denque": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
+ "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="
+ },
+ "depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
+ },
+ "destroy": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
+ },
+ "detect-libc": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+ "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
+ },
+ "dotenv": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
+ "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q=="
+ },
+ "ecdsa-sig-formatter": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+ "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+ "requires": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+ },
+ "encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="
+ },
+ "es-define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
+ "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
+ "requires": {
+ "get-intrinsic": "^1.2.4"
+ }
+ },
+ "es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="
+ },
+ "escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
+ },
+ "etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="
+ },
+ "express": {
+ "version": "4.19.2",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
+ "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
+ "requires": {
+ "accepts": "~1.3.8",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.20.2",
+ "content-disposition": "0.5.4",
+ "content-type": "~1.0.4",
+ "cookie": "0.6.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "1.2.0",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.7",
+ "qs": "6.11.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.2.1",
+ "send": "0.18.0",
+ "serve-static": "1.15.0",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "dependencies": {
+ "on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ },
+ "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=="
+ }
+ }
+ },
+ "fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
+ "finalhandler": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
+ "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+ "requires": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "statuses": "2.0.1",
+ "unpipe": "~1.0.0"
+ },
+ "dependencies": {
+ "on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ }
+ }
+ },
+ "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": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="
+ },
+ "fs-minipass": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
+ "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
+ "requires": {
+ "minipass": "^3.0.0"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+ },
+ "fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "optional": true
+ },
+ "function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="
+ },
+ "gauge": {
+ "version": "2.7.4",
+ "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
+ "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+ "requires": {
+ "aproba": "^1.0.3",
+ "console-control-strings": "^1.0.0",
+ "has-unicode": "^2.0.0",
+ "object-assign": "^4.1.0",
+ "signal-exit": "^3.0.0",
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1",
+ "wide-align": "^1.1.0"
+ }
+ },
+ "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"
+ }
+ },
+ "get-intrinsic": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
+ "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
+ "requires": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "has-proto": "^1.0.1",
+ "has-symbols": "^1.0.3",
+ "hasown": "^2.0.0"
+ }
+ },
+ "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"
+ }
+ },
+ "glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ },
+ "gopd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+ "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+ "requires": {
+ "get-intrinsic": "^1.1.3"
+ }
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
+ },
+ "has-property-descriptors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "requires": {
+ "es-define-property": "^1.0.0"
+ }
+ },
+ "has-proto": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
+ "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q=="
+ },
+ "has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
+ },
+ "has-unicode": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+ "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
+ },
+ "hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "requires": {
+ "function-bind": "^1.1.2"
+ }
+ },
+ "http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "requires": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ }
+ },
+ "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"
+ }
+ },
+ "ignore-by-default": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
+ "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk="
+ },
+ "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.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
+ },
+ "is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "requires": {
+ "binary-extensions": "^2.0.0"
+ }
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
+ },
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "is-glob": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+ "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ },
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
+ },
+ "is-property": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
+ "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ="
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+ },
+ "jsonwebtoken": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
+ "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
+ "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": "^7.5.4"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ }
+ }
+ },
+ "jwa": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
+ "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
+ "requires": {
+ "buffer-equal-constant-time": "1.0.1",
+ "ecdsa-sig-formatter": "1.0.11",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "jws": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
+ "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+ "requires": {
+ "jwa": "^1.4.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "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="
+ },
+ "long": {
+ "version": "5.2.3",
+ "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
+ "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q=="
+ },
+ "lru-cache": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-8.0.5.tgz",
+ "integrity": "sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA=="
+ },
+ "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.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
+ }
+ }
+ },
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+ },
+ "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.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"
+ }
+ },
+ "minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minipass": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz",
+ "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==",
+ "requires": {
+ "yallist": "^4.0.0"
+ }
+ },
+ "minizlib": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
+ "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
+ "requires": {
+ "minipass": "^3.0.0",
+ "yallist": "^4.0.0"
+ }
+ },
+ "mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
+ },
+ "morgan": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz",
+ "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==",
+ "requires": {
+ "basic-auth": "~2.0.1",
+ "debug": "2.6.9",
+ "depd": "~2.0.0",
+ "on-finished": "~2.3.0",
+ "on-headers": "~1.0.2"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ },
+ "mysql2": {
+ "version": "3.11.0",
+ "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.11.0.tgz",
+ "integrity": "sha512-J9phbsXGvTOcRVPR95YedzVSxJecpW5A5+cQ57rhHIFXteTP10HCs+VBjS7DHIKfEaI1zQ5tlVrquCd64A6YvA==",
+ "requires": {
+ "aws-ssl-profiles": "^1.1.1",
+ "denque": "^2.1.0",
+ "generate-function": "^2.3.1",
+ "iconv-lite": "^0.6.3",
+ "long": "^5.2.1",
+ "lru-cache": "^8.0.0",
+ "named-placeholders": "^1.1.3",
+ "seq-queue": "^0.0.5",
+ "sqlstring": "^2.3.2"
+ },
+ "dependencies": {
+ "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"
+ }
+ },
+ "sqlstring": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.2.tgz",
+ "integrity": "sha512-vF4ZbYdKS8OnoJAWBmMxCQDkiEBkGQYU7UZPtL8flbDRSNkhaXvRJ279ZtI6M+zDaQovVU4tuRgzK5fVhvFAhg=="
+ }
+ }
+ },
+ "named-placeholders": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz",
+ "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==",
+ "requires": {
+ "lru-cache": "^7.14.1"
+ },
+ "dependencies": {
+ "lru-cache": {
+ "version": "7.18.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
+ "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="
+ }
+ }
+ },
+ "negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
+ },
+ "node-addon-api": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz",
+ "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A=="
+ },
+ "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"
+ }
+ },
+ "nodemon": {
+ "version": "3.1.4",
+ "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.4.tgz",
+ "integrity": "sha512-wjPBbFhtpJwmIeY2yP7QF+UKzPfltVGtfce1g/bB15/8vCGZj8uxD62b/b9M9/WVgme0NZudpownKN+c0plXlQ==",
+ "requires": {
+ "chokidar": "^3.5.2",
+ "debug": "^4",
+ "ignore-by-default": "^1.0.1",
+ "minimatch": "^3.1.2",
+ "pstree.remy": "^1.1.8",
+ "semver": "^7.5.3",
+ "simple-update-notifier": "^2.0.0",
+ "supports-color": "^5.5.0",
+ "touch": "^3.1.0",
+ "undefsafe": "^2.0.5"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.3.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
+ "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
+ "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=="
+ }
+ }
+ },
+ "nopt": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
+ "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
+ "requires": {
+ "abbrev": "1"
+ }
+ },
+ "normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
+ },
+ "npmlog": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
+ "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+ "requires": {
+ "are-we-there-yet": "~1.1.2",
+ "console-control-strings": "~1.1.0",
+ "gauge": "~2.7.3",
+ "set-blocking": "~2.0.0"
+ }
+ },
+ "number-is-nan": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+ },
+ "object-inspect": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz",
+ "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g=="
+ },
+ "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"
+ }
+ },
+ "on-headers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
+ "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
+ },
+ "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="
+ },
+ "picomatch": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
+ "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw=="
+ },
+ "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"
+ }
+ },
+ "pstree.remy": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
+ "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w=="
+ },
+ "qs": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+ "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+ "requires": {
+ "side-channel": "^1.0.4"
+ }
+ },
+ "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.5.2",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
+ "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
+ "requires": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "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"
+ }
+ },
+ "readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "requires": {
+ "picomatch": "^2.2.1"
+ }
+ },
+ "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=="
+ },
+ "semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="
+ },
+ "send": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
+ "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
+ "requires": {
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "2.0.1"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
+ "on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ }
+ }
+ },
+ "seq-queue": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz",
+ "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4="
+ },
+ "serve-static": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
+ "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
+ "requires": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.18.0"
+ }
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
+ },
+ "set-function-length": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+ "requires": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "gopd": "^1.0.1",
+ "has-property-descriptors": "^1.0.2"
+ }
+ },
+ "setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+ },
+ "side-channel": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
+ "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
+ "requires": {
+ "call-bind": "^1.0.7",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.4",
+ "object-inspect": "^1.13.1"
+ }
+ },
+ "signal-exit": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
+ "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA=="
+ },
+ "simple-update-notifier": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
+ "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
+ "requires": {
+ "semver": "^7.5.3"
+ }
+ },
+ "statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
+ },
+ "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"
+ }
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ },
+ "tar": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
+ "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
+ "requires": {
+ "chownr": "^2.0.0",
+ "fs-minipass": "^2.0.0",
+ "minipass": "^5.0.0",
+ "minizlib": "^2.1.1",
+ "mkdirp": "^1.0.3",
+ "yallist": "^4.0.0"
+ },
+ "dependencies": {
+ "minipass": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
+ "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="
+ }
+ }
+ },
+ "to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "requires": {
+ "is-number": "^7.0.0"
+ }
+ },
+ "toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
+ },
+ "touch": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
+ "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
+ "requires": {
+ "nopt": "~1.0.10"
+ },
+ "dependencies": {
+ "nopt": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
+ "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=",
+ "requires": {
+ "abbrev": "1"
+ }
+ }
+ }
+ },
+ "tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
+ },
+ "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"
+ }
+ },
+ "undefsafe": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
+ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA=="
+ },
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="
+ },
+ "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="
+ },
+ "vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
+ },
+ "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"
+ }
+ },
+ "wide-align": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
+ "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
+ "requires": {
+ "string-width": "^1.0.2 || 2"
+ }
+ },
+ "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=="
+ }
+ }
+}
diff --git a/api/package.json b/api/package.json
new file mode 100644
index 00000000..f12e2110
--- /dev/null
+++ b/api/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "cafe-api",
+ "version": "1.1.0",
+ "description": "",
+ "main": "app.js",
+ "scripts": {
+ "start": "node app.js",
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "beanbeanjuice",
+ "license": "ISC",
+ "dependencies": {
+ "bcrypt": "^5.0.1",
+ "body-parser": "^1.19.0",
+ "dotenv": "^10.0.0",
+ "express": "^4.17.1",
+ "jsonwebtoken": "^9.0.2",
+ "morgan": "^1.10.0",
+ "mysql2": "^3.11.0",
+ "nodemon": "^3.1.4"
+ }
+}
diff --git a/api/public/form.html b/api/public/form.html
new file mode 100644
index 00000000..bafca917
--- /dev/null
+++ b/api/public/form.html
@@ -0,0 +1,13 @@
+
+
+
+ Please fill out the fields below...
+
+
+
+
+
\ No newline at end of file
diff --git a/api/routes/boggle/game.js b/api/routes/boggle/game.js
new file mode 100644
index 00000000..97591cf0
--- /dev/null
+++ b/api/routes/boggle/game.js
@@ -0,0 +1,144 @@
+const express = require('express');
+const router = express.Router();
+
+const check_authentication = require('../../middleware/check-auth');
+const getConnection = require('./modules/mysql-connection');
+
+// Gets a list of all games.
+router.get("/games", (request, response) => {
+ const connection = getConnection();
+ const query = "SELECT * FROM game_data;";
+ connection.query(query, (error, rows, fields) => {
+ if (error) {
+ console.log("Failed to Query Games: " + error);
+ response.status(500).json({
+ message: error
+ });
+ return;
+ }
+ response.status(200).json({
+ games: rows,
+ message: "Successfully Retrieved Games"
+ });
+ });
+});
+
+// Gets a list of all games for a specific user.
+router.get("/games/:user_id", (request, response) => {
+ const connection = getConnection();
+ const query = "SELECT * FROM game_data WHERE user_id = (?);";
+ const user_id = request.params.user_id;
+
+ connection.query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ console.log("Error Getting Games for User (" + user_id + "): " + error);
+ response.status(500).json({
+ message: error
+ });
+ }
+
+ response.status(200).json({
+ games: rows,
+ message: "Successfully Retrieved Games"
+ });
+ });
+})
+
+// Gets a specific game for a specific user.
+router.get("/game", (request, response) => {
+ const user_id = request.query.user_id;
+ const game_id = request.query.game_id;
+
+ // Checking if the userID and gameID exist.
+ if (typeof user_id === 'undefined' || typeof game_id === 'undefined') {
+ response.status(400).json({
+ message: "A Variable is Undefined"
+ });
+ return; // Must return so the app doesn't crash. Stops all the rest of the code from running.
+ }
+
+ const connection = getConnection();
+ const query = "SELECT * FROM game_data WHERE user_id = (?) AND game_id = (?);";
+ connection.query(query, [user_id, game_id], (error, rows, fields) => {
+
+ if (error) {
+ console.log("Failed to Query Game (" + game_id + "): " + error);
+ response.status(500).json({
+ message: error
+ });
+ return;
+ }
+
+ response.status(200).json({
+ game: rows,
+ message: "Successfully Retrieved Game (" + game_id + ") For User (" + user_id + ")"
+ });
+ });
+});
+
+// Adds a new game to the database.
+router.post('/game_create', check_authentication, (request, response) => {
+ console.log("Attempting to add a new game to the database...");
+
+ const user_id = request.user_data.user_id;
+ const game_id = request.query.game_id;
+ const score = request.query.score;
+ const board_characters = request.query.board_characters;
+ const time_taken = request.query.time_taken;
+ const time_allowed = request.query.time_allowed;
+ const words_found = request.query.words_found;
+ const total_words = request.query.total_words;
+ const found_words_string_list = request.query.found_words_string_list;
+ const total_words_string_list = request.query.total_words_string_list;
+
+ if (user_id === 'undefined' || game_id === 'undefined' || score === 'undefined'
+ || board_characters === 'undefined' || time_taken === 'undefined' || time_allowed === 'undefined'
+ || words_found === 'undefined' || total_words === 'undefined' || found_words_string_list === 'undefined'
+ || total_words_string_list === 'undefined') {
+ response.status(400).json({
+ message: "A Variable is Undefined"
+ });
+ return;
+ }
+
+ const check_query = "SELECT * FROM game_data WHERE user_id = (?) AND game_id = (?);";
+ const check_connection = getConnection();
+ check_connection.query(check_query, [user_id, game_id], (error, rows, fields) => {
+ if (error) {
+ response.status(500).json({
+ message: "Error Checking if Game Exists"
+ });
+ return;
+ }
+
+ if (rows.length > 0) {
+ response.status(500).json({
+ message: "A Game with ID (" + game_id + ") for User (" + user_id + ") Already Exists"
+ })
+ return;
+ }
+
+ // localhost:4101/boggle/v1/game_create?user_id=2&game_id=3&score=100&board_characters=PQUIFJZLAKDNALXOW&time_taken=94&time_allowed=300&words_found=100&total_words=150&found_words_string_list=hello,test,bruh,one,two&total_words_string_list=hello,test,bruh,one,two,three
+ const query = "INSERT INTO game_data " +
+ "(user_id, game_id, score, board_characters, time_taken, time_allowed, words_found, total_words, found_words_string_list, total_words_string_list) " +
+ "VALUES(?,?,?,?,?,?,?,?,?,?);";
+ const connection = getConnection();
+ connection.query(query, [user_id, game_id, score, board_characters, time_taken, time_allowed, words_found, total_words, found_words_string_list, total_words_string_list],
+ (error, rows, fields) => {
+ if (error) {
+ console.log("Failed to Insert New Game: " + error);
+ response.status(500).json({
+ message: error
+ });
+ return;
+ }
+
+ console.log("Inserted New Game (" + game_id + ") for User (" + user_id + ")");
+ response.status(201).json({
+ message: "Successfully Added New Game (" + game_id + ") for User (" + user_id + ")"
+ });
+ });
+ });
+});
+
+module.exports = router;
\ No newline at end of file
diff --git a/api/routes/boggle/modules/mysql-connection.js b/api/routes/boggle/modules/mysql-connection.js
new file mode 100644
index 00000000..d1cd93f9
--- /dev/null
+++ b/api/routes/boggle/modules/mysql-connection.js
@@ -0,0 +1,21 @@
+const mysql = require('mysql2');
+
+const mysql_url = "beanbeanjuice.com";
+const mysql_port = 4001;
+const mysql_user = "root";
+const mysql_password = "refr}2Z,.+ugT2Gd*.v6N36Ad,rb)L";
+const mysql_database = "boggle";
+
+// Creates a MySQL pool. Allows multiple connections.
+const pool = mysql.createPool({
+ connectionLimit: 10,
+ host: mysql_url,
+ port: mysql_port,
+ user: mysql_user,
+ password: mysql_password,
+ database: mysql_database
+});
+
+module.exports = () => {
+ return pool;
+}
\ No newline at end of file
diff --git a/api/routes/boggle/settings.js b/api/routes/boggle/settings.js
new file mode 100644
index 00000000..db2fcb8e
--- /dev/null
+++ b/api/routes/boggle/settings.js
@@ -0,0 +1,162 @@
+const express = require('express');
+const router = express.Router();
+
+const check_authentication = require('../../middleware/check-auth');
+const getConnection = require('./modules/mysql-connection');
+
+const check_if_user_exists = (request, response, next) => {
+ const user_id = request.user_data.user_id;
+
+ const query = "SELECT * FROM user_settings WHERE user_id = (?);";
+ const connection = getConnection();
+ connection.query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ response.status(500).json({
+ message: error
+ });
+ return;
+ }
+
+ if (rows.length < 1) {
+ response.status(500).json({
+ message: "Settings for User (" + user_id + ") Do Not Exist"
+ });
+ return;
+ }
+
+ next(); // Continue
+ });
+};
+
+// Gets a list of all settings.
+router.get("/user_settings", check_authentication, (request, response) => {
+ const connection = getConnection();
+ const query = "SELECT * FROM user_settings;";
+ connection.query(query, (error, rows, fields) => {
+ if (error) {
+ console.log("Failed to Query User Settings: " + error);
+ response.status(500).json({
+ message: error
+ });
+ return;
+ }
+ response.status(200).json({
+ settings: rows,
+ message: "Successfully Retrieved All User Settings"
+ });
+ });
+});
+
+// Gets a User's Settings
+router.get("/user_setting", check_authentication, check_if_user_exists, (request, response) => {
+ const user_id = request.user_data.user_id;
+ const connection = getConnection();
+ const query = "SELECT * FROM user_settings WHERE user_id = (?);";
+ connection.query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ response.status(500).json({
+ message: error
+ });
+ return;
+ }
+
+ response.status(200).json({
+ settings: rows,
+ message: "Successfully Retrived Settings for User (" + user_id + ")"
+ });
+ });
+});
+
+// Updates a specific user's settings.
+router.patch("/user_setting/update", check_authentication, check_if_user_exists, (request, response) => {
+
+ const user_id = request.user_data.user_id;
+ const time_limit = request.query.time_limit;
+ const ignore_time_limit = request.query.ignore_time_limit;
+
+ if (ignore_time_limit != 0 && ignore_time_limit != 1) {
+ response.status(500).json({
+ message: "The variable, ignore_time_limit, can only be between 0 and 1"
+ })
+ return;
+ }
+
+ const connection = getConnection();
+ const query = "UPDATE user_settings SET time_limit = (?), ignore_time_limit = (?) WHERE user_id = (?);";
+ connection.query(query, [time_limit, ignore_time_limit, user_id], (error, rows, fields) => {
+ if (error) {
+ console.log("Error Updating User (" + user_id + ") Settings: " + error);
+ response.status(500).json({
+ message: error
+ });
+ return;
+ }
+
+ console.log("Updated User (" + user_id + ") Settings");
+ response.status(200).json({
+ message: "Successfully Updated User (" + user_id + ") Settings"
+ });
+ });
+});
+
+
+// Creating User Settings
+router.post("/user_setting/create", check_authentication, (request, response) => {
+ const user_id = request.user_data.user_id;
+
+ // Checking If Settings Exist
+ const check_query = "SELECT * FROM user_settings WHERE user_id = (?);";
+ const check_connection = getConnection();
+ check_connection.query(check_query, [user_id], (error, rows, fields) => {
+ if (error) {
+ response.status(500).json({
+ message: "Error Checking if User (" + user_id + ") Settings Exists: " + error
+ });
+ return;
+ }
+
+ if (rows.length > 0) {
+ response.status(500).json({
+ message: "Error Creating User Settings: User's Settings Already Exists"
+ });
+ return;
+ }
+
+ const query = "INSERT INTO user_settings (user_id) VALUES (?);";
+ const connection = getConnection();
+ connection.query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ response.status(500).json({
+ message: "Error Creating User Settings: " + error
+ });
+ return;
+ }
+
+ response.status(201).json({
+ message: "Created User (" + user_id + ") Settings with Defaults"
+ });
+ })
+ });
+});
+
+// Deleting User Settings
+router.delete("/user_setting/remove", check_authentication, check_if_user_exists, (request, response) => {
+ const user_id = request.user_data.user_id;
+
+ const query = "DELETE FROM user_settings WHERE user_id = (?);";
+ const connection = getConnection();
+ connection.query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ response.status(500).json({
+ message: "Error Removing User (" + user_id + ") Settings: " + error
+ });
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Removed User (" + user_id + ") Settings"
+ });
+ });
+});
+
+module.exports = router;
\ No newline at end of file
diff --git a/api/routes/cafe/modules/mysql-connection.js b/api/routes/cafe/modules/mysql-connection.js
new file mode 100644
index 00000000..1708d279
--- /dev/null
+++ b/api/routes/cafe/modules/mysql-connection.js
@@ -0,0 +1,20 @@
+const mysql = require('mysql2');
+const checkType = require("../../../middleware/check-type");
+
+// TODO: Confirm this works.
+const mySQL_DATA = checkType.getMySQLData();
+const mysql_database = "cafe";
+
+// Creates a MySQL pool. Allows multiple connections.
+const pool = mysql.createPool({
+ connectionLimit: 200,
+ host: mySQL_DATA.url,
+ port: mySQL_DATA.port,
+ user: mySQL_DATA.user,
+ password: mySQL_DATA.password,
+ database: mysql_database,
+});
+
+module.exports = () => {
+ return pool;
+}
\ No newline at end of file
diff --git a/api/routes/cafe/user.js b/api/routes/cafe/user.js
new file mode 100644
index 00000000..ee239474
--- /dev/null
+++ b/api/routes/cafe/user.js
@@ -0,0 +1,231 @@
+const express = require('express');
+const router = express.Router();
+const bcrypt = require('bcrypt');
+const jwt = require('jsonwebtoken');
+
+const getConnection = require('../cafe/modules/mysql-connection');
+const check_authentication = require('../../middleware/check-auth');
+const check_admin = require('../../middleware/check-admin.js');
+const checkType = require('../../middleware/check-type');
+
+const TOKEN = checkType.TOKEN;
+
+// Gets a list of all users.
+router.get("/users", check_authentication, check_admin, (request, response, next) => {
+ query = "SELECT * FROM users;";
+ getConnection().query(query, (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ users: rows,
+ message: "Successfully Retrieved All Users"
+ });
+ return;
+ });
+});
+
+const check_if_user_exists = (request, response, next) => {
+ username = request.params.username;
+
+ if (!username) {
+ response.status(500).json({
+ variables: {
+ username: username || "undefined"
+ },
+ message: "A Variable is Undefined"
+ });
+ return;
+ }
+
+ query = "SELECT * FROM users WHERE username = (?);";
+ getConnection().query(query, [username], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!rows.length) {
+ const auth_error = new Error("Authorization Failed");
+ auth_error.status = 401;
+ next(auth_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+// Login to an account
+router.post("/user/login", (request, response, next) => {
+ const username = request.query.username;
+
+ const check_query = "SELECT * FROM users WHERE username = (?);";
+ const check_connection = getConnection();
+ check_connection.query(check_query, [username], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ // Checking If Users Exist
+ if (rows.length < 1) {
+ response.status(401).json({
+ message: "Authorization Failed" // Used to Prevent Brute Forcing
+ });
+ return;
+ }
+
+ const hashed_password = rows[0].password;
+ console.info("Checking Token...");
+ bcrypt.compare(request.query.password, hashed_password, (error, result) => {
+ if (error) {
+ response.status(401).json({
+ message: "Authorization Failed"
+ });
+ console.error("Error: " + error.message);
+ return;
+ }
+
+ console.log(TOKEN);
+
+ if (result) {
+ const api_key = jwt.sign({
+ user_id: rows[0].user_id,
+ username: rows[0].username,
+ user_type: rows[0].user_type
+ },
+ TOKEN, // TOKEN
+ {
+ expiresIn: "1h"
+ });
+
+ return response.status(200).json({
+ message: "Authorization Successful",
+ api_key: api_key,
+ expires_in: "1 Hour"
+ });
+ }
+
+ response.status(401).json({
+ message: "Authorization Failed"
+ });
+ });
+
+
+ });
+});
+
+// Creates a user.
+router.post('/user/signup', (request, response) => {
+
+ // HASHING the password
+ bcrypt.hash(request.query.password, 10, (error, hashed_password) => {
+ if (error) {
+ return response.status(500).json({
+ message: error
+ });
+ } else {
+
+ const username = request.query.username;
+ const password = hashed_password;
+
+ if (!username || !password) {
+ response.status(500).json({
+ variables: {
+ username: username || "undefined",
+ password: password || "undefined"
+ },
+ message: "A Variable is Undefined"
+ });
+ return;
+ }
+
+ // Checking if the User Exists Already
+ const check_query = "SELECT * FROM users WHERE username = (?);";
+ const check_connection = getConnection();
+ check_connection.query(check_query, [username], (error, rows, fields) => {
+
+ if (error) {
+ response.status(500).json({
+ message: "Error Checking if User Exists"
+ })
+ return;
+ }
+
+ if (rows.length > 0) {
+ response.status(401).json({
+ message: "Authorization Failed"
+ });
+ return;
+ } else {
+ const query = "INSERT INTO users (username, password) VALUES (?,?);";
+ const connection = getConnection();
+ connection.query(query, [username, password], (error, rows, fields) => {
+ if (error) {
+ console.log("Failed to Insert New User: " + error);
+ response.status(500).json({
+ message: error
+ });
+ return;
+ }
+
+ console.log("Inserted New User Successfully with ID: " + rows.insertId);
+
+ response.status(201).json({
+ message: "Successfully Created User (" + rows.insertId + ")"
+ });
+ });
+ return;
+ }
+ });
+
+ }
+ });
+});
+
+// Gets a specified user.
+router.get("/user/:username", check_authentication, check_admin, check_if_user_exists, (request, response) => {
+ const username = request.params.username;
+
+ query = "SELECT * FROM users WHERE username = (?);";
+ getConnection().query(query, [username], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ user: rows[0],
+ message: "Successfully Retrieved User"
+ });
+ return;
+ });
+});
+
+// Deleting User
+router.delete("/user/:username", check_authentication, check_admin, (request, response) => {
+
+ const username = request.params.username;
+
+ console.log("Deleting User (" + username + ")");
+
+ const query = "DELETE FROM users WHERE username = (?);";
+ const connection = getConnection();
+ connection.query(query, [username], (error, rows, fields) => {
+ if (error) {
+ response.status(500).json({
+ message: "Error Removing User (" + username + "): " + error
+ });
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Deleted User (" + username + ")"
+ });
+ });
+});
+
+module.exports = router;
diff --git a/api/routes/cafeBot/beanCoins.js b/api/routes/cafeBot/beanCoins.js
new file mode 100644
index 00000000..e1f88467
--- /dev/null
+++ b/api/routes/cafeBot/beanCoins.js
@@ -0,0 +1,139 @@
+const express = require('express');
+const router = express.Router();
+
+const getConnection = require('./modules/mysql-connection');
+const check_authentication = require('../../middleware/check-auth');
+const check_admin = require('../../middleware/check-admin.js');
+
+const check_if_user_exists = (request, response, next) => {
+ user_id = request.params.user_id;
+
+ query = "SELECT * FROM beancoin_donation_users WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!rows.length) {
+ const user_error = new Error("Donation User (" + user_id + ") Does Not Exist");
+ user_error.status = 404;
+ next(user_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+const check_if_user_does_not_exist = (request, response, next) => {
+ user_id = request.params.user_id;
+
+ query = "SELECT * FROM beancoin_donation_users WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!!rows.length) {
+ const user_error = new Error("User (" + user_id + ") Already Exists");
+ user_error.status = 409;
+ next(user_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+// Gets beanCoin donation users.
+router.get("/beanCoin/donation_users", check_authentication, check_admin, (request, response, next) => {
+ query = "SELECT * FROM beancoin_donation_users;";
+ connection = getConnection();
+ connection.query(query, (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ users: rows,
+ message: "Successfully Retrieved List of Active Donation Users"
+ });
+ return;
+ });
+});
+
+// Gets a specific donation user.
+router.get("/beanCoin/donation_users/:user_id", check_authentication, check_admin, check_if_user_exists, (request, response, next) => {
+
+ user_id = request.params.user_id;
+
+ query = "SELECT * FROM beancoin_donation_users WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ user: rows[0],
+ message: "Successfully Retrieved User (" + user_id + ")"
+ });
+ return;
+ });
+});
+
+// Add a new donation user
+router.post("/beanCoin/donation_users/:user_id", check_authentication, check_admin, check_if_user_does_not_exist, (request, response, next) => {
+
+ user_id = request.params.user_id;
+ time_stamp = request.query.time_stamp;
+
+ if (!time_stamp) {
+ response.status(400).json({
+ variables: {
+ user_id: user_id,
+ time_stamp: time_stamp || "undefined"
+ },
+ message: "A Variable is Undefined"
+ });
+ return;
+ }
+
+ query = "INSERT INTO beancoin_donation_users (user_id, time_until_next_donation) VALUES (?,?);";
+ getConnection().query(query, [user_id, time_stamp], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(201).json({
+ message: "Successfully Created User (" + user_id + ")"
+ });
+ return;
+ });
+
+});
+
+// Deletes a beanCoin donation user
+router.delete("/beanCoin/donation_users/:user_id", check_authentication, check_admin, (request, response, next) => {
+ user_id = request.params.user_id;
+
+ query = "DELETE FROM beancoin_donation_users WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Removed User (" + user_id + ")"
+ });
+ return;
+ });
+
+});
+
+module.exports = router;
diff --git a/api/routes/cafeBot/birthdays.js b/api/routes/cafeBot/birthdays.js
new file mode 100644
index 00000000..44aa9fde
--- /dev/null
+++ b/api/routes/cafeBot/birthdays.js
@@ -0,0 +1,214 @@
+const express = require('express');
+const router = express.Router();
+
+const getConnection = require('./modules/mysql-connection');
+const check_authentication = require('../../middleware/check-auth');
+const check_admin = require('../../middleware/check-admin.js');
+
+const check_if_user_exists = (request, response, next) => {
+ user_id = request.params.user_id;
+
+ query = "SELECT * FROM birthdays WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!rows.length) {
+ const user_error = new Error("User (" + user_id + ") Does Not Exist");
+ user_error.status = 404;
+ next(user_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+const check_if_user_does_not_exist = (request, response, next) => {
+ user_id = request.params.user_id;
+
+ query = "SELECT * FROM birthdays WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!!rows.length) {
+ const user_error = new Error("User (" + user_id + ") Already Exists");
+ user_error.status = 409;
+ next(user_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+// Gets all birthdays.
+router.get("/birthdays", check_authentication, check_admin, (request, response, next) => {
+ query = "SELECT * FROM birthdays;";
+ connection = getConnection();
+ connection.query(query, (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ birthdays: rows,
+ message: "Successfully Retrieved List of Birthdays"
+ });
+ return;
+ });
+});
+
+// Gets a user's specific birthday.
+router.get("/birthdays/:user_id", check_authentication, check_admin, check_if_user_exists, (request, response, next) => {
+ user_id = request.params.user_id;
+
+ query = "SELECT * FROM birthdays WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ birthday: rows[0],
+ message: "Successfully Retrieved Birthday Information for User (" + user_id + ")"
+ });
+ return;
+ });
+});
+
+// Updates a user's birthday.
+router.patch("/birthdays/:user_id", check_authentication, check_admin, check_if_user_exists, (request, response, next) => {
+ user_id = request.params.user_id;
+ birthday = request.query.birthday;
+ time_zone = request.query.time_zone
+
+ // TODO: Somehow add time_zone as well to this.
+ if (!birthday) {
+ response.status(400).json({
+ variables: {
+ user_id: user_id,
+ birthday: birthday || "undefined"
+ },
+ message: "A Variable is Undefined"
+ });
+ return;
+ }
+
+ // TODO: Test this
+ query = "UPDATE birthdays SET birth_date = (?), time_zone = (?) WHERE user_id = (?);";
+ getConnection().query(query, [birthday, time_zone, user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Updated Birthday for User (" + user_id + ")"
+ });
+ return;
+ });
+});
+
+// Updates the mention status of a user.
+router.patch("/birthdays/:user_id/mention", check_authentication, check_admin, check_if_user_exists, (request, response, next) => {
+ user_id = request.params.user_id;
+ already_mentioned = request.query.already_mentioned;
+
+ if (!already_mentioned) {
+ response.status(400).json({
+ variables: {
+ user_id: user_id,
+ already_mentioned: already_mentioned || "undefined"
+ },
+ message: "A Variable is Undefiend"
+ });
+ return;
+ }
+
+ if (already_mentioned == "true") {
+ already_mentioned = 1;
+ } else if (already_mentioned == "false") {
+ already_mentioned = 0;
+ } else {
+
+ if (already_mentioned != 0 && already_mentioned != 1) {
+ response.status(500).json({
+ message: "Only true or false is Available"
+ });
+ return;
+ }
+ }
+
+ query = "UPDATE birthdays SET already_mentioned = (?) WHERE user_id = (?);";
+ getConnection().query(query, [already_mentioned, user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Updated the Already Mentioned Status for User (" + user_id + ")"
+ });
+ return;
+ });
+});
+
+// TODO: Test this.
+// Creates a birthday
+router.post("/birthdays/:user_id", check_authentication, check_admin, check_if_user_does_not_exist, (request, response, next) => {
+ user_id = request.params.user_id;
+ birthday = request.query.birthday;
+ time_zone = request.query.time_zone;
+
+ if (!birthday) {
+ response.status(400).json({
+ variables: {
+ user_id: user_id,
+ birthday: birthday || "undefined"
+ },
+ message: "A Variable is Undefined"
+ });
+ return;
+ }
+
+ query = "INSERT INTO birthdays (user_id, birth_date, time_zone) VALUES (?,?,?);";
+ getConnection().query(query, [user_id, birthday, time_zone], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(201).json({
+ message: "Successfully Created a Birthday for User (" + user_id + ")"
+ });
+ return;
+ });
+});
+
+// Deletes a user's birthday.
+router.delete("/birthdays/:user_id", check_authentication, check_admin, (request, response, next) => {
+ user_id = request.params.user_id;
+
+ query = "DELETE FROM birthdays WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Deleted Birthday for User (" + user_id + ")"
+ });
+ return;
+ });
+});
+
+module.exports = router;
diff --git a/api/routes/cafeBot/cafe.js b/api/routes/cafeBot/cafe.js
new file mode 100644
index 00000000..3a18897d
--- /dev/null
+++ b/api/routes/cafeBot/cafe.js
@@ -0,0 +1,180 @@
+const express = require('express');
+const router = express.Router();
+
+const getConnection = require('./modules/mysql-connection');
+const check_authentication = require('../../middleware/check-auth');
+const check_admin = require('../../middleware/check-admin.js');
+
+const check_if_user_exists = (request, response, next) => {
+ user_id = request.params.user_id;
+
+ query = "SELECT * FROM cafe_information WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!rows.length) {
+ const user_error = new Error("User (" + user_id + ") Does Not Exist");
+ user_error.status = 404;
+ next(user_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+const check_if_user_does_not_exist = (request, response, next) => {
+ user_id = request.params.user_id;
+
+ query = "SELECT * FROM cafe_information WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!!rows.length) {
+ const user_error = new Error("User (" + user_id + ") Already Exists");
+ user_error.status = 409;
+ next(user_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+// Gets a list of all cafe user information.
+router.get("/cafe/users", check_authentication, check_admin, (request, response, next) => {
+ query = "SELECT * FROM cafe_information;";
+ connection = getConnection();
+ connection.query(query, (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ users: rows,
+ message: "Successfully Retrieved Cafe Users"
+ });
+ return;
+ });
+});
+
+// Gets a list of all information for a specific cafe user
+router.get("/cafe/users/:user_id", check_authentication, check_admin, check_if_user_exists, (request, response, next) => {
+ user_id = request.params.user_id;
+
+ query = "SELECT * FROM cafe_information WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ cafe_user: rows[0],
+ message: "Successfully Retrieved Cafe User (" + user_id + ")"
+ });
+ return;
+ });
+});
+
+// Updates a specific cafe user.
+router.patch("/cafe/users/:user_id", check_authentication, check_admin, check_if_user_exists, (request, response, next) => {
+ user_id = request.params.user_id;
+
+ type = request.query.type;
+ value = request.query.value;
+
+ var valid_variables = {
+ bean_coins: "Double",
+ last_serving_time: "SQL Timestamp",
+ orders_bought: "Integer",
+ orders_received: "Integer"
+ };
+
+ if (!type || !valid_variables[type]) {
+ response.status(400).json({
+ valid_variables,
+ message: "A Valid Type is Missing"
+ });
+ return;
+ }
+
+ // Retrieves the value of the key, "type"
+ value_type = Object.getOwnPropertyDescriptor(valid_variables, type).value;
+
+ if (!value) {
+ response.status(400).json({
+ variables_required: {
+ type: type,
+ value_type: value_type
+ },
+ message: "A Value Is Required",
+ example: "If the type is a Timestamp, then the value would be 2021-07-07 13:46:36."
+ });
+ return;
+ }
+
+ if (type === "last_serving_time") {
+ if (value === "null") {
+ value = null;
+ }
+ }
+
+ query = "UPDATE cafe_information SET ?? = (?) WHERE user_id = (?);";
+ getConnection().query(query, [type, value, user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Updated Cafe User (" + user_id + ")"
+ });
+ return;
+ });
+});
+
+// Creates a new cafe user.
+router.post("/cafe/users/:user_id", check_authentication, check_admin, check_if_user_does_not_exist, (request, response, next) => {
+ user_id = request.params.user_id;
+
+ query = "INSERT INTO cafe_information (user_id) VALUES (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(201).json({
+ message: "Successfully Created New Cafe User (" + user_id + ")"
+ });
+ return;
+ });
+});
+
+// Deletes a cafe user.
+router.delete("/cafe/users/:user_id", check_authentication, check_admin, (request, response, next) => {
+ user_id = request.params.user_id;
+
+ query = "DELETE FROM cafe_information WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Deleted Cafe User (" + user_id + ")"
+ });
+ return;
+ });
+});
+
+module.exports = router;
diff --git a/api/routes/cafeBot/cafeBot.js b/api/routes/cafeBot/cafeBot.js
new file mode 100644
index 00000000..7c691385
--- /dev/null
+++ b/api/routes/cafeBot/cafeBot.js
@@ -0,0 +1,55 @@
+const express = require('express');
+const router = express.Router();
+
+const getConnection = require('./modules/mysql-connection');
+const check_authentication = require('../../middleware/check-auth');
+const check_admin = require('../../middleware/check-admin.js');
+
+// Gets the current bot information.
+router.get("/cafeBot", (request, response, next) => {
+ query = "SELECT * FROM bot_information;";
+ connection = getConnection();
+ connection.query(query, (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ bot_information: {
+ "version": rows[0].version
+ },
+ message: "Successfully Retrieved the Current Bot Information"
+ });
+ return;
+ });
+});
+
+// Updates the cafeBog Version
+router.patch("/cafeBot", check_authentication, check_admin, (request, response, next) => {
+ version = request.query.version;
+
+ if (!version) {
+ response.status(400).json({
+ variables: {
+ version: version || "undefined"
+ },
+ message: "A Variable is Undefined"
+ });
+ return;
+ }
+ query = "UPDATE bot_information SET version = (?) WHERE id = 1;";
+ getConnection().query(query, [version], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Updated cafeBot Version (" + version + ")"
+ });
+ return;
+ });
+});
+
+module.exports = router;
diff --git a/api/routes/cafeBot/codes.js b/api/routes/cafeBot/codes.js
new file mode 100644
index 00000000..3b3de022
--- /dev/null
+++ b/api/routes/cafeBot/codes.js
@@ -0,0 +1,164 @@
+const express = require('express');
+const router = express.Router();
+
+const getConnection = require('./modules/mysql-connection');
+const check_authentication = require('../../middleware/check-auth');
+const check_admin = require('../../middleware/check-admin.js');
+
+const check_if_user_exists = (request, response, next) => {
+ user_id = request.params.user_id;
+
+ query = "SELECT * FROM generated_codes WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!rows.length) {
+ const user_error = new Error("Generated Code for User (" + user_id + ") Does Not Exist");
+ user_error.status = 404;
+ next(user_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+const check_if_user_does_not_exist = (request, response, next) => {
+ user_id = request.params.user_id;
+
+ query = "SELECT * FROM generated_codes WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!!rows.length) {
+ const user_error = new Error("Generated Code for User (" + user_id + ") Already Exists");
+ user_error.status = 409;
+ next(user_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+// Gets all generated codes.
+router.get("/codes", check_authentication, check_admin, (request, response, next) => {
+ query = "SELECT * FROM generated_codes;";
+ getConnection().query(query, (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ users: rows,
+ message: "Successfully Retrieved the Generated Codes for All Users"
+ });
+ return;
+ });
+});
+
+// Gets a user's code.
+router.get("/codes/:user_id", check_authentication, check_admin, check_if_user_exists, (request, response, next) => {
+ user_id = request.params.user_id;
+
+ query = "SELECT * FROM generated_codes WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ generated_code: rows[0].generated_code,
+ message: "Successfully Retrieved User (" + user_id + ") Code"
+ });
+ return;
+ });
+});
+
+// Updates an existing user's code.
+router.patch("/codes/:user_id", check_authentication, check_admin, check_if_user_exists, (request, response, next) => {
+ user_id = request.params.user_id;
+ generated_code = request.query.generated_code;
+
+ if (!generated_code) {
+ response.status(400).json({
+ variables: {
+ user_id: user_id,
+ generated_code: generated_code || "undefined"
+ },
+ message: "A Variable is Undefined"
+ });
+ return;
+ }
+
+ query = "UPDATE generated_codes SET generated_code = (?) WHERE user_id = (?);";
+ getConnection().query(query, [generated_code, user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Updated Existing Code for User (" + user_id + ")"
+ });
+ return;
+ });
+});
+
+// Creates a new user code.
+router.post("/codes/:user_id", check_authentication, check_admin, check_if_user_does_not_exist, (request, response, next) => {
+ user_id = request.params.user_id;
+ generated_code = request.query.generated_code;
+
+ if (!generated_code) {
+ response.status(500).json({
+ variables: {
+ user_id: user_id,
+ generated_code: generated_code || "undefined"
+ },
+ message: "A Variable is Undefined"
+ });
+ return;
+ }
+
+ query = "INSERT INTO generated_codes (user_id, generated_code) VALUES (?,?);";
+ getConnection().query(query, [user_id, generated_code], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(201).json({
+ message: "Successfully Generated Code for User (" + user_id + ")"
+ });
+ return;
+ });
+});
+
+// Deletes a user code.
+router.delete("/codes/:user_id", check_authentication, check_admin, (request, response, next) => {
+ user_id = request.params.user_id;
+
+ query = "DELETE FROM generated_codes WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Deleted Generated Code for User (" + user_id + ")"
+ });
+ return;
+ });
+});
+
+module.exports = router;
diff --git a/api/routes/cafeBot/counting.js b/api/routes/cafeBot/counting.js
new file mode 100644
index 00000000..77b0389e
--- /dev/null
+++ b/api/routes/cafeBot/counting.js
@@ -0,0 +1,159 @@
+const express = require('express');
+const router = express.Router();
+
+const getConnection = require('./modules/mysql-connection');
+const check_authentication = require('../../middleware/check-auth');
+const check_admin = require('../../middleware/check-admin.js');
+
+const check_if_guild_exists = (request, response, next) => {
+ guild_id = request.params.guild_id;
+
+ query = "SELECT * FROM counting_information WHERE guild_id = (?);";
+ getConnection().query(query, [guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!rows.length) {
+ const guild_error = new Error("Counting Information for Guild (" + guild_id + ") Does Not Exist");
+ guild_error.status = 404;
+ next(guild_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+const check_if_guild_does_not_exist = (request, response, next) => {
+ guild_id = request.params.guild_id;
+
+ query = "SELECT * FROM counting_information WHERE guild_id = (?);";
+ getConnection().query(query, [guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!!rows.length) {
+ const guild_error = new Error("Counting Information for Guild (" + guild_id + ") Already Exist");
+ guild_error.status = 409;
+ next(guild_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+// Gets a list of all guild counting information.
+router.get("/counting/guilds", check_authentication, check_admin, (request, response, next) => {
+ query = "SELECT * FROM counting_information;";
+ getConnection().query(query, (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ guilds: rows,
+ message: "Successfully Retrieved Counting Information for All Guilds"
+ });
+ return;
+ });
+});
+
+// Gets a list of counting information for a specified guild.
+router.get("/counting/guilds/:guild_id", check_authentication, check_admin, check_if_guild_exists, (request, response, next) => {
+ guild_id = request.params.guild_id;
+
+ query = "SELECT * FROM counting_information WHERE guild_id = (?);";
+ getConnection().query(query, [guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ counting_information: rows[0],
+ message: "Successfully Retrieved Counting Information for Guild (" + guild_id + ")"
+ });
+ return;
+ });
+});
+
+// Updates counting information for a specified guild.
+router.patch("/counting/guilds/:guild_id", check_authentication, check_admin, check_if_guild_exists, (request, response, next) => {
+ guild_id = request.params.guild_id;
+
+ highest_number = request.query.highest_number;
+ last_number = request.query.last_number;
+ last_user_id = request.query.last_user_id;
+ failure_role_id = request.query.failure_role_id;
+
+ if (!highest_number || !last_number || !last_user_id || !failure_role_id) {
+ response.status(500).json({
+ variables: {
+ guild_id: guild_id,
+ highest_number: highest_number || "undefined",
+ last_number: last_number || "undefined",
+ last_user_id: last_user_id || "undefined",
+ failure_role_id: failure_role_id || "undefined"
+ },
+ message: "A Variable is Undefined"
+ });
+ return;
+ }
+
+ query = "UPDATE counting_information SET highest_number = (?), last_number = (?), last_user_id = (?), failure_role_id = (?) WHERE guild_id = (?);";
+ getConnection().query(query, [highest_number, last_number, last_user_id, failure_role_id, guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Updated Counting Information for Guild (" + guild_id + ")"
+ });
+ return;
+ });
+});
+
+// Creates new counting information for a guild.
+router.post("/counting/guilds/:guild_id", check_authentication, check_admin, check_if_guild_does_not_exist, (request, response, next) => {
+ guild_id = request.params.guild_id;
+
+ query = "INSERT INTO counting_information (guild_id) VALUES (?);";
+ getConnection().query(query, [guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(201).json({
+ message: "Successfully Created new Counting Information for Guild (" + guild_id + ")"
+ });
+ return;
+ });
+});
+
+// Deletes counting information for a guild.
+router.delete("/counting/guilds/:guild_id", check_authentication, check_admin, (request, response, next) => {
+ guild_id = request.params.guild_id;
+
+ query = "DELETE FROM counting_information WHERE guild_id = (?);";
+ getConnection().query(query, [guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ mesage: "Successfully Deleted Counting Information for Guild (" + guild_id + ")"
+ });
+ return;
+ });
+});
+
+module.exports = router;
diff --git a/api/routes/cafeBot/goodbyes.js b/api/routes/cafeBot/goodbyes.js
new file mode 100644
index 00000000..866abe31
--- /dev/null
+++ b/api/routes/cafeBot/goodbyes.js
@@ -0,0 +1,151 @@
+const express = require('express');
+const router = express.Router();
+
+const getConnection = require('./modules/mysql-connection');
+const check_authentication = require('../../middleware/check-auth');
+const check_admin = require('../../middleware/check-admin.js');
+
+// Checks if a guild's goodbye exists
+const check_if_guild_exists = (request, response, next) => {
+ guild_id = request.params.guild_id;
+ query = "SELECT * FROM goodbye_information WHERE guild_id = (?);";
+
+ getConnection().query(query, [guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!rows.length) {
+ const guild_error = new Error("Guild (" + guild_id + ") Does Not Exist");
+ guild_error.status = 404;
+ next(guild_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+const check_if_guild_does_not_exist = (request, response, next) => {
+ guild_id = request.params.guild_id;
+ query = "SELECT * FROM goodbye_information WHERE guild_id = (?);";
+
+ getConnection().query(query, [guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!!rows.length) {
+ const guild_error = new Error("Guild (" + guild_id + ") Already Exists");
+ guild_error.status = 409;
+ next(guild_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+// Gets all goodbye information.
+router.get("/goodbyes", check_authentication, check_admin, (request, response, next) => {
+ query = "SELECT * FROM goodbye_information;";
+ getConnection().query(query, (error, rows, fields) => {
+ if (error) {
+ console.error("Error Getting All Goodbyes: " + error.message);
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ goodbyes: rows,
+ message: "Successfully Retrieved All Goodbye Information"
+ });
+ return;
+ });
+});
+
+// Gets a specific guild's goodbye information.
+router.get("/goodbyes/:guild_id", check_authentication, check_admin, check_if_guild_exists, (request, response, next) => {
+ guild_id = request.params.guild_id;
+ query = "SELECT * FROM goodbye_information WHERE guild_id = (?);";
+ getConnection().query(query, [guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ goodbye: rows[0],
+ message: "Successfully Retrieved Goodbye Information for Guild (" + guild_id + ")"
+ });
+ return;
+ });
+});
+
+// Updates a specific guild's goodbye information
+router.patch("/goodbyes/:guild_id", check_authentication, check_admin, check_if_guild_exists, (request, response, next) => {
+ guild_id = request.params.guild_id;
+ description = request.query.description || null;
+ thumbnail_url = request.query.thumbnail_url || null;
+ image_url = request.query.image_url || null;
+ message = request.query.message || null;
+
+ query = "UPDATE goodbye_information SET description = (?), thumbnail_url = (?), image_url = (?), message = (?) WHERE guild_id = (?);";
+ getConnection().query(query, [description, thumbnail_url, image_url, message, guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Updated Goodbye Information for Guild (" + guild_id + ")"
+ });
+ return;
+ });
+
+});
+
+// Adds a new guild goodbye
+router.post("/goodbyes/:guild_id", check_authentication, check_admin, check_if_guild_does_not_exist, (request, response, next) => {
+ guild_id = request.params.guild_id;
+
+ description = request.query.description || null;
+ thumbnail_url = request.query.thumbnail_url || null;
+ image_url = request.query.image_url || null;
+ message = request.query.message || null;
+
+ query = "INSERT INTO goodbye_information (guild_id, description, thumbnail_url, image_url, message) VALUES (?,?,?,?,?);";
+ getConnection().query(query, [guild_id, description, thumbnail_url, image_url, message], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(201).json({
+ message: "Successfully Created Goodbye Information for Guild (" + guild_id + ")"
+ });
+ return;
+ });
+});
+
+// Deletes a guild's goodbye information
+router.delete("/goodbyes/:guild_id", check_authentication, check_admin, (request, response, next) => {
+ guild_id = request.params.guild_id;
+
+ query = "DELETE FROM goodbye_information WHERE guild_id = (?);";
+ getConnection().query(query, [guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Removed Goodbye Information for Guild (" + guild_id + ")"
+ });
+ return;
+ });
+});
+
+module.exports = router;
diff --git a/api/routes/cafeBot/guild_twitch.js b/api/routes/cafeBot/guild_twitch.js
new file mode 100644
index 00000000..ad6eacb2
--- /dev/null
+++ b/api/routes/cafeBot/guild_twitch.js
@@ -0,0 +1,140 @@
+const express = require('express');
+const router = express.Router();
+
+const getConnection = require('./modules/mysql-connection');
+const check_authentication = require('../../middleware/check-auth');
+const check_admin = require('../../middleware/check-admin.js');
+
+const check_if_twitch_channel_exists = (request, response, next) => {
+ guild_id = request.params.guild_id;
+ twitch_channel = request.query.twitch_channel;
+ twitch_channel = twitch_channel.toLowerCase();
+
+ if (!twitch_channel) {
+ response.status(400).json({
+ variables: {
+ guild_id: guild_id,
+ twitch_channel: twitch_channel || "undefined"
+ },
+ message: "A Variable is Undefined"
+ });
+ return;
+ }
+
+ query = "SELECT * FROM guild_twitch WHERE guild_id = (?) AND twitch_channel = (?);";
+ getConnection().query(query, [guild_id, twitch_channel], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!!rows.length) {
+ twitch_error = new Error("Twitch Channel (" + twitch_channel + ") Already Exists for Guild (" + guild_id + ")");
+ twitch_error.status = 409;
+ next(twitch_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+// Gets all information for guild's twitch
+router.get("/guilds/twitch", check_authentication, check_admin, (request, response, next) => {
+
+ query = "SELECT * FROM guild_twitch;";
+ connection = getConnection();
+ connection.query(query, (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ guilds_twitch: rows,
+ message: "Successfully Grabbed All Guild Twitch Information"
+ });
+ return;
+ });
+
+});
+
+// Gets all information for a specified guild's twitch
+router.get("/guilds/twitch/:guild_id", check_authentication, check_admin, (request, response, next) => {
+
+ guild_id = request.params.guild_id;
+
+ query = "SELECT * FROM guild_twitch WHERE guild_id = (?);";
+ getConnection().query(query, [guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ var twitch_channels = [];
+ rows.forEach((row) => {
+ twitch_channels.push(row.twitch_channel);
+ });
+
+ response.status(200).json({
+ twitch_channels: twitch_channels,
+ message: "Successfully Retrieved Twitch Channels for Guild (" + guild_id + ")"
+ });
+ return;
+ });
+});
+
+// Adds a new twitch channel for a guild.
+router.post("/guilds/twitch/:guild_id", check_authentication, check_admin, check_if_twitch_channel_exists, (request, response, next) => {
+ guild_id = request.params.guild_id;
+
+ twitch_channel = request.query.twitch_channel;
+ twitch_channel = twitch_channel.toLowerCase(); // Converting to lowercase
+
+ query = "INSERT INTO guild_twitch (guild_id, twitch_channel) VALUES (?,?);";
+ getConnection().query(query, [guild_id, twitch_channel], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(201).json({
+ message: "Successfully Added Twitch Channel for Guild (" + guild_id + ")"
+ });
+ return;
+ });
+});
+
+// Deletes a channel for a specified guild.
+router.delete("/guilds/twitch/:guild_id", check_authentication, check_admin, (request, response, next) => {
+ guild_id = request.params.guild_id;
+ twitch_channel = request.query.twitch_channel;
+
+ if (!twitch_channel) {
+ response.status(400).json({
+ variables: {
+ guild_id: guild_id,
+ twitch_channel: twitch_channel || "undefined"
+ },
+ message: "A Variable is Undefined"
+ });
+ return;
+ }
+
+ twitch_channel = twitch_channel.toLowerCase();
+
+ query = "DELETE FROM guild_twitch WHERE guild_id = (?) AND twitch_channel = (?);";
+ getConnection().query(query, [guild_id, twitch_channel], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Removed Twitch Channel (" + twitch_channel + ") From Guild (" + guild_id + ")"
+ });
+ return;
+ });
+});
+
+module.exports = router;
diff --git a/api/routes/cafeBot/guilds.js b/api/routes/cafeBot/guilds.js
new file mode 100644
index 00000000..ad0e28a6
--- /dev/null
+++ b/api/routes/cafeBot/guilds.js
@@ -0,0 +1,190 @@
+const express = require('express');
+const router = express.Router();
+
+const getConnection = require('./modules/mysql-connection');
+const check_authentication = require('../../middleware/check-auth');
+const check_admin = require('../../middleware/check-admin.js');
+
+const check_if_guild_exists = (request, response, next) => {
+ guild_id = request.params.guild_id;
+
+ query = "SELECT * FROM guild_information WHERE guild_id = (?);";
+ getConnection().query(query, [guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!rows.length) {
+ const guild_error = new Error("The Guild (" + guild_id + ") Does Not Exist");
+ guild_error.status = 404;
+ next(guild_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+const check_if_guild_does_not_exist = (request, response, next) => {
+ guild_id = request.params.guild_id;
+
+ query = "SELECT * FROM guild_information WHERE guild_id = (?);";
+ getConnection().query(query, [guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!!rows.length) {
+ const guild_error = new Error("The Guild (" + guild_id + ") Already Exists");
+ guild_error.status = 409;
+ next(guild_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+// Gets a list of all guilds with their information.
+router.get("/guilds", check_authentication, check_admin, (request, response, next) => {
+ query = "SELECT * FROM guild_information";
+ connection = getConnection();
+ connection.query(query, (error, rows, fields) => {
+
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ guilds: rows
+ });
+ return;
+
+ });
+});
+
+// Gets a specific guild with its information
+router.get("/guilds/:guild_id", check_authentication, check_admin, check_if_guild_exists, (request, response, next) => {
+
+ guild_id = request.params.guild_id;
+
+ query = "SELECT * FROM guild_information WHERE guild_id = (?);";
+ connection = getConnection();
+ connection.query(query, [guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ guild: rows[0],
+ message: "Successfully Retrieved Any Guilds with ID (" + guild_id + ")"
+ })
+ });
+
+});
+
+// Creates a new guild.
+router.post("/guilds/:guild_id", check_authentication, check_admin, check_if_guild_does_not_exist, (request, response, next) => {
+ guild_id = request.params.guild_id;
+
+ query = "INSERT INTO guild_information (guild_id, prefix) VALUES (?,?);";
+ getConnection().query(query, [guild_id, "!!"], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(201).json({
+ message: "Successfully Created Guild (" + guild_id + ") with Default Settings"
+ });
+ return;
+ })
+});
+
+// Deletes a specified guild.
+router.delete("/guilds/:guild_id", check_authentication, check_admin, (request, response, next) => {
+ guild_id = request.params.guild_id;
+
+ query = "DELETE FROM guild_information WHERE guild_id = (?);";
+ getConnection().query(query, [guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Deleted Guild (" + guild_id + ")"
+ });
+ return;
+ });
+});
+
+// Updates a guild's information.
+router.patch("/guilds/:guild_id", check_authentication, check_admin, check_if_guild_exists, (request, response, next) => {
+ guild_id = request.params.guild_id;
+
+ type = request.query.type;
+ value = request.query.value;
+
+ var valid_variables = {
+ prefix: "String",
+ moderator_role_id: "Big Integer/Long",
+ twitch_channel_id: "Big Integer/Long",
+ muted_role_id: "Big Integer/Long",
+ live_notifications_role_id: "Big Integer/Long",
+ notify_on_update: "Tiny Integer",
+ update_channel_id: "Big Integer/Long",
+ counting_channel_id: "Big Integer/Long",
+ poll_channel_id: "Big Integer/Long",
+ raffle_channel_id: "Big Integer/Long",
+ birthday_channel_id: "Big Integer/Long",
+ welcome_channel_id: "Big Integer/Long",
+ log_channel_id: "Big Integer/Long",
+ venting_channel_id: "Big Integer/Long",
+ ai_response: "Tiny Integer",
+ daily_channel_id: "Big Integer/Long",
+ goodbye_channel_id: "Big Integer/Long"
+ };
+
+ if (!type || !valid_variables[type]) {
+ response.status(400).json({
+ valid_variables,
+ message: "A Valid Type is Missing"
+ });
+ return;
+ }
+
+ // Retrieves the value of the key, "type"
+ value_type = Object.getOwnPropertyDescriptor(valid_variables, type).value;
+
+ if (!value) {
+ response.status(500).json({
+ variables_required: {
+ type: type,
+ value_type: value_type
+ },
+ message: "A Value Is Required",
+ example: "If the type is a Timestamp, then the value would be 2021-07-07 13:46:36."
+ });
+ return;
+ }
+
+ query = "UPDATE guild_information SET ?? = (?) WHERE guild_id = (?);";
+ getConnection().query(query, [type, value, guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Updated Guild (" + guild_id + ")"
+ });
+ return;
+ });
+});
+
+module.exports = router;
diff --git a/api/routes/cafeBot/interaction_pictures/interaction_pictures.js b/api/routes/cafeBot/interaction_pictures/interaction_pictures.js
new file mode 100644
index 00000000..eb51e706
--- /dev/null
+++ b/api/routes/cafeBot/interaction_pictures/interaction_pictures.js
@@ -0,0 +1,162 @@
+const express = require('express');
+const router = express.Router();
+
+const getConnection = require('../../cafeBot/modules/mysql-connection.js');
+const check_authentication = require('../../../middleware/check-auth.js');
+const check_admin = require('../../../middleware/check-admin.js');
+
+const api_url = "https://cdn.beanbeanjuice.com/images/cafeBot/interaction/{type}/{number}.gif"
+
+const types = {
+ HUG: {
+ amount: 22,
+ url_type: "hugs"
+ },
+ PUNCH: {
+ amount: 8,
+ url_type: "punches"
+ },
+ KISS: {
+ amount: 25,
+ url_type: "kisses"
+ },
+ BITE: {
+ amount: 17,
+ url_type: "bites"
+ },
+ BLUSH: {
+ amount: 21,
+ url_type: "blushes"
+ },
+ CUDDLE: {
+ amount: 15,
+ url_type: "cuddles"
+ },
+ NOM: {
+ amount: 16,
+ url_type: "noms"
+ },
+ POKE: {
+ amount: 13,
+ url_type: "pokes"
+ },
+ SLAP: {
+ amount: 14,
+ url_type: "slaps"
+ },
+ STAB: {
+ amount: 4,
+ url_type: "stabs"
+ },
+ HMPH: {
+ amount: 8,
+ url_type: "hmphs"
+ },
+ POUT: {
+ amount: 13,
+ url_type: "pouts"
+ },
+ THROW: {
+ amount: 6,
+ url_type: "throws"
+ },
+ SMILE: {
+ amount: 15,
+ url_type: "smiles"
+ },
+ STARE: {
+ amount: 13,
+ url_type: "stares"
+ },
+ TICKLE: {
+ amount: 10,
+ url_type: "tickles"
+ },
+ RAGE: {
+ amount: 14,
+ url_type: "rages"
+ },
+ YELL: {
+ amount: 11,
+ url_type: "yells"
+ },
+ HEADPAT: {
+ amount: 18,
+ url_type: "headpats"
+ },
+ CRY: {
+ amount: 14,
+ url_type: "cries"
+ },
+ DANCE: {
+ amount: 12,
+ url_type: "dances"
+ },
+ DAB: {
+ amount: 11,
+ url_type: "dabs"
+ },
+ BONK: {
+ amount: 13,
+ url_type: "bonks"
+ },
+ SLEEP: {
+ amount: 18,
+ url_type: "sleeps"
+ },
+ DIE: {
+ amount: 7,
+ url_type: "dies"
+ },
+ WELCOME: {
+ amount: 9,
+ url_type: "welcomes"
+ },
+ LICK: {
+ amount: 14,
+ url_type: "licks"
+ },
+ SHUSH: {
+ amount: 11,
+ url_type: "shushes"
+ }
+}
+
+const check_type = (request, response, next) => {
+ type = request.params.type;
+ type = type.toUpperCase();
+
+ if (!types[type]) {
+ response.status(418).json({
+ variables: types,
+ message: "Only a Valid Variable is Acceptable"
+ });
+ return;
+ }
+
+ next();
+}
+
+// Retrieves a random picture.
+router.get("/interaction_pictures/:type", check_authentication, check_type, (request, response, next) => {
+ type = request.params.type;
+ type = type.toUpperCase();
+
+ type_amount = types[type].amount;
+ type_url = types[type].url_type;
+ var url = api_url.replace("{type}", type_url);
+ url = url.replace("{number}", randomIntFromInterval(1, type_amount));
+
+ response.status(200).json({
+ url: url,
+ message: "Successfully Retrieved " + type + " URL."
+ });
+ return;
+});
+
+// Generates a random number
+function randomIntFromInterval(min, max) { // min and max included
+ return Math.floor(Math.random() * (max - min + 1) + min)
+}
+
+module.exports = router;
diff --git a/api/routes/cafeBot/interactions.js b/api/routes/cafeBot/interactions.js
new file mode 100644
index 00000000..17cca04d
--- /dev/null
+++ b/api/routes/cafeBot/interactions.js
@@ -0,0 +1,344 @@
+const express = require('express');
+const router = express.Router();
+
+const getConnection = require('./modules/mysql-connection');
+const check_authentication = require('../../middleware/check-auth');
+const check_admin = require('../../middleware/check-admin.js');
+
+const check_if_sender_exists = (request, response, next) => {
+ user_id = request.params.user_id;
+ query = "SELECT * FROM interaction_senders WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!rows.length) {
+ const sender_error = new Error("User (" + user_id + ") Does Not Exist");
+ sender_error.status = 404;
+ next(sender_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+const check_if_sender_does_not_exist = (request, response, next) => {
+ user_id = request.params.user_id;
+ query = "SELECT * FROM interaction_senders WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!!rows.length) {
+ const sender_error = new Error("User (" + user_id + ") Already Exists");
+ sender_error.status = 409;
+ next(sender_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+const check_if_receiver_exists = (request, response, next) => {
+ user_id = request.params.user_id;
+ query = "SELECT * FROM interaction_receivers WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!rows.length) {
+ const receiver_error = new Error("User (" + user_id + ") Does Not Exist");
+ receiver_error.status = 404;
+ next(receiver_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+const check_if_receiver_does_not_exist = (request, response, next) => {
+ user_id = request.params.user_id;
+ query = "SELECT * FROM interaction_receivers WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!!rows.length) {
+ const receiver_error = new Error("User (" + user_id + ") Already Exists");
+ receiver_error.status = 409;
+ next(receiver_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+// Gets all interaction senders.
+router.get("/interactions/senders", check_authentication, check_admin, (request, response, next) => {
+ query = "SELECT * FROM interaction_senders;";
+ getConnection().query(query, (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ interactions_sent: rows,
+ message: "Successfully Retrieved Interaction Senders"
+ });
+ return;
+ });
+});
+
+// Gets all interactions sent from a specified user.
+router.get("/interactions/senders/:user_id", check_authentication, check_if_sender_exists, (request, response, next) => {
+ user_id = request.params.user_id;
+
+ type = request.query.type;
+
+ query = "SELECT * FROM interaction_senders WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!type) {
+ response.status(200).json({
+ interactions_sent: rows[0],
+ message: "Successfully Retrieved Interactions Sent for User (" + user_id + ")"
+ });
+ return;
+ } else {
+
+ var type_amount;
+ type += "_amount"
+
+ if (!rows[0][type] === undefined) {
+ type_amount = type + " Does Not Exist";
+ } else {
+ type_amount = rows[0][type];
+ }
+
+ response.status(200).json({
+ [type]: type_amount,
+ message: "Successfully Retrieved " + type + " Interactions Sent for User (" + user_id + ")"
+ });
+ return;
+ }
+ });
+});
+
+// Updates interactions for a user.
+router.patch("/interactions/senders/:user_id", check_authentication, check_admin, check_if_sender_exists, (request, response, next) => {
+ user_id = request.params.user_id;
+ type = request.query.type;
+ value = request.query.value;
+
+ if (!type || !value) {
+ response.status(500).json({
+ variables: {
+ user_id: user_id,
+ type: type || "undefined",
+ value: value || "undefined"
+ },
+ message: "A Variable is Undefined"
+ });
+ return;
+ }
+
+ type += "_amount"
+
+ query = "UPDATE interaction_senders SET ?? = (?) WHERE user_id = (?);";
+ getConnection().query(query, [type, value, user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Updated " + type + " for User (" + user_id + ")"
+ });
+ return;
+ });
+});
+
+// Inserts a new interaction sender.
+router.post("/interactions/senders/:user_id", check_authentication, check_admin, check_if_sender_does_not_exist, (request, response, next) => {
+ user_id = request.params.user_id;
+
+ query = "INSERT INTO interaction_senders (user_id) VALUES (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(error);
+ return;
+ }
+
+ response.status(201).json({
+ message: "Successfully Created Interaction Sender User (" + user_id + ")"
+ });
+ return;
+ });
+});
+
+// Deletes an interaction sender.
+router.delete("/interactions/senders/:user_id", check_authentication, check_admin, (request, response, next) => {
+ user_id = request.params.user_id;
+
+ query = "DELETE FROM interaction_senders WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Removed User (" + user_id + ") From Interaction Senders"
+ });
+ return;
+ });
+});
+
+// ========================================
+// INTERACTIONS RECEIVED
+// ========================================
+
+// Gets all interaction receivers.
+router.get("/interactions/receivers", check_authentication, check_admin, (request, response, next) => {
+ query = "SELECT * FROM interaction_receivers;";
+ getConnection().query(query, (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ interactions_received: rows,
+ message: "Successfully Retrieved Interaction Receivers"
+ });
+ return;
+ })
+});
+
+// Gets all interactions received for a specified user.
+router.get("/interactions/receivers/:user_id", check_authentication, check_if_receiver_exists, (request, response, next) => {
+ user_id = request.params.user_id;
+
+ type = request.query.type;
+
+ query = "SELECT * FROM interaction_receivers WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!type) {
+ response.status(200).json({
+ interactions_received: rows[0],
+ message: "Successfully Retrieved Interactions Received for User (" + user_id + ")"
+ });
+ return;
+ } else {
+ var type_amount;
+ type += "_amount"
+
+ if (!rows[0][type] === undefined) {
+ type_amount = type + " Does Not Exist";
+ } else {
+ type_amount = rows[0][type];
+ }
+
+ response.status(200).json({
+ [type]: type_amount,
+ message: "Successfully Retrieved " + type + " Interactions Received for User (" + user_id + ")"
+ });
+ return;
+ }
+ });
+});
+
+// Updates interactions for a user.
+router.patch("/interactions/receivers/:user_id", check_authentication, check_admin, check_if_receiver_exists, (request, response, next) => {
+ user_id = request.params.user_id;
+ type = request.query.type;
+ value = request.query.value;
+
+ if (!type || !value) {
+ response.status(500).json({
+ variables: {
+ user_id: user_id,
+ type: type || "undefined",
+ value: value || "undefined"
+ },
+ message: "A Variable is Undefined"
+ });
+ return;
+ }
+
+ type += "_amount"
+
+ query = "UPDATE interaction_receivers SET ?? = (?) WHERE user_id = (?);";
+ getConnection().query(query, [type, value, user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Updated " + type + " for User (" + user_id + ")"
+ });
+ return;
+ });
+});
+
+// Inserts a new interaction receiver
+router.post("/interactions/receivers/:user_id", check_authentication, check_admin, check_if_receiver_does_not_exist, (request, response, next) => {
+
+ user_id = request.params.user_id;
+
+ query = "INSERT INTO interaction_receivers (user_id) VALUES (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(201).json({
+ message: "Successfully Created Interaction Receiver User (" + user_id + ")"
+ });
+ return;
+ });
+});
+
+// Deletes a user from interaction receivers.
+router.delete("/interactions/receivers/:user_id", check_authentication, check_admin, (request, response, next) => {
+ user_id = request.params.user_id;
+
+ query = "DELETE FROM interaction_receivers WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Removed User (" + user_id + ") From Interaction Receivers"
+ });
+ return;
+ });
+});
+
+module.exports = router;
diff --git a/api/routes/cafeBot/minigames.js b/api/routes/cafeBot/minigames.js
new file mode 100644
index 00000000..bee1b433
--- /dev/null
+++ b/api/routes/cafeBot/minigames.js
@@ -0,0 +1,184 @@
+const express = require('express');
+const router = express.Router();
+
+const getConnection = require('./modules/mysql-connection');
+const check_authentication = require('../../middleware/check-auth');
+const check_admin = require('../../middleware/check-admin.js');
+
+const check_if_user_exists = (request, response, next) => {
+ user_id = request.params.user_id;
+
+ query = "SELECT * FROM minigames_win_streaks WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!rows.length) {
+ user_error = new Error("User (" + user_id + ") Win Streaks Does Not Exist");
+ user_error.status = 404;
+ next(user_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+const check_if_user_does_not_exist = (request, response, next) => {
+ user_id = request.params.user_id;
+
+ query = "SELECT * FROM minigames_win_streaks WHERE user_id = (?);";
+
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!!rows.length) {
+ user_error = new Error("User (" + user_id + ") Win Streaks Already Exists");
+ user_error.status = 409;
+ next(user_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+// Retrieves all minigame win streaks.
+router.get("/minigames/win_streaks", check_authentication, check_admin, (request, response, next) => {
+ query = "SELECT * FROM minigames_win_streaks;";
+ getConnection().query(query, (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ win_streaks: rows,
+ message: "Successfully Retrieved Minigame Win Streaks"
+ })
+ });
+});
+
+// Retrieves minigame streaks for a specified user.
+router.get("/minigames/win_streaks/:user_id", check_authentication, check_if_user_exists, (request, response, next) => {
+ user_id = request.params.user_id;
+ query = "SELECT * FROM minigames_win_streaks WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ win_streaks: rows[0],
+ message: "Successfully Retrieved Minigame Win Streaks for User (" + user_id + ")"
+ });
+ return;
+ });
+});
+
+// Updates the minigame winstreaks for a specified user.
+router.patch("/minigames/win_streaks/:user_id", check_authentication, check_admin, check_if_user_exists, (request, response, next) => {
+ user_id = request.params.user_id;
+ // tic_tac_toe_streak = request.query.tic_tac_toe_streak;
+ // connect_four_streak = request.query.connect_four_streak;
+
+ type = request.query.type;
+ value = request.query.value;
+
+ var valid_variables = {
+ tic_tac_toe: "Integer",
+ connect_four: "Integer"
+ };
+
+ if (!type || !valid_variables[type]) {
+ response.status(400).json({
+ valid_variables,
+ message: "A Valid Type is Missing"
+ });
+ return;
+ }
+
+ // Retrieves the value of the key, "type"
+ value_type = Object.getOwnPropertyDescriptor(valid_variables, type).value;
+
+ if (!value) {
+ response.status(400).json({
+ variables_required: {
+ type: type,
+ value_type: value_type
+ },
+ message: "A Value Is Required",
+ example: "If the type is a Timestamp, then the value would be 2021-07-07 13:46:36."
+ });
+ return;
+ }
+
+ // if (!tic_tac_toe_streak || !connect_four_streak) {
+ // response.status(500).json({
+ // variables: {
+ // user_id: user_id,
+ // tic_tac_toe_streak: tic_tac_toe_streak || "undefined",
+ // connect_four_streak: connect_four_streak || "undefined"
+ // },
+ // message: "A Variable is Undefined"
+ // });
+ // return;
+ // }
+
+ query = "UPDATE minigames_win_streaks SET ?? = (?) WHERE user_id = (?);";
+ getConnection().query(query, [type, value, user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Updated Win Streaks for User (" + user_id + ")"
+ });
+ return;
+ });
+});
+
+// Creating a new win streak for a specified user.
+router.post("/minigames/win_streaks/:user_id", check_authentication, check_admin, check_if_user_does_not_exist, (request, response, next) => {
+ user_id = request.params.user_id;
+
+ query = "INSERT INTO minigames_win_streaks (user_id) VALUES (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(201).json({
+ message: "Successfully Created New Win Streak for User (" + user_id + ")"
+ });
+ return;
+ });
+});
+
+// Deletes a win streak for a specified user.
+router.delete("/minigames/win_streaks/:user_id", check_authentication, check_admin, (request, response, next) => {
+ user_id = request.params.user_id;
+
+ query = "DELETE FROM minigames_win_streaks WHERE user_id = (?);";
+ getConnection().query(query, [user_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Deleted User (" + user_id + ")"
+ });
+ return;
+ });
+});
+
+module.exports = router;
diff --git a/api/routes/cafeBot/modules/mysql-connection.js b/api/routes/cafeBot/modules/mysql-connection.js
new file mode 100644
index 00000000..69078e40
--- /dev/null
+++ b/api/routes/cafeBot/modules/mysql-connection.js
@@ -0,0 +1,22 @@
+const mysql = require('mysql2');
+const checkType = require('../../../middleware/check-type');
+
+// TODO: Confirm this works.
+const mySQL_DATA = checkType.getMySQLData();
+const mysql_database = "cafeBot";
+
+// Creates a MySQL pool. Allows multiple connections.
+const pool = mysql.createPool({
+ connectionLimit: 200,
+ host: mySQL_DATA.url,
+ port: mySQL_DATA.port,
+ user: mySQL_DATA.user,
+ password: mySQL_DATA.password,
+ database: mysql_database,
+ supportBigNumbers: true,
+ bigNumberStrings: true
+});
+
+module.exports = () => {
+ return pool;
+}
diff --git a/api/routes/cafeBot/polls.js b/api/routes/cafeBot/polls.js
new file mode 100644
index 00000000..6d7b8394
--- /dev/null
+++ b/api/routes/cafeBot/polls.js
@@ -0,0 +1,141 @@
+const express = require('express');
+const router = express.Router();
+
+const getConnection = require('./modules/mysql-connection');
+const check_authentication = require('../../middleware/check-auth');
+const check_admin = require('../../middleware/check-admin.js');
+
+const check_if_poll_does_not_exist = (request, response, next) => {
+ guild_id = request.params.guild_id;
+ message_id = request.query.message_id;
+
+ if (!message_id) {
+ response.status(400).json({
+ variables: {
+ guild_id: guild_id,
+ message_id: message_id || "undefined"
+ },
+ message: "A Variable is Undefined"
+ });
+ return;
+ }
+
+ query = "SELECT * FROM polls WHERE guild_id = (?) AND message_id = (?);";
+ getConnection().query(query, [guild_id, message_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!!rows.length) {
+ const poll_error = new Error("A Poll with Message ID (" + message_id + ") For Guild (" + guild_id + ") Already Exists");
+ poll_error.status = 409;
+ next(poll_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+// Retrieves all polls
+router.get("/polls", check_authentication, check_admin, (request, response, next) => {
+ query = "SELECT * FROM polls;";
+ getConnection().query(query, (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ polls: rows,
+ message: "Successfully Retrieved All Polls"
+ });
+ return;
+ });
+});
+
+// Retrieves all polls for a specific guild.
+router.get("/polls/:guild_id", check_authentication, check_admin, (request, response, next) => {
+ guild_id = request.params.guild_id;
+
+ query = "SELECT * FROM polls WHERE guild_id = (?);";
+ getConnection().query(query, [guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ polls: rows,
+ message: "Successfully Retrieved Polls for Guild (" + guild_id + ")"
+ });
+ return;
+ });
+});
+
+// Adds a new poll
+router.post("/polls/:guild_id", check_authentication, check_admin, check_if_poll_does_not_exist, (request, response, next) => {
+ guild_id = request.params.guild_id;
+
+ message_id = request.query.message_id;
+ ending_time = request.query.ending_time;
+
+ if (!message_id || !ending_time) {
+ response.status(400).json({
+ variables: {
+ guild_id: guild_id,
+ message_id: message_id || "undefined",
+ ending_time: ending_time || "undefined"
+ },
+ message: "A Variable is Undefined"
+ });
+ return;
+ }
+
+ query = "INSERT INTO polls (guild_id, message_id, ending_time) VALUES (?,?,?);";
+ getConnection().query(query, [guild_id, message_id, ending_time], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(201).json({
+ message: "Successfully Created POLL for Guild (" + guild_id + ")"
+ });
+ return;
+ });
+});
+
+// Deletes a poll
+router.delete("/polls/:guild_id", check_authentication, check_admin, (request, response, next) => {
+ guild_id = request.params.guild_id;
+
+ message_id = request.query.message_id;
+
+ if (!message_id) {
+ response.status(400).json({
+ variables: {
+ guild_id: guild_id,
+ message_id: message_id || "undefined"
+ },
+ message: "A Variable is Undefined"
+ });
+ return;
+ }
+
+ query = "DELETE FROM polls WHERE guild_id = (?) AND message_id = (?);";
+ getConnection().query(query, [guild_id, message_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Deleted Poll from Guild (" + guild_id + ")"
+ });
+ return;
+ });
+});
+
+module.exports = router;
diff --git a/api/routes/cafeBot/raffles.js b/api/routes/cafeBot/raffles.js
new file mode 100644
index 00000000..93c95ff6
--- /dev/null
+++ b/api/routes/cafeBot/raffles.js
@@ -0,0 +1,142 @@
+const express = require('express');
+const router = express.Router();
+
+const getConnection = require('./modules/mysql-connection');
+const check_authentication = require('../../middleware/check-auth');
+const check_admin = require('../../middleware/check-admin.js');
+
+const check_if_raffle_does_not_exist = (request, response, next) => {
+ guild_id = request.params.guild_id;
+ message_id = request.query.message_id;
+
+ if (!message_id) {
+ response.status(400).json({
+ variables: {
+ guild_id: guild_id,
+ message_id: message_id || "undefined"
+ },
+ message: "A Variable is Undefined"
+ });
+ return;
+ }
+
+ query = "SELECT * FROM raffles WHERE guild_id = (?) AND message_id = (?);";
+ getConnection().query(query, [guild_id, message_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!!rows.length) {
+ const raffle_error = new Error("A Raffle with Message ID (" + message_id + ") For Guild (" + guild_id + ") Already Exists");
+ raffle_error.status = 409;
+ next(raffle_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+// Retrieves all raffles.
+router.get("/raffles", check_authentication, check_admin, (request, response, next) => {
+ query = "SELECT * FROM raffles;";
+ getConnection().query(query, (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ raffles: rows,
+ message: "Successfully Retrieved All Raffles"
+ });
+ return;
+ });
+});
+
+// Gets all raffles for a specific guild.
+router.get("/raffles/:guild_id", check_authentication, check_admin, (request, response, next) => {
+ guild_id = request.params.guild_id;
+ query = "SELECT * FROM raffles WHERE guild_id = (?);";
+ getConnection().query(query, [guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ raffles: rows,
+ message: "Successfully Retrieved Raffles for Guild (" + guild_id + ")"
+ });
+ return;
+ });
+});
+
+// Creates a new raffle.
+router.post("/raffles/:guild_id", check_authentication, check_admin, check_if_raffle_does_not_exist, (request, response, next) => {
+ guild_id = request.params.guild_id;
+
+ message_id = request.query.message_id;
+ ending_time = request.query.ending_time;
+ winner_amount = request.query.winner_amount;
+
+ if (!message_id || !ending_time || !winner_amount) {
+ response.status(400).json({
+ variables: {
+ guild_id: guild_id,
+ message_id: message_id || "undefined",
+ ending_time: ending_time || "undefined",
+ winner_amount: winner_amount || "undefined"
+ },
+ message: "A Variable is Undefined"
+ });
+ return;
+ }
+
+ query = "INSERT INTO raffles (guild_id, message_id, ending_time, winner_amount) VALUES (?,?,?,?);";
+ getConnection().query(query, [guild_id, message_id, ending_time, winner_amount], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(201).json({
+ message: "Successfully Inserted Raffle to Guild (" + guild_id + ")"
+ });
+ return;
+ });
+});
+
+// Deletes a raffle from a guild.
+router.delete("/raffles/:guild_id", check_authentication, check_admin, (request, response, next) => {
+ guild_id = request.params.guild_id;
+
+ message_id = request.query.message_id;
+
+ if (!message_id) {
+ response.status(500).json({
+ variables: {
+ guild_id: guild_id,
+ message_id: message_id || "undefined"
+ },
+ message: "A Variable is Undefined"
+ });
+ return;
+ }
+
+ query = "DELETE FROM raffles WHERE guild_id = (?) AND message_id = (?);";
+ getConnection().query(query, [guild_id, message_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Deleted Raffle from Guild (" + guild_id + ")"
+ });
+ return;
+ });
+});
+
+module.exports = router;
diff --git a/api/routes/cafeBot/voice_binds.js b/api/routes/cafeBot/voice_binds.js
new file mode 100644
index 00000000..84b6d51b
--- /dev/null
+++ b/api/routes/cafeBot/voice_binds.js
@@ -0,0 +1,123 @@
+const express = require('express');
+const router = express.Router();
+
+const getConnection = require('./modules/mysql-connection');
+const check_authentication = require('../../middleware/check-auth');
+const check_admin = require('../../middleware/check-admin.js');
+
+// Gets all voice channel role binds.
+router.get("/voice_binds", check_authentication, check_admin, (request, response, next) => {
+ query = "SELECT * FROM voice_channel_role_binds;";
+ getConnection().query(query, (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ voice_binds: rows,
+ message: "Successfully Retrieved All Voice Channel Role Binds"
+ });
+ return;
+ });
+});
+
+// Gets all voice binds for that guild.
+router.get("/voice_binds/:guild_id", check_authentication, check_admin, (request, response, next) => {
+ guild_id = request.params.guild_id;
+
+ query = "SELECT * FROM voice_channel_role_binds WHERE guild_id = (?);";
+ getConnection().query(query, [guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ voice_binds: rows,
+ message: "Successfully Retrieved Binds for Guild (" + guild_id + ")"
+ });
+ return;
+ });
+});
+
+// Adds a new voice bind for a guild.
+router.post("/voice_binds/:guild_id", check_authentication, check_admin, (request, response, next) => {
+ guild_id = request.params.guild_id;
+ voice_channel_id = request.query.voice_channel_id;
+ role_id = request.query.role_id;
+
+ if (!voice_channel_id || !role_id) {
+ response.status(400).json({
+ variables: {
+ guild_id: guild_id,
+ voice_channel_id: voice_channel_id || "undefined",
+ role_id: role_id || "undefined"
+ },
+ message: "A Variable is Undefined"
+ });
+ return;
+ }
+
+ check_query = "SELECT * FROM voice_channel_role_binds WHERE guild_id = (?) AND voice_channel_id = (?) AND role_id = (?);";
+ getConnection().query(check_query, [guild_id, voice_channel_id, role_id], (check_error, check_rows, check_fields) => {
+ if (check_error) {
+ next(new Error(check_error));
+ return;
+ }
+
+ if (!check_rows.length) {
+ query = "INSERT INTO voice_channel_role_binds (guild_id, voice_channel_id, role_id) VALUES (?,?,?);";
+ getConnection().query(query, [guild_id, voice_channel_id, role_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(201).json({
+ message: "Successfully Created New Bind for Guild (" + guild_id + ")"
+ });
+ return;
+ });
+ } else {
+ response.status(409).json({
+ message: "That Bind for the Guild (" + guild_id + ") Already Exists"
+ });
+ return;
+ }
+ });
+});
+
+// Deletes a voice channel bind.
+router.delete("/voice_binds/:guild_id", check_authentication, check_admin, (request, response, next) => {
+ guild_id = request.params.guild_id;
+ voice_channel_id = request.query.voice_channel_id;
+ role_id = request.query.role_id;
+
+ if (!voice_channel_id || !role_id) {
+ response.status(500).json({
+ variables: {
+ guild_id: guild_id,
+ voice_channel_id: voice_channel_id || "undefined",
+ role_id: role_id || "undefined"
+ },
+ message: "A Variable is Undefined"
+ });
+ return;
+ }
+
+ query = "DELETE FROM voice_channel_role_binds WHERE guild_id = (?) AND voice_channel_id = (?) AND role_id = (?);";
+ getConnection().query(query, [guild_id, voice_channel_id, role_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Removed Role Bind for Guild (" + guild_id + ")"
+ });
+ return;
+ });
+});
+
+module.exports = router;
diff --git a/api/routes/cafeBot/welcomes.js b/api/routes/cafeBot/welcomes.js
new file mode 100644
index 00000000..de91a10c
--- /dev/null
+++ b/api/routes/cafeBot/welcomes.js
@@ -0,0 +1,150 @@
+const express = require('express');
+const router = express.Router();
+
+const getConnection = require('./modules/mysql-connection');
+const check_authentication = require('../../middleware/check-auth');
+const check_admin = require('../../middleware/check-admin.js');
+
+// Checks if a guild's welcome exists
+const check_if_guild_exists = (request, response, next) => {
+ guild_id = request.params.guild_id;
+ query = "SELECT * FROM welcome_information WHERE guild_id = (?);";
+
+ getConnection().query(query, [guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!rows.length) {
+ const guild_error = new Error("Guild (" + guild_id + ") Does Not Exist");
+ guild_error.status = 404;
+ next(guild_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+const check_if_guild_does_not_exist = (request, response, next) => {
+ guild_id = request.params.guild_id;
+ query = "SELECT * FROM welcome_information WHERE guild_id = (?);";
+
+ getConnection().query(query, [guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!!rows.length) {
+ const guild_error = new Error("Guild (" + guild_id + ") Already Exists");
+ guild_error.status = 409;
+ next(guild_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+// Gets all welcome information.
+router.get("/welcomes", check_authentication, check_admin, (request, response, next) => {
+ query = "SELECT * FROM welcome_information;";
+ getConnection().query(query, (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ welcomes: rows,
+ message: "Successfully Retrieved All Welcome Information"
+ });
+ return;
+ });
+});
+
+// Gets a specific guild's welcome information.
+router.get("/welcomes/:guild_id", check_authentication, check_admin, check_if_guild_exists, (request, response, next) => {
+ guild_id = request.params.guild_id;
+ query = "SELECT * FROM welcome_information WHERE guild_id = (?);";
+ getConnection().query(query, [guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ welcome: rows[0],
+ message: "Successfully Retrieved Welcome Information for Guild (" + guild_id + ")"
+ });
+ return;
+ });
+});
+
+// Updates a specific guild's welcome information
+router.patch("/welcomes/:guild_id", check_authentication, check_admin, check_if_guild_exists, (request, response, next) => {
+ guild_id = request.params.guild_id;
+ description = request.query.description || null;
+ thumbnail_url = request.query.thumbnail_url || null;
+ image_url = request.query.image_url || null;
+ message = request.query.message || null;
+
+ query = "UPDATE welcome_information SET description = (?), thumbnail_url = (?), image_url = (?), message = (?) WHERE guild_id = (?);";
+ getConnection().query(query, [description, thumbnail_url, image_url, message, guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Updated Welcome Information for Guild (" + guild_id + ")"
+ });
+ return;
+ });
+
+});
+
+// Adds a new guild welcome
+router.post("/welcomes/:guild_id", check_authentication, check_admin, check_if_guild_does_not_exist, (request, response, next) => {
+ guild_id = request.params.guild_id;
+
+ description = request.query.description || null;
+ thumbnail_url = request.query.thumbnail_url || null;
+ image_url = request.query.image_url || null;
+ message = request.query.message || null;
+
+ query = "INSERT INTO welcome_information (guild_id, description, thumbnail_url, image_url, message) VALUES (?,?,?,?,?);";
+ getConnection().query(query, [guild_id, description, thumbnail_url, image_url, message], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(201).json({
+ message: "Successfully Created Welcome Information for Guild (" + guild_id + ")"
+ });
+ return;
+ });
+});
+
+// Deletes a guild's welcome information
+router.delete("/welcomes/:guild_id", check_authentication, check_admin, (request, response, next) => {
+ guild_id = request.params.guild_id;
+
+ query = "DELETE FROM welcome_information WHERE guild_id = (?);";
+ getConnection().query(query, [guild_id], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Removed Welcome Information for Guild (" + guild_id + ")"
+ });
+ return;
+ });
+});
+
+module.exports = router;
diff --git a/api/routes/cafeBot/words.js b/api/routes/cafeBot/words.js
new file mode 100644
index 00000000..421bc099
--- /dev/null
+++ b/api/routes/cafeBot/words.js
@@ -0,0 +1,97 @@
+const express = require('express');
+const router = express.Router();
+
+const getConnection = require('./modules/mysql-connection');
+const check_authentication = require('../../middleware/check-auth');
+const check_admin = require('../../middleware/check-admin.js');
+
+// Checks if a word exists
+const check_if_word_exists = (request, response, next) => {
+ word = request.params.word;
+ query = "SELECT * FROM serve_words WHERE word = (?);";
+
+ getConnection().query(query, [word], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ if (!rows.length) {
+ const request_error = new Error("Word (" + word + ") Not Found");
+ request_error.status = 404;
+ next (request_error);
+ return;
+ }
+
+ next();
+ });
+}
+
+// Gets all dictionary words.
+router.get("/words", check_authentication, (request, response, next) => {
+ query = "SELECT * FROM serve_words;";
+
+ getConnection().query(query, (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ words: rows,
+ message: "Successfully Retrieved All Words"
+ });
+ return;
+ });
+});
+
+// Gets a specific word
+router.get("/words/:word", check_authentication, check_if_word_exists, (request, response, next) => {
+ word = request.params.word;
+
+ query = "SELECT * FROM serve_words WHERE word = (?);";
+ getConnection().query(query, [word], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ word: rows[0],
+ message: "Successfully Retrieved Word (" + word + ")"
+ });
+ return;
+ });
+});
+
+// Updates a specific word.
+router.patch("/words/:word", check_authentication, check_admin, check_if_word_exists, (request, response, next) => {
+ word = request.params.word;
+ uses = request.query.uses;
+
+ if (!uses) {
+ response.status(400).json({
+ variables: {
+ word: word,
+ uses: uses || "undefined"
+ },
+ message: "A Variable is Undefined"
+ });
+ return;
+ }
+
+ query = "UPDATE cafeBot.serve_words SET uses = (?) WHERE word = (?);";
+ getConnection().query(query, [uses, word], (error, rows, fields) => {
+ if (error) {
+ next(new Error(error));
+ return;
+ }
+
+ response.status(200).json({
+ message: "Successfully Updated Word (" + word + ") With Uses (" + uses + ")"
+ })
+ return;
+ });
+});
+
+module.exports = router;
diff --git a/api/sql/cafe/users.sql b/api/sql/cafe/users.sql
new file mode 100644
index 00000000..866b0567
--- /dev/null
+++ b/api/sql/cafe/users.sql
@@ -0,0 +1,9 @@
+CREATE TABLE users
+(
+user_id INT NOT NULL AUTO_INCREMENT,
+username TEXT NOT NULL,
+password TEXT NOT NULL,
+user_type VARCHAR(10) DEFAULT 'USER',
+PRIMARY KEY (user_id),
+UNIQUE KEY user_id_index (user_id)
+);
\ No newline at end of file
diff --git a/api/sql/cafeBot/beancoin_donation_users.sql b/api/sql/cafeBot/beancoin_donation_users.sql
new file mode 100644
index 00000000..67559bb6
--- /dev/null
+++ b/api/sql/cafeBot/beancoin_donation_users.sql
@@ -0,0 +1,3 @@
+CREATE TABLE beancoin_donation_users
+(user_id BIGINT,
+time_until_next_donation TIMESTAMP);
\ No newline at end of file
diff --git a/api/sql/cafeBot/birthdays.sql b/api/sql/cafeBot/birthdays.sql
new file mode 100644
index 00000000..56797e04
--- /dev/null
+++ b/api/sql/cafeBot/birthdays.sql
@@ -0,0 +1,5 @@
+CREATE TABLE birthdays
+(user_id BIGINT,
+birth_date TEXT,
+time_zone TEXT,
+already_mentioned TINYINT DEFAULT 0);
\ No newline at end of file
diff --git a/api/sql/cafeBot/bot_information.sql b/api/sql/cafeBot/bot_information.sql
new file mode 100644
index 00000000..41217223
--- /dev/null
+++ b/api/sql/cafeBot/bot_information.sql
@@ -0,0 +1,3 @@
+CREATE TABLE bot_information
+(id INT default 1,
+ version TEXT);
\ No newline at end of file
diff --git a/api/sql/cafeBot/cafe_information.sql b/api/sql/cafeBot/cafe_information.sql
new file mode 100644
index 00000000..42f405f3
--- /dev/null
+++ b/api/sql/cafeBot/cafe_information.sql
@@ -0,0 +1,6 @@
+CREATE TABLE cafe_information
+(user_id BIGINT,
+ bean_coins DOUBLE DEFAULT 0,
+ last_serving_time TIMESTAMP DEFAULT null,
+ orders_bought INT DEFAULT 0,
+ orders_received INT DEFAULT 0);
\ No newline at end of file
diff --git a/api/sql/cafeBot/counting_information.sql b/api/sql/cafeBot/counting_information.sql
new file mode 100644
index 00000000..ce78ed61
--- /dev/null
+++ b/api/sql/cafeBot/counting_information.sql
@@ -0,0 +1,6 @@
+CREATE TABLE counting_information
+(guild_id BIGINT,
+highest_number INT DEFAULT 0,
+last_number INT DEFAULT 0,
+last_user_id BIGINT DEFAULT 0,
+failure_role_id BIGINT DEFAULT 0);
\ No newline at end of file
diff --git a/api/sql/cafeBot/generated_codes.sql b/api/sql/cafeBot/generated_codes.sql
new file mode 100644
index 00000000..b7ee6e96
--- /dev/null
+++ b/api/sql/cafeBot/generated_codes.sql
@@ -0,0 +1,4 @@
+CREATE TABLE generated_codes
+(user_id BIGINT,
+generated_code VARCHAR(32),
+CONSTRAINT id PRIMARY KEY (user_id));
\ No newline at end of file
diff --git a/api/sql/cafeBot/goodbye_information.sql b/api/sql/cafeBot/goodbye_information.sql
new file mode 100644
index 00000000..40dcd2c2
--- /dev/null
+++ b/api/sql/cafeBot/goodbye_information.sql
@@ -0,0 +1,6 @@
+CREATE TABLE goodbye_information
+(guild_id BIGINT,
+description TEXT null,
+thumbnail_url TEXT null,
+image_url TEXT null,
+message TEXT null);
diff --git a/api/sql/cafeBot/guild_information.sql b/api/sql/cafeBot/guild_information.sql
new file mode 100644
index 00000000..2f36c0e1
--- /dev/null
+++ b/api/sql/cafeBot/guild_information.sql
@@ -0,0 +1,19 @@
+CREATE TABLE guild_information
+(guild_id BIGINT,
+prefix TEXT,
+moderator_role_id BIGINT DEFAULT 0,
+twitch_channel_id BIGINT DEFAULT 0,
+muted_role_id BIGINT DEFAULT 0,
+live_notifications_role_id BIGINT DEFAULT 0,
+notify_on_update TINYINT DEFAULT 1,
+update_channel_id BIGINT DEFAULT 0,
+counting_channel_id BIGINT DEFAULT 0,
+poll_channel_id BIGINT DEFAULT 0,
+raffle_channel_id BIGINT DEFAULT 0,
+birthday_channel_id BIGINT DEFAULT 0,
+welcome_channel_id BIGINT DEFAULT 0,
+goodbye_channel_id BIGINT DEFAULT 0,
+log_channel_id BIGINT DEFAULT 0,
+venting_channel_id BIGINT DEFAULT 0,
+ai_response TINYINT DEFAULT 0,
+daily_channel_id BIGINT DEFAULT 0);
diff --git a/api/sql/cafeBot/guild_twitch.sql b/api/sql/cafeBot/guild_twitch.sql
new file mode 100644
index 00000000..edcb661f
--- /dev/null
+++ b/api/sql/cafeBot/guild_twitch.sql
@@ -0,0 +1,2 @@
+CREATE TABLE guild_twitch
+(guild_id BIGINT, twitch_channel TEXT);
\ No newline at end of file
diff --git a/api/sql/cafeBot/interaction_receivers.sql b/api/sql/cafeBot/interaction_receivers.sql
new file mode 100644
index 00000000..3fbdfd9d
--- /dev/null
+++ b/api/sql/cafeBot/interaction_receivers.sql
@@ -0,0 +1,41 @@
+CREATE TABLE interaction_receivers
+(user_id BIGINT,
+hug_amount INT DEFAULT 0,
+punch_amount INT DEFAULT 0,
+kiss_amount INT DEFAULT 0,
+bite_amount INT DEFAULT 0,
+blush_amount INT DEFAULT 0,
+cuddle_amount INT DEFAULT 0,
+nom_amount INT DEFAULT 0,
+poke_amount INT DEFAULT 0,
+slap_amount INT DEFAULT 0,
+stab_amount INT DEFAULT 0,
+hmph_amount INT DEFAULT 0,
+pout_amount INT DEFAULT 0,
+throw_amount INT DEFAULT 0,
+smile_amount INT DEFAULT 0,
+stare_amount INT DEFAULT 0,
+tickle_amount INT DEFAULT 0,
+rage_amount INT DEFAULT 0,
+yell_amount INT DEFAULT 0,
+headpat_amount INT DEFAULT 0,
+cry_amount INT DEFAULT 0,
+dance_amount INT DEFAULT 0,
+dab_amount INT DEFAULT 0,
+bonk_amount INT DEFAULT 0,
+sleep_amount INT DEFAULT 0,
+die_amount INT DEFAULT 0,
+welcome_amount INT DEFAULT 0,
+lick_amount INT DEFAULT 0,
+shush_amount INT DEFAULT 0,
+wave_amount INT DEFAULT 0,
+shoot_amount INT DEFAULT 0,
+amazed_amount INT DEFAULT 0,
+ask_amount INT DEFAULT 0,
+boop_amount INT DEFAULT 0,
+love_amount INT DEFAULT 0,
+nosebleed_amount INT DEFAULT 0,
+ok_amount INT DEFAULT 0,
+uwu_amount INT DEFAULT 0,
+wink_amount INT DEFAULT 0,
+hide_amount INT DEFAULT 0);
diff --git a/api/sql/cafeBot/interaction_senders.sql b/api/sql/cafeBot/interaction_senders.sql
new file mode 100644
index 00000000..e8b9b72d
--- /dev/null
+++ b/api/sql/cafeBot/interaction_senders.sql
@@ -0,0 +1,42 @@
+CREATE TABLE interaction_senders
+(user_id BIGINT,
+hug_amount INT DEFAULT 0,
+punch_amount INT DEFAULT 0,
+kiss_amount INT DEFAULT 0,
+bite_amount INT DEFAULT 0,
+blush_amount INT DEFAULT 0,
+cuddle_amount INT DEFAULT 0,
+nom_amount INT DEFAULT 0,
+poke_amount INT DEFAULT 0,
+slap_amount INT DEFAULT 0,
+stab_amount INT DEFAULT 0,
+hmph_amount INT DEFAULT 0,
+pout_amount INT DEFAULT 0,
+throw_amount INT DEFAULT 0,
+smile_amount INT DEFAULT 0,
+stare_amount INT DEFAULT 0,
+tickle_amount INT DEFAULT 0,
+rage_amount INT DEFAULT 0,
+yell_amount INT DEFAULT 0,
+headpat_amount INT DEFAULT 0,
+cry_amount INT DEFAULT 0,
+dance_amount INT DEFAULT 0,
+dab_amount INT DEFAULT 0,
+bonk_amount INT DEFAULT 0,
+sleep_amount INT DEFAULT 0,
+die_amount INT DEFAULT 0,
+welcome_amount INT DEFAULT 0,
+lick_amount INT DEFAULT 0,
+shush_amount INT DEFAULT 0,
+wave_amount INT DEFAULT 0,
+shoot_amount INT DEFAULT 0,
+amazed_amount INT DEFAULT 0,
+ask_amount INT DEFAULT 0,
+boop_amount INT DEFAULT 0,
+love_amount INT DEFAULT 0,
+nosebleed_amount INT DEFAULT 0,
+ok_amount INT DEFAULT 0,
+uwu_amount INT DEFAULT 0,
+wink_amount INT DEFAULT 0,
+hide_amount INT DEFAULT 0
+);
diff --git a/api/sql/cafeBot/minigames_win_streaks.sql b/api/sql/cafeBot/minigames_win_streaks.sql
new file mode 100644
index 00000000..0319476e
--- /dev/null
+++ b/api/sql/cafeBot/minigames_win_streaks.sql
@@ -0,0 +1,4 @@
+CREATE TABLE minigames_win_streaks
+(user_id BIGINT,
+tic_tac_toe INT DEFAULT 0,
+connect_four INT DEFAULT 0);
\ No newline at end of file
diff --git a/api/sql/cafeBot/polls.sql b/api/sql/cafeBot/polls.sql
new file mode 100644
index 00000000..49b5ad28
--- /dev/null
+++ b/api/sql/cafeBot/polls.sql
@@ -0,0 +1,4 @@
+CREATE TABLE polls
+(guild_id BIGINT,
+message_id BIGINT,
+ending_time TIMESTAMP);
\ No newline at end of file
diff --git a/api/sql/cafeBot/raffles.sql b/api/sql/cafeBot/raffles.sql
new file mode 100644
index 00000000..9eaa1ef4
--- /dev/null
+++ b/api/sql/cafeBot/raffles.sql
@@ -0,0 +1,5 @@
+CREATE TABLE raffles
+(guild_id BIGINT,
+message_id BIGINT,
+ending_time TIMESTAMP,
+winner_amount INT);
\ No newline at end of file
diff --git a/api/sql/cafeBot/serve_words.sql b/api/sql/cafeBot/serve_words.sql
new file mode 100644
index 00000000..f99a8e3f
--- /dev/null
+++ b/api/sql/cafeBot/serve_words.sql
@@ -0,0 +1,3 @@
+CREATE TABLE serve_words
+(word TEXT,
+uses INT DEFAULT 0);
\ No newline at end of file
diff --git a/api/sql/cafeBot/voice_channel_role_binds.sql b/api/sql/cafeBot/voice_channel_role_binds.sql
new file mode 100644
index 00000000..1c989a77
--- /dev/null
+++ b/api/sql/cafeBot/voice_channel_role_binds.sql
@@ -0,0 +1,4 @@
+CREATE TABLE voice_channel_role_binds
+(guild_id BIGINT,
+voice_channel_id BIGINT,
+role_id BIGINT);
\ No newline at end of file
diff --git a/api/sql/cafeBot/welcome_information.sql b/api/sql/cafeBot/welcome_information.sql
new file mode 100644
index 00000000..246126c7
--- /dev/null
+++ b/api/sql/cafeBot/welcome_information.sql
@@ -0,0 +1,6 @@
+CREATE TABLE welcome_information
+(guild_id BIGINT,
+description TEXT null,
+thumbnail_url TEXT null,
+image_url TEXT null,
+message TEXT null);
\ No newline at end of file
diff --git a/.gitignore b/bot/.gitignore
similarity index 100%
rename from .gitignore
rename to bot/.gitignore
diff --git a/LICENSE b/bot/LICENSE
similarity index 100%
rename from LICENSE
rename to bot/LICENSE
diff --git a/build.gradle.kts b/bot/build.gradle.kts
similarity index 96%
rename from build.gradle.kts
rename to bot/build.gradle.kts
index d4a59b9f..45a9cddf 100644
--- a/build.gradle.kts
+++ b/bot/build.gradle.kts
@@ -92,6 +92,8 @@ dependencies {
implementation("com.fasterxml.jackson.core:jackson-databind:2.17.1")
+ implementation("org.apache.httpcomponents.client5:httpclient5:5.3.1") // OpenAI HTTP Requests
+
implementation("com.github.twitch4j", "twitch4j", "1.21.0")
compileOnly("org.projectlombok", "lombok", "1.18.32")
diff --git a/gradle/libs.versions.toml b/bot/gradle/libs.versions.toml
similarity index 100%
rename from gradle/libs.versions.toml
rename to bot/gradle/libs.versions.toml
diff --git a/gradle/wrapper/gradle-wrapper.properties b/bot/gradle/wrapper/gradle-wrapper.properties
similarity index 100%
rename from gradle/wrapper/gradle-wrapper.properties
rename to bot/gradle/wrapper/gradle-wrapper.properties
diff --git a/gradlew b/bot/gradlew
old mode 100755
new mode 100644
similarity index 100%
rename from gradlew
rename to bot/gradlew
diff --git a/gradlew.bat b/bot/gradlew.bat
similarity index 100%
rename from gradlew.bat
rename to bot/gradlew.bat
diff --git a/settings.gradle.kts b/bot/settings.gradle.kts
similarity index 100%
rename from settings.gradle.kts
rename to bot/settings.gradle.kts
diff --git a/src/main/java/com/beanbeanjuice/cafebot/CafeBot.java b/bot/src/main/java/com/beanbeanjuice/cafebot/CafeBot.java
similarity index 99%
rename from src/main/java/com/beanbeanjuice/cafebot/CafeBot.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/CafeBot.java
index b589c547..5705f503 100644
--- a/src/main/java/com/beanbeanjuice/cafebot/CafeBot.java
+++ b/bot/src/main/java/com/beanbeanjuice/cafebot/CafeBot.java
@@ -289,7 +289,7 @@ public void addEventListener(final ListenerAdapter listener) {
}
private void setupListeners() {
- this.aiResponseListener = new AIResponseListener(this);
+ this.aiResponseListener = new AIResponseListener(this, System.getenv("CAFEBOT_OPENAI_API_KEY"), System.getenv("CAFEBOT_OPENAI_ASSISTANT_ID"));
this.shardManager.addEventListener(
new BotAddListener(this),
new BotRemoveListener(this),
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/cafe/BalanceCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/cafe/BalanceCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/cafe/BalanceCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/cafe/BalanceCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/cafe/DonateCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/cafe/DonateCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/cafe/DonateCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/cafe/DonateCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/cafe/MenuCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/cafe/MenuCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/cafe/MenuCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/cafe/MenuCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/cafe/ServeCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/cafe/ServeCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/cafe/ServeCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/cafe/ServeCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/AvatarCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/AvatarCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/AvatarCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/AvatarCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/BannerCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/BannerCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/BannerCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/BannerCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/EightBallCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/EightBallCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/EightBallCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/EightBallCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/JokeCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/JokeCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/JokeCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/JokeCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/birthday/BirthdayCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/birthday/BirthdayCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/birthday/BirthdayCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/birthday/BirthdayCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/birthday/BirthdayGetSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/birthday/BirthdayGetSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/birthday/BirthdayGetSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/birthday/BirthdayGetSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/birthday/channel/BirthdayChannelRemoveSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/birthday/channel/BirthdayChannelRemoveSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/birthday/channel/BirthdayChannelRemoveSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/birthday/channel/BirthdayChannelRemoveSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/birthday/channel/BirthdayChannelSetSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/birthday/channel/BirthdayChannelSetSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/birthday/channel/BirthdayChannelSetSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/birthday/channel/BirthdayChannelSetSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/birthday/self/BirthdayRemoveSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/birthday/self/BirthdayRemoveSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/birthday/self/BirthdayRemoveSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/birthday/self/BirthdayRemoveSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/birthday/self/BirthdaySetSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/birthday/self/BirthdaySetSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/birthday/self/BirthdaySetSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/birthday/self/BirthdaySetSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/counting/CountingCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/counting/CountingCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/counting/CountingCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/counting/CountingCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/counting/CountingStatisticsSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/counting/CountingStatisticsSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/counting/CountingStatisticsSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/counting/CountingStatisticsSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/counting/RemoveCountingChannelSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/counting/RemoveCountingChannelSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/counting/RemoveCountingChannelSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/counting/RemoveCountingChannelSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/counting/RemoveFailureRoleSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/counting/RemoveFailureRoleSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/counting/RemoveFailureRoleSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/counting/RemoveFailureRoleSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/counting/SetCountingChannelSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/counting/SetCountingChannelSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/counting/SetCountingChannelSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/counting/SetCountingChannelSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/counting/SetFailureRoleSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/counting/SetFailureRoleSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/counting/SetFailureRoleSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/counting/SetFailureRoleSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/meme/CoffeeMemeSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/meme/CoffeeMemeSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/meme/CoffeeMemeSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/meme/CoffeeMemeSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/meme/MemeCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/meme/MemeCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/meme/MemeCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/meme/MemeCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/meme/RandomMemeSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/meme/RandomMemeSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/meme/RandomMemeSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/meme/RandomMemeSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/meme/TeaMemeSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/meme/TeaMemeSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/meme/TeaMemeSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/meme/TeaMemeSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/rate/RateCaffeinatedSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/rate/RateCaffeinatedSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/rate/RateCaffeinatedSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/rate/RateCaffeinatedSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/rate/RateCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/rate/RateCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/rate/RateCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/rate/RateCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/rate/RateInsaneSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/rate/RateInsaneSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/rate/RateInsaneSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/rate/RateInsaneSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/rate/RatePoorSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/rate/RatePoorSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/rate/RatePoorSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/rate/RatePoorSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/rate/RateSimpSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/rate/RateSimpSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/rate/RateSimpSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/rate/RateSimpSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/fun/rate/RateSmartSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/rate/RateSmartSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/fun/rate/RateSmartSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/fun/rate/RateSmartSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/games/CoinFlipCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/games/CoinFlipCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/games/CoinFlipCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/games/CoinFlipCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/games/DiceRollCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/games/DiceRollCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/games/DiceRollCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/games/DiceRollCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/games/TicTacToeCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/games/TicTacToeCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/games/TicTacToeCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/games/TicTacToeCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/games/game/DataSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/games/game/DataSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/games/game/DataSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/games/game/DataSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/games/game/GameCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/games/game/GameCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/games/game/GameCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/games/game/GameCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/generic/BotDonateCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/BotDonateCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/generic/BotDonateCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/BotDonateCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/generic/BotInviteCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/BotInviteCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/generic/BotInviteCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/BotInviteCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/generic/BotUpvoteCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/BotUpvoteCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/generic/BotUpvoteCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/BotUpvoteCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/generic/BugReportCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/BugReportCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/generic/BugReportCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/BugReportCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/generic/DefineCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/DefineCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/generic/DefineCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/DefineCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/generic/EmbedCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/EmbedCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/generic/EmbedCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/EmbedCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/generic/FeatureCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/FeatureCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/generic/FeatureCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/FeatureCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/generic/GenerateCode.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/GenerateCode.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/generic/GenerateCode.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/GenerateCode.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/generic/HelpCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/HelpCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/generic/HelpCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/HelpCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/generic/InfoCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/InfoCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/generic/InfoCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/InfoCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/generic/PingCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/PingCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/generic/PingCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/PingCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/generic/RemoveMyDataCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/RemoveMyDataCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/generic/RemoveMyDataCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/RemoveMyDataCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/generic/StatsCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/StatsCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/generic/StatsCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/StatsCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/generic/SupportCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/SupportCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/generic/SupportCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/SupportCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/generic/VersionCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/VersionCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/generic/VersionCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/VersionCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/generic/WhoCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/WhoCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/generic/WhoCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/generic/WhoCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/AmazedCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/AmazedCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/AmazedCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/AmazedCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/AskCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/AskCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/AskCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/AskCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/BiteCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/BiteCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/BiteCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/BiteCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/BlushCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/BlushCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/BlushCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/BlushCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/BonkCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/BonkCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/BonkCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/BonkCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/BoopCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/BoopCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/BoopCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/BoopCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/CryCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/CryCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/CryCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/CryCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/CuddleCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/CuddleCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/CuddleCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/CuddleCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/DabCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/DabCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/DabCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/DabCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/DanceCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/DanceCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/DanceCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/DanceCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/DieCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/DieCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/DieCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/DieCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/GreetCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/GreetCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/GreetCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/GreetCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/HeadPatCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/HeadPatCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/HeadPatCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/HeadPatCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/HmphCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/HmphCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/HmphCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/HmphCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/HugCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/HugCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/HugCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/HugCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/KissCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/KissCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/KissCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/KissCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/LickCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/LickCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/LickCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/LickCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/LoveCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/LoveCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/LoveCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/LoveCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/NomCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/NomCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/NomCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/NomCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/NoseBleedCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/NoseBleedCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/NoseBleedCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/NoseBleedCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/OkCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/OkCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/OkCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/OkCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/PokeCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/PokeCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/PokeCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/PokeCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/PoutCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/PoutCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/PoutCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/PoutCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/PunchCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/PunchCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/PunchCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/PunchCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/RageCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/RageCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/RageCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/RageCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/ShootCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/ShootCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/ShootCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/ShootCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/ShushCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/ShushCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/ShushCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/ShushCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/SlapCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/SlapCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/SlapCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/SlapCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/SleepCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/SleepCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/SleepCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/SleepCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/SmileCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/SmileCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/SmileCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/SmileCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/StabCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/StabCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/StabCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/StabCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/StareCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/StareCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/StareCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/StareCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/ThrowCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/ThrowCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/ThrowCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/ThrowCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/TickleCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/TickleCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/TickleCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/TickleCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/UWUCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/UWUCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/UWUCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/UWUCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/WaveCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/WaveCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/WaveCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/WaveCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/WinkCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/WinkCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/WinkCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/WinkCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/YellCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/YellCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/interaction/YellCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/interaction/YellCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/ClearChatCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/ClearChatCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/moderation/ClearChatCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/ClearChatCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/polls/PollCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/polls/PollCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/moderation/polls/PollCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/polls/PollCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/polls/PollCreateModalListener.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/polls/PollCreateModalListener.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/moderation/polls/PollCreateModalListener.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/polls/PollCreateModalListener.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/polls/PollCreateSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/polls/PollCreateSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/moderation/polls/PollCreateSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/polls/PollCreateSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/polls/channel/PollChannelRemoveSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/polls/channel/PollChannelRemoveSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/moderation/polls/channel/PollChannelRemoveSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/polls/channel/PollChannelRemoveSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/polls/channel/PollChannelSetSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/polls/channel/PollChannelSetSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/moderation/polls/channel/PollChannelSetSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/polls/channel/PollChannelSetSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/raffles/RaffleCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/raffles/RaffleCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/moderation/raffles/RaffleCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/raffles/RaffleCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/raffles/RaffleCreateSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/raffles/RaffleCreateSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/moderation/raffles/RaffleCreateSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/raffles/RaffleCreateSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/raffles/channel/RaffleChannelRemoveSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/raffles/channel/RaffleChannelRemoveSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/moderation/raffles/channel/RaffleChannelRemoveSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/raffles/channel/RaffleChannelRemoveSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/raffles/channel/RaffleChannelSetSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/raffles/channel/RaffleChannelSetSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/moderation/raffles/channel/RaffleChannelSetSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/moderation/raffles/channel/RaffleChannelSetSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/settings/AICommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/AICommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/settings/AICommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/AICommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/settings/CustomChannelsCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/CustomChannelsCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/settings/CustomChannelsCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/CustomChannelsCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/settings/daily/DailyCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/daily/DailyCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/settings/daily/DailyCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/daily/DailyCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/settings/daily/DailyRemoveSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/daily/DailyRemoveSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/settings/daily/DailyRemoveSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/daily/DailyRemoveSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/settings/daily/DailySetSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/daily/DailySetSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/settings/daily/DailySetSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/daily/DailySetSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/settings/goodbye/GoodbyeCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/goodbye/GoodbyeCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/settings/goodbye/GoodbyeCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/goodbye/GoodbyeCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/settings/goodbye/channel/GoodbyeChannelRemoveSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/goodbye/channel/GoodbyeChannelRemoveSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/settings/goodbye/channel/GoodbyeChannelRemoveSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/goodbye/channel/GoodbyeChannelRemoveSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/settings/goodbye/channel/GoodbyeChannelSetSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/goodbye/channel/GoodbyeChannelSetSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/settings/goodbye/channel/GoodbyeChannelSetSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/goodbye/channel/GoodbyeChannelSetSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/settings/goodbye/message/GoodbyeMessageModalListener.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/goodbye/message/GoodbyeMessageModalListener.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/settings/goodbye/message/GoodbyeMessageModalListener.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/goodbye/message/GoodbyeMessageModalListener.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/settings/goodbye/message/GoodbyeMessageRemoveSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/goodbye/message/GoodbyeMessageRemoveSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/settings/goodbye/message/GoodbyeMessageRemoveSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/goodbye/message/GoodbyeMessageRemoveSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/settings/goodbye/message/GoodbyeMessageSetSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/goodbye/message/GoodbyeMessageSetSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/settings/goodbye/message/GoodbyeMessageSetSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/goodbye/message/GoodbyeMessageSetSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/settings/update/UpdateCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/update/UpdateCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/settings/update/UpdateCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/update/UpdateCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/settings/update/UpdateStatusSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/update/UpdateStatusSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/settings/update/UpdateStatusSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/update/UpdateStatusSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/settings/update/channel/UpdateChannelRemoveSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/update/channel/UpdateChannelRemoveSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/settings/update/channel/UpdateChannelRemoveSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/update/channel/UpdateChannelRemoveSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/settings/update/channel/UpdateChannelSetSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/update/channel/UpdateChannelSetSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/settings/update/channel/UpdateChannelSetSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/update/channel/UpdateChannelSetSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/settings/welcome/WelcomeCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/welcome/WelcomeCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/settings/welcome/WelcomeCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/welcome/WelcomeCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/settings/welcome/channel/WelcomeChannelRemoveSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/welcome/channel/WelcomeChannelRemoveSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/settings/welcome/channel/WelcomeChannelRemoveSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/welcome/channel/WelcomeChannelRemoveSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/settings/welcome/channel/WelcomeChannelSetSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/welcome/channel/WelcomeChannelSetSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/settings/welcome/channel/WelcomeChannelSetSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/welcome/channel/WelcomeChannelSetSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/settings/welcome/message/WelcomeMessageModalListener.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/welcome/message/WelcomeMessageModalListener.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/settings/welcome/message/WelcomeMessageModalListener.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/welcome/message/WelcomeMessageModalListener.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/settings/welcome/message/WelcomeMessageRemoveSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/welcome/message/WelcomeMessageRemoveSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/settings/welcome/message/WelcomeMessageRemoveSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/welcome/message/WelcomeMessageRemoveSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/settings/welcome/message/WelcomeMessageSetSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/welcome/message/WelcomeMessageSetSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/settings/welcome/message/WelcomeMessageSetSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/settings/welcome/message/WelcomeMessageSetSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/social/MemberCountCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/social/MemberCountCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/social/MemberCountCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/social/MemberCountCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/social/vent/RemoveVentChannelSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/social/vent/RemoveVentChannelSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/social/vent/RemoveVentChannelSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/social/vent/RemoveVentChannelSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/social/vent/SetVentChannelSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/social/vent/SetVentChannelSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/social/vent/SetVentChannelSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/social/vent/SetVentChannelSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/social/vent/VentCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/social/vent/VentCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/social/vent/VentCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/social/vent/VentCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/social/vent/VentSendSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/social/vent/VentSendSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/social/vent/VentSendSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/social/vent/VentSendSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/twitch/TwitchCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/twitch/TwitchCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/twitch/TwitchCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/twitch/TwitchCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/twitch/channel/TwitchChannelRemoveSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/twitch/channel/TwitchChannelRemoveSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/twitch/channel/TwitchChannelRemoveSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/twitch/channel/TwitchChannelRemoveSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/twitch/channel/TwitchChannelSetSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/twitch/channel/TwitchChannelSetSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/twitch/channel/TwitchChannelSetSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/twitch/channel/TwitchChannelSetSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/twitch/role/TwitchRoleRemoveSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/twitch/role/TwitchRoleRemoveSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/twitch/role/TwitchRoleRemoveSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/twitch/role/TwitchRoleRemoveSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/twitch/role/TwitchRoleSetSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/twitch/role/TwitchRoleSetSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/twitch/role/TwitchRoleSetSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/twitch/role/TwitchRoleSetSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/twitch/user/TwitchAddUserSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/twitch/user/TwitchAddUserSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/twitch/user/TwitchAddUserSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/twitch/user/TwitchAddUserSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/twitch/user/TwitchListUsersSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/twitch/user/TwitchListUsersSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/twitch/user/TwitchListUsersSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/twitch/user/TwitchListUsersSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/commands/twitch/user/TwitchRemoveUserSubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/commands/twitch/user/TwitchRemoveUserSubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/commands/twitch/user/TwitchRemoveUserSubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/commands/twitch/user/TwitchRemoveUserSubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/EnvironmentVariable.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/EnvironmentVariable.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/EnvironmentVariable.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/EnvironmentVariable.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/api/GitHubVersionEndpointWrapper.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/api/GitHubVersionEndpointWrapper.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/api/GitHubVersionEndpointWrapper.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/api/GitHubVersionEndpointWrapper.java
diff --git a/bot/src/main/java/com/beanbeanjuice/cafebot/utility/api/OpenAIAPIWrapper.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/api/OpenAIAPIWrapper.java
new file mode 100644
index 00000000..e72302c1
--- /dev/null
+++ b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/api/OpenAIAPIWrapper.java
@@ -0,0 +1,248 @@
+package com.beanbeanjuice.cafebot.utility.api;
+
+import com.beanbeanjuice.cafeapi.wrapper.requests.Request;
+import com.beanbeanjuice.cafebot.CafeBot;
+import com.beanbeanjuice.cafebot.utility.listeners.ai.AIResponseListener;
+import com.beanbeanjuice.cafebot.utility.listeners.ai.PreviousMessage;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.fasterxml.jackson.databind.util.JSONPObject;
+import lombok.RequiredArgsConstructor;
+import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
+import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
+import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
+import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.HttpResponse;
+import org.apache.hc.core5.http.HttpStatus;
+import org.apache.hc.core5.http.Method;
+import org.apache.hc.core5.net.URIAuthority;
+import org.apache.hc.core5.net.URIBuilder;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Queue;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+@RequiredArgsConstructor
+public class OpenAIAPIWrapper {
+
+ private final String authorizationKey;
+ private final String assistantID;
+ private final Map>> previousMessageMap;
+
+ private final String URL = "https://api.openai.com/v1";
+
+ private final Map aiThreads = new HashMap<>();
+ private Map headers;
+
+ public void setHeaders() {
+ this.headers = new HashMap<>() {{
+ put("Authorization", "Bearer " + authorizationKey);
+ put("OpenAI-Beta", "assistants=v2");
+ put("Content-Type", "application/json");
+ put("User-Agent", "cafeBot/4.0.0");
+ }};
+ }
+
+ private CompletableFuture getThread(final String guildID) throws URISyntaxException {
+ if (aiThreads.containsKey(guildID)) return CompletableFuture.supplyAsync(() -> aiThreads.get(guildID));
+
+ System.out.println("Thread not found, creating.");
+
+ return createThread().thenApplyAsync((threadID) -> {
+ aiThreads.put(guildID, threadID);
+ return threadID;
+ });
+ }
+
+ private CompletableFuture createThread() throws URISyntaxException {
+ URIBuilder uriBuilder = new URIBuilder(String.format("%s/threads", URL));
+ SimpleHttpRequest httpRequest = new SimpleHttpRequest(Method.POST, uriBuilder.build());
+
+ return CompletableFuture.supplyAsync(() -> {
+ SimpleHttpResponse httpResponse = null;
+ try {
+ httpResponse = (SimpleHttpResponse) this.get(httpRequest);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ byte[] bodyBytes = httpResponse.getBodyBytes();
+
+ JsonNode body = null;
+ try {
+ body = new ObjectMapper().readTree(bodyBytes);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ return body.get("id").asText();
+ });
+ }
+
+ private CompletableFuture deleteThread(final String threadID) throws URISyntaxException {
+ URIBuilder uriBuilder = new URIBuilder(String.format("%s/threads/%s", URL, threadID));
+ SimpleHttpRequest httpRequest = new SimpleHttpRequest(Method.DELETE, uriBuilder.build());
+
+ return CompletableFuture.supplyAsync(() -> {
+ SimpleHttpResponse httpResponse = null;
+ try {
+ httpResponse = (SimpleHttpResponse) this.get(httpRequest);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ int status = httpResponse.getCode();
+ return status == HttpStatus.SC_OK;
+ });
+ }
+
+ private CompletableFuture createRun(final String guildID, final String channelID, final String threadID) throws URISyntaxException {
+ URIBuilder uriBuilder = new URIBuilder(String.format("%s/threads/%s/runs", URL, threadID));
+ SimpleHttpRequest httpRequest = new SimpleHttpRequest(Method.POST, uriBuilder.build());
+
+ ObjectMapper mapper = new ObjectMapper();
+ ObjectNode bodyNode = mapper.createObjectNode();
+
+ bodyNode.put("assistant_id", this.assistantID);
+ bodyNode.set("additional_messages", this.convertFewMessagesToJSONArray(guildID, channelID));
+
+ httpRequest.setBody(bodyNode.toString(), ContentType.APPLICATION_JSON);
+
+ return CompletableFuture.supplyAsync(() -> {
+ SimpleHttpResponse httpResponse = null;
+ try {
+ httpResponse = (SimpleHttpResponse) this.get(httpRequest);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ byte[] bodyBytes = httpResponse.getBodyBytes();
+
+ JsonNode body = null;
+ try {
+ body = new ObjectMapper().readTree(bodyBytes);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ return body.get("id").asText();
+ });
+
+ }
+
+ private CompletableFuture getLatestMessageFromRun(final String threadID, final String runID) throws URISyntaxException {
+ URIBuilder uriBuilder = new URIBuilder(String.format("%s/threads/%s/messages", URL, threadID));
+ uriBuilder.setParameter("run_id", runID);
+
+ SimpleHttpRequest httpRequest = new SimpleHttpRequest(Method.GET, uriBuilder.build());
+
+ return CompletableFuture.supplyAsync(() -> {
+ SimpleHttpResponse httpResponse = null;
+ try { httpResponse = (SimpleHttpResponse) this.get(httpRequest); }
+ catch (Exception e) { throw new RuntimeException(e); }
+
+ byte[] bodyBytes = httpResponse.getBodyBytes();
+
+ JsonNode body = null;
+ try { body = new ObjectMapper().readTree(bodyBytes); }
+ catch (IOException e) { throw new RuntimeException(e); }
+
+ return body.get("data").get(0).get("content").get(0).get("text").get("value").asText();
+ });
+ }
+
+ private CompletableFuture getRunStatus(final String threadID, final String runID) throws URISyntaxException {
+ URIBuilder uriBuilder = new URIBuilder(String.format("%s/threads/%s/runs/%s", URL, threadID, runID));
+
+ SimpleHttpRequest httpRequest = new SimpleHttpRequest(Method.GET, uriBuilder.build());
+
+ return CompletableFuture.supplyAsync(() -> {
+ SimpleHttpResponse httpResponse = null;
+ try { httpResponse = (SimpleHttpResponse) this.get(httpRequest); }
+ catch (Exception e) { throw new RuntimeException(e); }
+
+ byte[] bodyBytes = httpResponse.getBodyBytes();
+
+ JsonNode body = null;
+ try { body = new ObjectMapper().readTree(bodyBytes); }
+ catch (IOException e) { throw new RuntimeException(e); }
+
+ return body.get("status").asText();
+ });
+ }
+
+ private ArrayNode convertFewMessagesToJSONArray(final String guildID, final String channelID) {
+ ObjectMapper mapper = new ObjectMapper();
+ ArrayNode additionalMessagesNode = mapper.createArrayNode();
+
+ Queue messageQueue = previousMessageMap.get(guildID).get(channelID);
+
+ while (!messageQueue.isEmpty()) {
+ PreviousMessage message = messageQueue.poll();
+
+ ObjectNode messageNode = mapper.createObjectNode();
+ messageNode.put("role", "user");
+ messageNode.put("content", String.format("%s: %s", message.getUsername(), message.getContent()));
+
+ additionalMessagesNode.add(messageNode);
+ }
+
+ return additionalMessagesNode;
+ }
+
+ private HttpResponse get(final SimpleHttpRequest request) throws ExecutionException, InterruptedException, IOException {
+ headers.forEach(request::addHeader);
+
+ CloseableHttpAsyncClient client = HttpAsyncClients.custom().build();
+ client.start();
+
+ Future future = client.execute(request, null);
+ HttpResponse response = future.get();
+
+ client.close();
+ return response;
+ }
+
+ public CompletableFuture getResponse(final String guildID, final String channelID) throws URISyntaxException {
+ // Get active OpenAI Thread
+ return this.getThread(guildID)
+
+ // Run assistant on thread
+ .thenComposeAsync(
+ (threadID) -> {
+ try { return this.createRun(guildID, channelID, threadID); }
+ catch (URISyntaxException e) { throw new RuntimeException(e); }
+ }
+ )
+
+ // Get assistant's response from thread
+ .thenComposeAsync((runID) -> {
+ // Wait until run is complete. Retry 10 times. Once per second.
+ String threadID = aiThreads.get(guildID);
+
+ String runStatus = "in progress";
+ int count = 0;
+ while (!runStatus.equalsIgnoreCase("completed") && count < 10) {
+ try { runStatus = this.getRunStatus(threadID, runID).get(); count++; Thread.sleep(1000); }
+ catch (Exception e) { throw new RuntimeException(e); }
+ }
+
+ if (!runStatus.equalsIgnoreCase("completed")) {
+ return CompletableFuture.supplyAsync(() -> "Sorry... I'm really busy with customers right now... I'll talk to you in a bit though!");
+ }
+
+ try { return this.getLatestMessageFromRun(threadID, runID); }
+ catch (URISyntaxException e) { throw new RuntimeException(e); }
+ });
+ }
+
+}
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/api/RedditAPIWrapper.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/api/RedditAPIWrapper.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/api/RedditAPIWrapper.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/api/RedditAPIWrapper.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/api/dictionary/DictionaryAPIWrapper.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/api/dictionary/DictionaryAPIWrapper.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/api/dictionary/DictionaryAPIWrapper.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/api/dictionary/DictionaryAPIWrapper.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/api/dictionary/DictionaryMeaning.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/api/dictionary/DictionaryMeaning.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/api/dictionary/DictionaryMeaning.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/api/dictionary/DictionaryMeaning.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/api/dictionary/DictionaryWord.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/api/dictionary/DictionaryWord.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/api/dictionary/DictionaryWord.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/api/dictionary/DictionaryWord.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/commands/Command.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/commands/Command.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/commands/Command.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/commands/Command.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/commands/CommandCategory.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/commands/CommandCategory.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/commands/CommandCategory.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/commands/CommandCategory.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/commands/CommandHandler.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/commands/CommandHandler.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/commands/CommandHandler.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/commands/CommandHandler.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/commands/ICommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/commands/ICommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/commands/ICommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/commands/ICommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/commands/ISubCommand.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/commands/ISubCommand.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/commands/ISubCommand.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/commands/ISubCommand.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/commands/SubCommandGroup.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/commands/SubCommandGroup.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/commands/SubCommandGroup.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/commands/SubCommandGroup.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/exception/WebhookException.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/exception/WebhookException.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/exception/WebhookException.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/exception/WebhookException.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/helper/DailyChannelHelper.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/helper/DailyChannelHelper.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/helper/DailyChannelHelper.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/helper/DailyChannelHelper.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/helper/Helper.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/helper/Helper.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/helper/Helper.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/helper/Helper.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/helper/UpdateCheckHelper.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/helper/UpdateCheckHelper.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/helper/UpdateCheckHelper.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/helper/UpdateCheckHelper.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/listeners/BotAddListener.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/listeners/BotAddListener.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/listeners/BotAddListener.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/listeners/BotAddListener.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/listeners/BotRemoveListener.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/listeners/BotRemoveListener.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/listeners/BotRemoveListener.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/listeners/BotRemoveListener.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/listeners/CountingListener.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/listeners/CountingListener.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/listeners/CountingListener.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/listeners/CountingListener.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/listeners/GoodbyeListener.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/listeners/GoodbyeListener.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/listeners/GoodbyeListener.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/listeners/GoodbyeListener.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/listeners/WelcomeListener.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/listeners/WelcomeListener.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/listeners/WelcomeListener.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/listeners/WelcomeListener.java
diff --git a/bot/src/main/java/com/beanbeanjuice/cafebot/utility/listeners/ai/AIResponseListener.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/listeners/ai/AIResponseListener.java
new file mode 100644
index 00000000..d7d7f6cb
--- /dev/null
+++ b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/listeners/ai/AIResponseListener.java
@@ -0,0 +1,129 @@
+package com.beanbeanjuice.cafebot.utility.listeners.ai;
+
+import com.beanbeanjuice.cafeapi.wrapper.endpoints.guilds.GuildInformationType;
+import com.beanbeanjuice.cafebot.CafeBot;
+import com.beanbeanjuice.cafebot.utility.api.OpenAIAPIWrapper;
+import com.beanbeanjuice.cafebot.utility.helper.Helper;
+import com.beanbeanjuice.cafebot.utility.logging.LogLevel;
+import com.fasterxml.jackson.databind.JsonNode;
+import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
+import net.dv8tion.jda.api.hooks.ListenerAdapter;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.*;
+
+public class AIResponseListener extends ListenerAdapter {
+
+ private final CafeBot cafeBot;
+ private final HashMap, List> messageMap;
+ private final OpenAIAPIWrapper openAI;
+
+ // Map of guild IDs, containing a map of channel IDs with a list of messages
+ private final Map>> previousMessageMap;
+
+ public AIResponseListener(final CafeBot cafeBot, final String openAIAPIKey, final String openAIAssistantID) {
+ this.cafeBot = cafeBot;
+ this.messageMap = new HashMap<>();
+
+ previousMessageMap = new HashMap<>();
+ this.openAI = new OpenAIAPIWrapper(openAIAPIKey, openAIAssistantID, previousMessageMap);
+ this.openAI.setHeaders();
+ refreshMaps();
+ }
+
+ public void refreshMaps() {
+ this.messageMap.clear();
+
+ try {
+ createMaps();
+ } catch (IOException e) {
+ cafeBot.getLogger().log(AIResponseListener.class, LogLevel.ERROR, "Unable to refresh AI maps...", true, true, e);
+ }
+ }
+
+ private void createMaps() throws IOException {
+ for (JsonNode type : Helper.parseJson("ai.json")) {
+ List triggers = new ArrayList<>();
+ List responses = new ArrayList<>();
+
+ for (JsonNode trigger : type.get("triggers")) triggers.add(trigger.asText());
+ for (JsonNode response : type.get("responses")) responses.add(response.asText());
+
+ messageMap.put(triggers, responses);
+ }
+ }
+
+ private void addMessageToGuild(final MessageReceivedEvent event) {
+ previousMessageMap.putIfAbsent(event.getGuild().getId(), new HashMap<>());
+
+ Map> previousMessageMapForGuild = previousMessageMap.get(event.getGuild().getId());
+ previousMessageMapForGuild.putIfAbsent(event.getChannel().getId(), new LinkedList<>());
+
+ String message = event.getMessage().getContentDisplay();
+ if (message.length() >= 500) {
+ message = message.substring(0, 500);
+ message = message + "... (more was shown but just try to ignore the rest)";
+ }
+
+ previousMessageMapForGuild.get(event.getChannel().getId()).offer(new PreviousMessage(message, event.getAuthor().getName()));
+
+ if (previousMessageMapForGuild.get(event.getChannel().getId()).size() > 10)
+ previousMessageMapForGuild.get(event.getChannel().getId()).poll();
+ }
+
+ private void handleOpenAIResponse(final MessageReceivedEvent event) {
+ try {
+ event.getChannel().sendTyping().queue();
+
+ cafeBot.getLogger().log(AIResponseListener.class, LogLevel.INFO, String.format("Running AI For User (%s) on Guild (%s): %s", event.getAuthor().getId(), event.getGuild().getId(), event.getMessage().getContentRaw()), false, false);
+ openAI.getResponse(event.getGuild().getId(), event.getChannel().getId())
+ .thenAcceptAsync((response) -> event.getMessage().reply(response).queue());
+ } catch (URISyntaxException e) {
+ event.getMessage().reply(e.getMessage()).queue();
+ }
+ }
+
+ @Override
+ public void onMessageReceived(final MessageReceivedEvent event) {
+ if (!event.isFromGuild()) return;
+ if (event.getAuthor().isBot()) return;
+
+ String guildID = event.getGuild().getId();
+
+ cafeBot.getCafeAPI().getGuildsEndpoint().getGuildInformation(guildID).thenAcceptAsync((information) -> {
+ boolean useAI = Boolean.parseBoolean(information.getSetting(GuildInformationType.AI_RESPONSE));
+ if (!useAI) return;
+ this.addMessageToGuild(event);
+
+// if (event.getMessage().getReferencedMessage().getAuthor().equals(this.cafeBot.getSelfUser())) {
+// // TODO: Handle reply response.
+// return;
+// }
+
+ if (event.getMessage().getMentions().isMentioned(this.cafeBot.getSelfUser())) {
+ this.handleOpenAIResponse(event);
+ return;
+ }
+
+// String message = event.getMessage().getContentRaw().replaceAll("[^\\sa-zA-Z0-9]", "").toLowerCase();
+//
+// messageMap.forEach((commandTerms, commandResponses) -> {
+// if (commandTerms.stream().noneMatch(message::contains)) return;
+//
+// // TODO: Handle trigger word response.
+// event.getMessage().reply(parseMessage(
+// commandResponses.get(Helper.getRandomInteger(0, commandResponses.size())),
+// event.getAuthor()
+// )).queue();
+// cafeBot.increaseCommandsRun();
+// });
+ });
+ }
+
+ private String parseMessage(final String message, final User user) {
+ return message.replace("{user}", user.getAsMention());
+ }
+
+}
diff --git a/bot/src/main/java/com/beanbeanjuice/cafebot/utility/listeners/ai/PreviousMessage.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/listeners/ai/PreviousMessage.java
new file mode 100644
index 00000000..bccccc62
--- /dev/null
+++ b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/listeners/ai/PreviousMessage.java
@@ -0,0 +1,13 @@
+package com.beanbeanjuice.cafebot.utility.listeners.ai;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public class PreviousMessage {
+
+ private final String content;
+ private final String username;
+
+}
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/logging/LogLevel.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/logging/LogLevel.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/logging/LogLevel.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/logging/LogLevel.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/logging/LogManager.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/logging/LogManager.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/logging/LogManager.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/logging/LogManager.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/sections/cafe/CafeCategory.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/cafe/CafeCategory.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/sections/cafe/CafeCategory.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/cafe/CafeCategory.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/sections/cafe/MenuHandler.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/cafe/MenuHandler.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/sections/cafe/MenuHandler.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/cafe/MenuHandler.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/sections/cafe/MenuItem.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/cafe/MenuItem.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/sections/cafe/MenuItem.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/cafe/MenuItem.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/sections/cafe/MenuListener.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/cafe/MenuListener.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/sections/cafe/MenuListener.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/cafe/MenuListener.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/sections/fun/birthday/BirthdayHelper.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/fun/birthday/BirthdayHelper.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/sections/fun/birthday/BirthdayHelper.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/fun/birthday/BirthdayHelper.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/sections/game/TicTacToeListener.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/game/TicTacToeListener.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/sections/game/TicTacToeListener.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/game/TicTacToeListener.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/sections/generic/HelpHandler.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/generic/HelpHandler.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/sections/generic/HelpHandler.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/generic/HelpHandler.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/sections/generic/HelpListener.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/generic/HelpListener.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/sections/generic/HelpListener.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/generic/HelpListener.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/sections/interactions/CafeInteraction.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/interactions/CafeInteraction.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/sections/interactions/CafeInteraction.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/interactions/CafeInteraction.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/sections/interactions/ICommandInteraction.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/interactions/ICommandInteraction.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/sections/interactions/ICommandInteraction.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/interactions/ICommandInteraction.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/sections/settings/CustomChannels.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/settings/CustomChannels.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/sections/settings/CustomChannels.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/settings/CustomChannels.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/sections/twitch/TwitchGoLiveEventListener.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/twitch/TwitchGoLiveEventListener.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/sections/twitch/TwitchGoLiveEventListener.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/twitch/TwitchGoLiveEventListener.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/sections/twitch/TwitchHandler.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/twitch/TwitchHandler.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/sections/twitch/TwitchHandler.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/sections/twitch/TwitchHandler.java
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/webhook/Webhook.java b/bot/src/main/java/com/beanbeanjuice/cafebot/utility/webhook/Webhook.java
similarity index 100%
rename from src/main/java/com/beanbeanjuice/cafebot/utility/webhook/Webhook.java
rename to bot/src/main/java/com/beanbeanjuice/cafebot/utility/webhook/Webhook.java
diff --git a/src/main/resources/cafebot.properties b/bot/src/main/resources/cafebot.properties
similarity index 100%
rename from src/main/resources/cafebot.properties
rename to bot/src/main/resources/cafebot.properties
diff --git a/src/main/resources/log4j2.xml b/bot/src/main/resources/log4j2.xml
similarity index 100%
rename from src/main/resources/log4j2.xml
rename to bot/src/main/resources/log4j2.xml
diff --git a/src/test/java/com/beanbeanjuice/BotTest.java b/bot/src/test/java/com/beanbeanjuice/BotTest.java
similarity index 100%
rename from src/test/java/com/beanbeanjuice/BotTest.java
rename to bot/src/test/java/com/beanbeanjuice/BotTest.java
diff --git a/src/test/java/com/beanbeanjuice/EnvironmentVariableTest.java b/bot/src/test/java/com/beanbeanjuice/EnvironmentVariableTest.java
similarity index 100%
rename from src/test/java/com/beanbeanjuice/EnvironmentVariableTest.java
rename to bot/src/test/java/com/beanbeanjuice/EnvironmentVariableTest.java
diff --git a/src/test/java/com/beanbeanjuice/utility/logging/LogLevelTest.java b/bot/src/test/java/com/beanbeanjuice/utility/logging/LogLevelTest.java
similarity index 100%
rename from src/test/java/com/beanbeanjuice/utility/logging/LogLevelTest.java
rename to bot/src/test/java/com/beanbeanjuice/utility/logging/LogLevelTest.java
diff --git a/wrappers/cafe-api-wrapper/README.md b/bot/wrappers/cafe-api-wrapper/README.md
similarity index 100%
rename from wrappers/cafe-api-wrapper/README.md
rename to bot/wrappers/cafe-api-wrapper/README.md
diff --git a/wrappers/cafe-api-wrapper/build.gradle.kts b/bot/wrappers/cafe-api-wrapper/build.gradle.kts
similarity index 100%
rename from wrappers/cafe-api-wrapper/build.gradle.kts
rename to bot/wrappers/cafe-api-wrapper/build.gradle.kts
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/CafeAPI.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/CafeAPI.java
similarity index 99%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/CafeAPI.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/CafeAPI.java
index 739bc0f5..0f3c86dd 100644
--- a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/CafeAPI.java
+++ b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/CafeAPI.java
@@ -23,7 +23,6 @@
import com.beanbeanjuice.cafeapi.wrapper.endpoints.words.WordsEndpoint;
import lombok.Getter;
-import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/CafeEndpoint.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/CafeEndpoint.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/CafeEndpoint.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/CafeEndpoint.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/beancoins/users/DonationUsersEndpoint.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/beancoins/users/DonationUsersEndpoint.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/beancoins/users/DonationUsersEndpoint.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/beancoins/users/DonationUsersEndpoint.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/birthdays/Birthday.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/birthdays/Birthday.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/birthdays/Birthday.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/birthdays/Birthday.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/birthdays/BirthdayMonth.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/birthdays/BirthdayMonth.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/birthdays/BirthdayMonth.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/birthdays/BirthdayMonth.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/birthdays/BirthdaysEndpoint.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/birthdays/BirthdaysEndpoint.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/birthdays/BirthdaysEndpoint.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/birthdays/BirthdaysEndpoint.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/cafe/CafeType.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/cafe/CafeType.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/cafe/CafeType.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/cafe/CafeType.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/cafe/CafeUser.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/cafe/CafeUser.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/cafe/CafeUser.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/cafe/CafeUser.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/cafe/CafeUsersEndpoint.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/cafe/CafeUsersEndpoint.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/cafe/CafeUsersEndpoint.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/cafe/CafeUsersEndpoint.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/codes/GeneratedCodesEndpoint.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/codes/GeneratedCodesEndpoint.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/codes/GeneratedCodesEndpoint.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/codes/GeneratedCodesEndpoint.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/counting/CountingEndpoint.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/counting/CountingEndpoint.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/counting/CountingEndpoint.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/counting/CountingEndpoint.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/counting/CountingInformation.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/counting/CountingInformation.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/counting/CountingInformation.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/counting/CountingInformation.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/goodbyes/GoodbyesEndpoint.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/goodbyes/GoodbyesEndpoint.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/goodbyes/GoodbyesEndpoint.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/goodbyes/GoodbyesEndpoint.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/goodbyes/GuildGoodbye.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/goodbyes/GuildGoodbye.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/goodbyes/GuildGoodbye.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/goodbyes/GuildGoodbye.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/guilds/GuildInformation.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/guilds/GuildInformation.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/guilds/GuildInformation.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/guilds/GuildInformation.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/guilds/GuildInformationType.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/guilds/GuildInformationType.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/guilds/GuildInformationType.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/guilds/GuildInformationType.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/guilds/GuildsEndpoint.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/guilds/GuildsEndpoint.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/guilds/GuildsEndpoint.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/guilds/GuildsEndpoint.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/interactions/InteractionType.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/interactions/InteractionType.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/interactions/InteractionType.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/interactions/InteractionType.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/interactions/InteractionsEndpoint.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/interactions/InteractionsEndpoint.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/interactions/InteractionsEndpoint.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/interactions/InteractionsEndpoint.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/interactions/pictures/InteractionPicturesEndpoint.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/interactions/pictures/InteractionPicturesEndpoint.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/interactions/pictures/InteractionPicturesEndpoint.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/interactions/pictures/InteractionPicturesEndpoint.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/interactions/users/Interaction.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/interactions/users/Interaction.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/interactions/users/Interaction.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/interactions/users/Interaction.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/minigames/winstreaks/MinigameType.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/minigames/winstreaks/MinigameType.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/minigames/winstreaks/MinigameType.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/minigames/winstreaks/MinigameType.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/minigames/winstreaks/WinStreak.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/minigames/winstreaks/WinStreak.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/minigames/winstreaks/WinStreak.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/minigames/winstreaks/WinStreak.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/minigames/winstreaks/WinStreaksEndpoint.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/minigames/winstreaks/WinStreaksEndpoint.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/minigames/winstreaks/WinStreaksEndpoint.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/minigames/winstreaks/WinStreaksEndpoint.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/polls/Poll.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/polls/Poll.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/polls/Poll.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/polls/Poll.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/polls/PollsEndpoint.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/polls/PollsEndpoint.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/polls/PollsEndpoint.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/polls/PollsEndpoint.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/raffles/Raffle.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/raffles/Raffle.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/raffles/Raffle.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/raffles/Raffle.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/raffles/RafflesEndpoint.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/raffles/RafflesEndpoint.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/raffles/RafflesEndpoint.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/raffles/RafflesEndpoint.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/twitches/TwitchEndpoint.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/twitches/TwitchEndpoint.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/twitches/TwitchEndpoint.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/twitches/TwitchEndpoint.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/version/VersionsEndpoint.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/version/VersionsEndpoint.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/version/VersionsEndpoint.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/version/VersionsEndpoint.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/voicebinds/VoiceChannelBind.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/voicebinds/VoiceChannelBind.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/voicebinds/VoiceChannelBind.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/voicebinds/VoiceChannelBind.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/voicebinds/VoiceChannelBindsEndpoint.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/voicebinds/VoiceChannelBindsEndpoint.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/voicebinds/VoiceChannelBindsEndpoint.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/voicebinds/VoiceChannelBindsEndpoint.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/welcomes/GuildWelcome.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/welcomes/GuildWelcome.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/welcomes/GuildWelcome.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/welcomes/GuildWelcome.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/welcomes/WelcomesEndpoint.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/welcomes/WelcomesEndpoint.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/welcomes/WelcomesEndpoint.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/welcomes/WelcomesEndpoint.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/words/Word.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/words/Word.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/words/Word.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/words/Word.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/words/WordsEndpoint.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/words/WordsEndpoint.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/words/WordsEndpoint.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/endpoints/words/WordsEndpoint.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/AuthorizationException.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/AuthorizationException.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/AuthorizationException.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/AuthorizationException.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/CafeException.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/CafeException.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/CafeException.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/CafeException.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/ConflictException.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/ConflictException.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/ConflictException.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/ConflictException.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/NotFoundException.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/NotFoundException.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/NotFoundException.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/NotFoundException.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/ResponseException.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/ResponseException.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/ResponseException.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/ResponseException.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/TeaPotException.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/TeaPotException.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/TeaPotException.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/TeaPotException.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/UndefinedVariableException.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/UndefinedVariableException.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/UndefinedVariableException.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/api/UndefinedVariableException.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/program/BirthdayOverfillException.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/program/BirthdayOverfillException.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/program/BirthdayOverfillException.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/program/BirthdayOverfillException.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/program/InvalidTimeZoneException.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/program/InvalidTimeZoneException.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/program/InvalidTimeZoneException.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/exception/program/InvalidTimeZoneException.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/generic/CafeGeneric.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/generic/CafeGeneric.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/generic/CafeGeneric.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/generic/CafeGeneric.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/requests/Request.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/requests/Request.java
similarity index 94%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/requests/Request.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/requests/Request.java
index fbb984bd..4adfc586 100644
--- a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/requests/Request.java
+++ b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/requests/Request.java
@@ -10,7 +10,7 @@
*/
public class Request {
- @Getter final int statusCode;
+ @Getter private final int statusCode;
@Getter private final JsonNode data;
/**
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/requests/RequestBuilder.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/requests/RequestBuilder.java
similarity index 69%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/requests/RequestBuilder.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/requests/RequestBuilder.java
index 05b5693f..fc03beec 100644
--- a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/requests/RequestBuilder.java
+++ b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/requests/RequestBuilder.java
@@ -134,58 +134,6 @@ private HttpResponse get(final SimpleHttpRequest request) throws ExecutionExcept
return response;
}
-// /**
-// * Retrieves the {@link HttpResponse} for a {@link RequestType GET} request.
-// * @return The {@link RequestType GET} {@link HttpResponse}.
-// * @throws URISyntaxException Thrown if there is an issue with the route syntax.
-// * @throws IOException Thrown if there is an issue with the data returned.
-// */
-// private HttpResponse get() throws URISyntaxException, IOException {
-// HttpGet httpGet = new HttpGet(uriBuilder.build());
-// httpGet.addHeader(authorization);
-//
-// return httpClient.execute(httpGet);
-// }
-//
-// /**
-// * Retrieves the {@link HttpResponse} for a {@link RequestType POST} request.
-// * @return The {@link RequestType POST} {@link HttpResponse}.
-// * @throws URISyntaxException Thrown if there is an issue with the route syntax.
-// * @throws IOException Thrown if there is an issue with the data returned.
-// */
-// private HttpResponse post() throws URISyntaxException, IOException {
-// HttpPost httpPost = new HttpPost(uriBuilder.build());
-// httpPost.addHeader(authorization);
-//
-// return httpClient.execute(httpPost);
-// }
-//
-// /**
-// * Retrieves the {@link HttpResponse} for a {@link RequestType PATCH} request.
-// * @return The {@link RequestType PATCH} {@link HttpResponse}.
-// * @throws URISyntaxException Thrown if there is an issue with the route syntax.
-// * @throws IOException Thrown if there is an issue with the data returned.
-// */
-// private HttpResponse patch() throws URISyntaxException, IOException {
-// HttpPatch httpPatch = new HttpPatch(uriBuilder.build());
-// httpPatch.addHeader(authorization);
-//
-// return httpClient.execute(httpPatch);
-// }
-//
-// /**
-// * Retrieves the {@link HttpResponse} for a {@link RequestType DELETE} request.
-// * @return The {@link RequestType DELETE} {@link HttpResponse}.
-// * @throws URISyntaxException Thrown if there is an issue with the route syntax.
-// * @throws IOException Thrown if there is an issue with the data returned.
-// */
-// private HttpResponse delete() throws URISyntaxException, IOException {
-// HttpDelete httpDelete = new HttpDelete(uriBuilder.build());
-// httpDelete.addHeader(authorization);
-//
-// return httpClient.execute(httpDelete);
-// }
-
/**
* @return The {@link String route} for the {@link RequestBuilder}.
*/
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/requests/RequestLocation.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/requests/RequestLocation.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/requests/RequestLocation.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/requests/RequestLocation.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/requests/RequestRoute.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/requests/RequestRoute.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/requests/RequestRoute.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/requests/RequestRoute.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/requests/RequestType.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/requests/RequestType.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/requests/RequestType.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/requests/RequestType.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/user/User.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/user/User.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/user/User.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/user/User.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/user/UserType.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/user/UserType.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/user/UserType.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/user/UserType.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/user/UsersEndpoint.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/user/UsersEndpoint.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/user/UsersEndpoint.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/user/UsersEndpoint.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/utility/Time.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/utility/Time.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/utility/Time.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/utility/Time.java
diff --git a/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/utility/TimestampDifference.java b/bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/utility/TimestampDifference.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/utility/TimestampDifference.java
rename to bot/wrappers/cafe-api-wrapper/src/main/java/com/beanbeanjuice/cafeapi/wrapper/utility/TimestampDifference.java
diff --git a/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/BirthdaysEndpointTests.java b/bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/BirthdaysEndpointTests.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/BirthdaysEndpointTests.java
rename to bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/BirthdaysEndpointTests.java
diff --git a/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/CafeUsersEndpointTests.java b/bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/CafeUsersEndpointTests.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/CafeUsersEndpointTests.java
rename to bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/CafeUsersEndpointTests.java
diff --git a/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/CountingEndpointTests.java b/bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/CountingEndpointTests.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/CountingEndpointTests.java
rename to bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/CountingEndpointTests.java
diff --git a/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/DonationUsersEndpointTests.java b/bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/DonationUsersEndpointTests.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/DonationUsersEndpointTests.java
rename to bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/DonationUsersEndpointTests.java
diff --git a/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/GeneratedCodesEndpointTests.java b/bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/GeneratedCodesEndpointTests.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/GeneratedCodesEndpointTests.java
rename to bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/GeneratedCodesEndpointTests.java
diff --git a/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/GoodbyesEndpointTests.java b/bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/GoodbyesEndpointTests.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/GoodbyesEndpointTests.java
rename to bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/GoodbyesEndpointTests.java
diff --git a/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/GuildsEndpointTests.java b/bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/GuildsEndpointTests.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/GuildsEndpointTests.java
rename to bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/GuildsEndpointTests.java
diff --git a/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/InteractionPictureTest.java b/bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/InteractionPictureTest.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/InteractionPictureTest.java
rename to bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/InteractionPictureTest.java
diff --git a/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/InteractionsEndpointTests.java b/bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/InteractionsEndpointTests.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/InteractionsEndpointTests.java
rename to bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/InteractionsEndpointTests.java
diff --git a/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/PollsEndpointTests.java b/bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/PollsEndpointTests.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/PollsEndpointTests.java
rename to bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/PollsEndpointTests.java
diff --git a/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/RafflesEndpointTests.java b/bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/RafflesEndpointTests.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/RafflesEndpointTests.java
rename to bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/RafflesEndpointTests.java
diff --git a/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/TwitchEndpointTests.java b/bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/TwitchEndpointTests.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/TwitchEndpointTests.java
rename to bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/TwitchEndpointTests.java
diff --git a/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/UsersEndpointTests.java b/bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/UsersEndpointTests.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/UsersEndpointTests.java
rename to bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/UsersEndpointTests.java
diff --git a/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/VersionsEndpointTests.java b/bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/VersionsEndpointTests.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/VersionsEndpointTests.java
rename to bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/VersionsEndpointTests.java
diff --git a/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/VoiceChannelBindsEndpointTests.java b/bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/VoiceChannelBindsEndpointTests.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/VoiceChannelBindsEndpointTests.java
rename to bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/VoiceChannelBindsEndpointTests.java
diff --git a/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/WelcomesEndpointTests.java b/bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/WelcomesEndpointTests.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/WelcomesEndpointTests.java
rename to bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/WelcomesEndpointTests.java
diff --git a/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/WinStreaksEndpointTests.java b/bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/WinStreaksEndpointTests.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/WinStreaksEndpointTests.java
rename to bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/WinStreaksEndpointTests.java
diff --git a/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/WordsEndpointTests.java b/bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/WordsEndpointTests.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/WordsEndpointTests.java
rename to bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/beta/WordsEndpointTests.java
diff --git a/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/utility/TimeTest.java b/bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/utility/TimeTest.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/utility/TimeTest.java
rename to bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/cafeapi/utility/TimeTest.java
diff --git a/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/classes/BirthdayTest.java b/bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/classes/BirthdayTest.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/classes/BirthdayTest.java
rename to bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/classes/BirthdayTest.java
diff --git a/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/classes/LoggingTest.java b/bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/classes/LoggingTest.java
similarity index 100%
rename from wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/classes/LoggingTest.java
rename to bot/wrappers/cafe-api-wrapper/src/test/java/com/beanbeanjuice/classes/LoggingTest.java
diff --git a/wrappers/kawaii-api-wrapper/README.md b/bot/wrappers/kawaii-api-wrapper/README.md
similarity index 100%
rename from wrappers/kawaii-api-wrapper/README.md
rename to bot/wrappers/kawaii-api-wrapper/README.md
diff --git a/wrappers/kawaii-api-wrapper/build.gradle.kts b/bot/wrappers/kawaii-api-wrapper/build.gradle.kts
similarity index 100%
rename from wrappers/kawaii-api-wrapper/build.gradle.kts
rename to bot/wrappers/kawaii-api-wrapper/build.gradle.kts
diff --git a/wrappers/kawaii-api-wrapper/src/main/java/com/beanbeanjuice/kawaiiapi/wrapper/KawaiiAPI.java b/bot/wrappers/kawaii-api-wrapper/src/main/java/com/beanbeanjuice/kawaiiapi/wrapper/KawaiiAPI.java
similarity index 100%
rename from wrappers/kawaii-api-wrapper/src/main/java/com/beanbeanjuice/kawaiiapi/wrapper/KawaiiAPI.java
rename to bot/wrappers/kawaii-api-wrapper/src/main/java/com/beanbeanjuice/kawaiiapi/wrapper/KawaiiAPI.java
diff --git a/wrappers/kawaii-api-wrapper/src/main/java/com/beanbeanjuice/kawaiiapi/wrapper/endpoint/GifEndpoint.java b/bot/wrappers/kawaii-api-wrapper/src/main/java/com/beanbeanjuice/kawaiiapi/wrapper/endpoint/GifEndpoint.java
similarity index 100%
rename from wrappers/kawaii-api-wrapper/src/main/java/com/beanbeanjuice/kawaiiapi/wrapper/endpoint/GifEndpoint.java
rename to bot/wrappers/kawaii-api-wrapper/src/main/java/com/beanbeanjuice/kawaiiapi/wrapper/endpoint/GifEndpoint.java
diff --git a/wrappers/kawaii-api-wrapper/src/main/java/com/beanbeanjuice/kawaiiapi/wrapper/endpoint/KawaiiEndpoint.java b/bot/wrappers/kawaii-api-wrapper/src/main/java/com/beanbeanjuice/kawaiiapi/wrapper/endpoint/KawaiiEndpoint.java
similarity index 100%
rename from wrappers/kawaii-api-wrapper/src/main/java/com/beanbeanjuice/kawaiiapi/wrapper/endpoint/KawaiiEndpoint.java
rename to bot/wrappers/kawaii-api-wrapper/src/main/java/com/beanbeanjuice/kawaiiapi/wrapper/endpoint/KawaiiEndpoint.java
diff --git a/wrappers/kawaii-api-wrapper/src/main/java/com/beanbeanjuice/kawaiiapi/wrapper/requests/Request.java b/bot/wrappers/kawaii-api-wrapper/src/main/java/com/beanbeanjuice/kawaiiapi/wrapper/requests/Request.java
similarity index 100%
rename from wrappers/kawaii-api-wrapper/src/main/java/com/beanbeanjuice/kawaiiapi/wrapper/requests/Request.java
rename to bot/wrappers/kawaii-api-wrapper/src/main/java/com/beanbeanjuice/kawaiiapi/wrapper/requests/Request.java
diff --git a/wrappers/kawaii-api-wrapper/src/main/java/com/beanbeanjuice/kawaiiapi/wrapper/requests/RequestBuilder.java b/bot/wrappers/kawaii-api-wrapper/src/main/java/com/beanbeanjuice/kawaiiapi/wrapper/requests/RequestBuilder.java
similarity index 100%
rename from wrappers/kawaii-api-wrapper/src/main/java/com/beanbeanjuice/kawaiiapi/wrapper/requests/RequestBuilder.java
rename to bot/wrappers/kawaii-api-wrapper/src/main/java/com/beanbeanjuice/kawaiiapi/wrapper/requests/RequestBuilder.java
diff --git a/wrappers/kawaii-api-wrapper/src/main/java/com/beanbeanjuice/kawaiiapi/wrapper/requests/RequestRoute.java b/bot/wrappers/kawaii-api-wrapper/src/main/java/com/beanbeanjuice/kawaiiapi/wrapper/requests/RequestRoute.java
similarity index 100%
rename from wrappers/kawaii-api-wrapper/src/main/java/com/beanbeanjuice/kawaiiapi/wrapper/requests/RequestRoute.java
rename to bot/wrappers/kawaii-api-wrapper/src/main/java/com/beanbeanjuice/kawaiiapi/wrapper/requests/RequestRoute.java
diff --git a/wrappers/kawaii-api-wrapper/src/test/java/com/beanbeanjuice/GIFEndpointTest.java b/bot/wrappers/kawaii-api-wrapper/src/test/java/com/beanbeanjuice/GIFEndpointTest.java
similarity index 100%
rename from wrappers/kawaii-api-wrapper/src/test/java/com/beanbeanjuice/GIFEndpointTest.java
rename to bot/wrappers/kawaii-api-wrapper/src/test/java/com/beanbeanjuice/GIFEndpointTest.java
diff --git a/wrappers/kawaii-api-wrapper/src/test/java/com/beanbeanjuice/KawaiiAPITest.java b/bot/wrappers/kawaii-api-wrapper/src/test/java/com/beanbeanjuice/KawaiiAPITest.java
similarity index 100%
rename from wrappers/kawaii-api-wrapper/src/test/java/com/beanbeanjuice/KawaiiAPITest.java
rename to bot/wrappers/kawaii-api-wrapper/src/test/java/com/beanbeanjuice/KawaiiAPITest.java
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index e6441136..00000000
Binary files a/gradle/wrapper/gradle-wrapper.jar and /dev/null differ
diff --git a/src/main/java/com/beanbeanjuice/cafebot/utility/listeners/ai/AIResponseListener.java b/src/main/java/com/beanbeanjuice/cafebot/utility/listeners/ai/AIResponseListener.java
deleted file mode 100644
index df495c48..00000000
--- a/src/main/java/com/beanbeanjuice/cafebot/utility/listeners/ai/AIResponseListener.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package com.beanbeanjuice.cafebot.utility.listeners.ai;
-
-import com.beanbeanjuice.cafeapi.wrapper.endpoints.guilds.GuildInformationType;
-import com.beanbeanjuice.cafebot.CafeBot;
-import com.beanbeanjuice.cafebot.utility.helper.Helper;
-import com.beanbeanjuice.cafebot.utility.logging.LogLevel;
-import com.fasterxml.jackson.databind.JsonNode;
-import net.dv8tion.jda.api.entities.User;
-import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
-import net.dv8tion.jda.api.hooks.ListenerAdapter;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
-public class AIResponseListener extends ListenerAdapter {
-
- private final CafeBot cafeBot;
- private final HashMap, List> messageMap;
-
- public AIResponseListener(final CafeBot cafeBot) {
- this.cafeBot = cafeBot;
- this.messageMap = new HashMap<>();
- refreshMaps();
- }
-
- public void refreshMaps() {
- this.messageMap.clear();
-
- try {
- createMaps();
- } catch (IOException e) {
- cafeBot.getLogger().log(AIResponseListener.class, LogLevel.ERROR, "Unable to refresh AI maps...", true, true, e);
- }
- }
-
- private void createMaps() throws IOException {
- for (JsonNode type : Helper.parseJson("ai.json")) {
- List triggers = new ArrayList<>();
- List responses = new ArrayList<>();
-
- for (JsonNode trigger : type.get("triggers")) triggers.add(trigger.asText());
- for (JsonNode response : type.get("responses")) responses.add(response.asText());
-
- messageMap.put(triggers, responses);
- }
- }
-
- @Override
- public void onMessageReceived(final MessageReceivedEvent event) {
- if (!event.isFromGuild()) return;
- if (event.getAuthor().isBot()) return;
-
- String guildID = event.getGuild().getId();
-
- cafeBot.getCafeAPI().getGuildsEndpoint().getGuildInformation(guildID).thenAcceptAsync((information) -> {
- boolean useAI = Boolean.parseBoolean(information.getSetting(GuildInformationType.AI_RESPONSE));
- if (!useAI) return;
-
- String message = event.getMessage().getContentRaw().replaceAll("[^\\sa-zA-Z0-9]", "");
-
- messageMap.forEach((commandTerms, commandResponses) -> {
- if (!commandTerms.contains(message)) return;
-
- event.getMessage().reply(parseMessage(
- commandResponses.get(Helper.getRandomInteger(0, commandResponses.size())),
- event.getAuthor()
- )).queue();
- cafeBot.increaseCommandsRun();
- });
- });
- }
-
- private String parseMessage(final String message, final User user) {
- return message.replace("{user}", user.getAsMention());
- }
-
-}