Development (#11)

We need this NOW.

---------

Co-authored-by: PineaFan <ash@pinea.dev>
Co-authored-by: pineafan <pineapplefanyt@gmail.com>
Co-authored-by: PineappleFan <PineaFan@users.noreply.github.com>
Co-authored-by: Skyler <skyler3665@gmail.com>
diff --git a/src/config/default.json b/src/config/default.json
deleted file mode 100644
index 8e4197c..0000000
--- a/src/config/default.json
+++ /dev/null
@@ -1,100 +0,0 @@
-{
-    "id": "default",
-    "version": 1,
-    "singleEventNotifications": {
-        "statsChannelDeleted": false
-    },
-    "filters": {
-        "images": {
-            "NSFW": false,
-            "size": false
-        },
-        "malware": false,
-        "wordFilter": {
-            "enabled": false,
-            "words": {
-                "strict": [],
-                "loose": []
-            }
-        },
-        "invite": {
-            "enabled": false,
-            "allowed": {
-                "users": [],
-                "roles": [],
-                "channels": []
-            }
-        },
-        "pings": {
-            "mass": 5,
-            "everyone": true,
-            "roles": true
-        }
-    },
-    "welcome": {
-        "enabled": false,
-        "role": null,
-        "ping": null,
-        "channel": null,
-        "message": null
-    },
-    "stats": {},
-    "logging": {
-        "logs": {
-            "enabled": true,
-            "channel": null,
-            "toLog": "3fffff"
-        },
-        "staff": {
-            "channel": null
-        },
-        "attachments": {
-            "channel": null,
-            "saved": {}
-        }
-    },
-    "verify": {
-        "enabled": false,
-        "role": null
-    },
-    "tickets": {
-        "enabled": false,
-        "category": null,
-        "types": "3f",
-        "customTypes": null,
-        "useCustom": false,
-        "supportRole": null,
-        "maxTickets": 5
-    },
-    "moderation": {
-        "mute": {
-            "timeout": true,
-            "role": null,
-            "text": null,
-            "link": null
-        },
-        "kick": {
-            "text": null,
-            "link": null
-        },
-        "ban": {
-            "text": null,
-            "link": null
-        },
-        "softban": {
-            "text": null,
-            "link": null
-        },
-        "warn": {
-            "text": null,
-            "link": null
-        },
-        "nickname": {
-            "text": null,
-            "link": null
-        }
-    },
-    "tracks": [],
-    "roleMenu": [],
-    "tags": {}
-}
diff --git a/src/config/emojis.json b/src/config/emojis.json
index 26d4c98..ecf1858 100644
--- a/src/config/emojis.json
+++ b/src/config/emojis.json
@@ -1,6 +1,8 @@
 {
     "NUCLEUS": {
         "LOGO": "953040840945721385",
+        "PREMIUMACTIVATE": "a1067536222764925068",
+        "PREMIUM": "1067928702027042876",
         "LOADING": "a946346549271732234",
         "INFO": {
             "HELP": "751751467014029322",
@@ -22,9 +24,11 @@
         "FILTER": "990242059451514902",
         "ATTACHMENT": "997570687193587812",
         "LOGGING": "999613304446144562",
+        "SAVE": "1065722246322200586",
+        "REORDER": "1069323453909454890",
         "NOTIFY": {
             "ON": "1000726394579464232",
-            "OFF": "1000726363495477368"
+            "OFF": "1078058136092541008"
         },
         "OPP": {
             "ADD": "837355918831124500",
@@ -94,9 +98,8 @@
         "TITLEUPDATE": "729763053620691044",
         "TOPICUPDATE": "729763053477953536",
         "SLOWMODE": {
-            "ON": "777138171301068831",
-            "OFF": "777138171447869480",
-            "// TODO": "Make these green and red respectively"
+            "ON": "973616021304913950",
+            "OFF": "777138171447869480"
         },
         "NSFW": {
             "ON": "729064531208175736",
@@ -210,6 +213,12 @@
             "STOP": "853519660116738078"
         }
     },
+    "SETTINGS": {
+        "STATS": {
+            "GREEN": "752214059159650396",
+            "RED": "1065677252630675556"
+        }
+    },
     "GUILD": {
         "RED": "959779988264079361",
         "YELLOW": "729763053352124529",
@@ -219,8 +228,10 @@
             "EDIT": "729066518549233795",
             "DELETE": "953035210121953320"
         },
-        "GRAPHS": "752214059159650396",
-        "SETTINGS": "752570111063228507",
+        "SETTINGS": {
+            "GREEN": "752570111063228507",
+            "RED": "1068607393728049253"
+        },
         "ICONCHANGE": "729763053612302356",
         "TICKET": {
             "OPEN": "853245836331188264",
@@ -338,7 +349,7 @@
             "TOP": {
                 "ACTIVE": "963122664648630293",
                 "INACTIVE": "963122659862917140",
-                "GREY": {
+                "GRAY": {
                     "ACTIVE": "963123505052934144",
                     "INACTIVE": "963123495221469194"
                 }
@@ -346,7 +357,7 @@
             "MIDDLE": {
                 "ACTIVE": "963122679332880384",
                 "INACTIVE": "963122673246937199",
-                "GREY": {
+                "GRAY": {
                     "ACTIVE": "963123517702955018",
                     "INACTIVE": "963123511927390329"
                 }
@@ -354,7 +365,7 @@
             "BOTTOM": {
                 "ACTIVE": "963122691752218624",
                 "INACTIVE": "963122685691453552",
-                "GREY": {
+                "GRAY": {
                     "ACTIVE": "963123529988059187",
                     "INACTIVE": "963123523742748742"
                 }
@@ -363,10 +374,20 @@
         "SINGLE": {
             "ACTIVE": "963361162215424060",
             "INACTIVE": "963361431758176316",
-            "GREY": {
+            "GRAY": {
                 "ACTIVE": "963361204695334943",
                 "INACTIVE": "963361200828198952"
             }
         }
+    },
+    "COLORS": {
+        "RED": "875822912802803754",
+        "ORANGE": "875822913104785418",
+        "YELLOW": "875822913079611402",
+        "GREEN": "875822913213841418",
+        "BLUE": "875822912777637889",
+        "PURPLE": "875822913213841419",
+        "PINK": "875822913088020541",
+        "GRAY": "875822913117368340"
     }
 }
diff --git a/src/config/format.ts b/src/config/format.ts
index 713a233..e32bef6 100644
--- a/src/config/format.ts
+++ b/src/config/format.ts
@@ -1,8 +1,8 @@
+
 import fs from "fs";
-// @ts-expect-error
 import * as readLine from "node:readline/promises";
 
-const defaultDict: Record<string, string | string[] | boolean> = {
+const defaultDict: Record<string, string | string[] | boolean | Record<string, string>> = {
     developmentToken: "Your development bot token (Used for testing in one server, rather than production)",
     developmentGuildID: "Your development guild ID",
     enableDevelopment: true,
@@ -15,7 +15,17 @@
     userContextFolder: "Your built user context folder (usually dist/context/users)",
     verifySecret:
         "If using verify, enter a code here which matches the secret sent back by your website. You can use a random code if you do not have one already. (Optional)",
-    mongoUrl: "Your Mongo connection string, e.g. mongodb://127.0.0.1:27017",
+    mongoUsername: "Your Mongo username (optional)",
+    mongoPassword: "Your Mongo password (optional)",
+    mongoDatabase: "Your Mongo database name (optional, e.g. Nucleus)",
+    mongoHost: "Your Mongo host (optional, e.g. localhost:27017)",
+    mongoOptions: {
+        username: "",
+        password: "",
+        database: "",
+        host: "",
+        authSource: "",
+    },
     baseUrl: "Your website where buttons such as Verify and Role menu will link to, e.g. https://example.com/",
     pastebinApiKey: "An API key for pastebin (optional)",
     pastebinUsername: "Your pastebin username (optional)",
@@ -51,18 +61,27 @@
         // }
     }
 
-    let json;
+    let json: typeof defaultDict;
     let out = true;
     try {
-        json = JSON.parse(fs.readFileSync("./src/config/main.json", "utf8"));
+        json = await import("./main.js") as unknown as typeof defaultDict;
     } catch (e) {
-        console.log("\x1b[31m⚠ No main.json found, creating one.");
-        console.log("  \x1b[2mYou can edit src/config/main.json directly using template written to the file.\x1b[0m\n");
+        console.log("\x1b[31m⚠ No main.ts found, creating one.");
+        console.log("  \x1b[2mYou can edit src/config/main.ts directly using template written to the file.\x1b[0m\n");
         out = false;
-        json = {};
+        json = {} as typeof defaultDict;
     }
+
+    if (Object.keys(json).length) {
+        if (json["token"] === defaultDict["token"] || json["developmentToken"] === defaultDict["developmentToken"]) {
+            console.log("\x1b[31m⚠ No main.ts found, creating one.");
+            console.log("  \x1b[2mYou can edit src/config/main.ts directly using template written to the file.\x1b[0m\n");
+            json = {};
+        }
+    }
+
     for (const key in defaultDict) {
-        if (!json[key]) {
+        if (Object.keys(json).includes(key)) {
             if (walkthrough) {
                 switch (key) {
                     case "enableDevelopment": {
@@ -88,18 +107,20 @@
                         json[key] = toWrite;
                         break;
                     }
+                    case "mongoOptions": {
+                        break;
+                    }
                     default: {
                         json[key] = await getInput(`\x1b[36m${key} \x1b[0m(\x1b[35m${defaultDict[key]}\x1b[0m) > `);
                     }
                 }
             } else {
-                json[key] = defaultDict[key];
+                json[key] = defaultDict[key]!;
             }
         }
     }
-    if (walkthrough && !json.mongoUrl) json.mongoUrl = "mongodb://127.0.0.1:27017";
-    if (!json.mongoUrl.endsWith("/")) json.mongoUrl += "/";
-    if (!json.baseUrl.endsWith("/")) json.baseUrl += "/";
+    if (walkthrough && !(json["mongoUrl"] ?? false)) json["mongoUrl"] = "mongodb://127.0.0.1:27017";
+    if (!((json["baseUrl"] as string | undefined) ?? "").endsWith("/")) (json["baseUrl"] as string) += "/";
     let hosts;
     try {
         hosts = fs.readFileSync("/etc/hosts", "utf8").toString().split("\n");
@@ -108,16 +129,23 @@
             "\x1b[31m⚠ No /etc/hosts found. Please ensure the file exists and is readable. (Windows is not supported, Mac and Linux users should not experience this error)"
         );
     }
-    let localhost = hosts.find((line) => line.split(" ")[1] === "localhost");
+    let localhost: string | undefined = hosts.find((line) => line.split(" ")[1] === "localhost");
     if (localhost) {
         localhost = localhost.split(" ")[0];
     } else {
         localhost = "127.0.0.1";
     }
-    json.mongoUrl = json.mongoUrl.replace("localhost", localhost);
-    json.baseUrl = json.baseUrl.replace("localhost", localhost);
+    json["mongoUrl"] = (json["mongoUrl"]! as string).replace("localhost", localhost!);
+    json["baseUrl"] = (json["baseUrl"]! as string).replace("localhost", localhost!);
+    json["mongoOptions"] = {
+        username: json["username"] as string,
+        password: json["password"] as string,
+        database: json["database"] as string,
+        host: json["host"] as string,
+        authSource: json["authSource"] as string,
+    };
 
-    fs.writeFileSync("./src/config/main.json", JSON.stringify(json, null, 4));
+    fs.writeFileSync("./src/config/main.ts", "export default " + JSON.stringify(json, null, 4) + ";");
 
     if (walkthrough) {
         console.log("\x1b[32m✓ All properties added.\x1b[0m");
diff --git a/src/config/main.d.ts b/src/config/main.d.ts
new file mode 100644
index 0000000..6549234
--- /dev/null
+++ b/src/config/main.d.ts
@@ -0,0 +1,26 @@
+declare const config: {
+    developmentToken: string,
+    developmentGuildID: string,
+    enableDevelopment: boolean,
+    token: string,
+    managementGuildID: string,
+    owners: string[],
+    commandsFolder: string,
+    eventsFolder: string,
+    messageContextFolder: string,
+    userContextFolder: string,
+    verifySecret: string,
+    mongoOptions: {
+        username: string,
+        password: string,
+        database: string,
+        host: string,
+    },
+    baseUrl: string,
+    pastebinApiKey: string,
+    pastebinUsername: string,
+    pastebinPassword: string,
+    rapidApiKey: string
+};
+
+export default config;
\ No newline at end of file
diff --git a/src/config/main.json b/src/config/main.json
deleted file mode 100644
index 64abe93..0000000
--- a/src/config/main.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
-    developmentToken: "Your development bot token (Used for testing in one server, rather than production)",
-    developmentGuildID: "Your development guild ID",
-    enableDevelopment: true,
-    token: "Your bot token",
-    managementGuildID: "Your management guild ID (Used for running management commands on the bot)",
-    owners: [],
-    commandsFolder: "Your built commands folder (usually dist/commands)",
-    eventsFolder: "Your built events folder (usually dist/events)",
-    messageContextFolder: "Your built message context folder (usually dist/context/messages)",
-    userContextFolder: "Your built user context folder (usually dist/context/users)",
-    verifySecret:
-        "If using verify, enter a code here which matches the secret sent back by your website. You can use a random code if you do not have one already. (Optional)",
-    mongoUrl: "Your Mongo connection string, e.g. mongodb://127.0.0.1:27017",
-    baseUrl: "Your website where buttons such as Verify and Role menu will link to, e.g. https://example.com/",
-    pastebinApiKey: "An API key for pastebin (optional)",
-    pastebinUsername: "Your pastebin username (optional)",
-    pastebinPassword: "Your pastebin password (optional)",
-    rapidApiKey: "Your RapidAPI key (optional), used for Unscan"
-}