minor-fixes-and-type-safety-improvements (#22)

diff --git a/.envrc b/.envrc
new file mode 100644
index 0000000..e31c306
--- /dev/null
+++ b/.envrc
@@ -0,0 +1,4 @@
+if ! has nix_direnv_version || ! nix_direnv_version 2.2.1; then
+    source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.2.1/direnvrc" "sha256-zelF0vLbEl5uaqrfIzbgNzJWGmLzCmYAkInj/LNxvKs="
+fi
+use flake
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 15a8d7a..d0c3d2b 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -15,8 +15,12 @@
 jobs:
     lint:
         runs-on: ubuntu-latest
+
         steps:
             - uses: actions/checkout@v3
+            - uses: actions/setup-node@v3.6.0
+              with:
+                  node-version: 19.x
             - run: yarn install --immutable
             - name: Compile
               run: yarn build
diff --git a/.gitignore b/.gitignore
index b8b8506..6deb598 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,7 +5,7 @@
 
 !src/config/*.d.ts
 !src/config/format.ts
-!src/config/default.json
+!src/config/default.ts
 !src/config/emojis.json
 src/config/main.ts
 .vscode/
@@ -19,3 +19,5 @@
 
 ClicksMigratingProblems/oldData/
 ClicksMigratingProblems/oldData copy/
+
+.direnv/
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..f30c0f6
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,43 @@
+{
+  "nodes": {
+    "flake-utils": {
+      "locked": {
+        "lastModified": 1676283394,
+        "narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "3db36a8b464d0c4532ba1c7dda728f4576d6d073",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    },
+    "nixpkgs": {
+      "locked": {
+        "lastModified": 1677852945,
+        "narHash": "sha256-liiVJjkBTuBTAkRW3hrI8MbPD2ImYzwUpa7kvteiKhM=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "f5ffd5787786dde3a8bf648c7a1b5f78c4e01abb",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixpkgs-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "root": {
+      "inputs": {
+        "flake-utils": "flake-utils",
+        "nixpkgs": "nixpkgs"
+      }
+    }
+  },
+  "root": "root",
+  "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..c11ea5f
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,14 @@
+{
+  description = "A basic flake with a shell";
+  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
+  inputs.flake-utils.url = "github:numtide/flake-utils";
+
+  outputs = { self, nixpkgs, flake-utils }:
+    flake-utils.lib.eachDefaultSystem (system: let
+      pkgs = nixpkgs.legacyPackages.${system};
+    in {
+      devShells.default = pkgs.mkShell {
+        packages = [ pkgs.yarn pkgs.nodejs-19_x pkgs.typescript pkgs.act ];
+      };
+    });
+}
diff --git a/package.json b/package.json
index f28878f..a319086 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,9 @@
     "dependencies": {
         "@discordjs/rest": "^0.2.0-canary.0",
         "@hokify/agenda": "^6.2.12",
+        "@total-typescript/ts-reset": "^0.3.7",
         "@tsconfig/node18-strictest-esm": "^1.0.0",
+        "@types/node": "^18.14.6",
         "@ungap/structured-clone": "^1.0.1",
         "agenda": "^4.3.0",
         "body-parser": "^1.20.0",
@@ -18,7 +20,7 @@
         "node-tesseract-ocr": "^2.2.1",
         "structured-clone": "^0.2.2",
         "systeminformation": "^5.17.3"
-        },
+    },
     "resolutions": {
         "discord-api-types": "0.37.23"
     },
diff --git a/src/commands/settings/automod.ts b/src/commands/settings/automod.ts
index 09b8914..ff9e0b2 100644
--- a/src/commands/settings/automod.ts
+++ b/src/commands/settings/automod.ts
@@ -874,6 +874,7 @@
         await i.deferUpdate();
         if(i.isButton()) {
             await client.database.guilds.write(interaction.guild.id, {filters: config});
+            await client.memory.forceUpdate(interaction.guild.id);
         } else {
             switch(i.values[0]) {
                 case "invites": {
diff --git a/src/commands/settings/autopublish.ts b/src/commands/settings/autopublish.ts
index 2c01fe2..27d01bd 100644
--- a/src/commands/settings/autopublish.ts
+++ b/src/commands/settings/autopublish.ts
@@ -79,6 +79,7 @@
                     await client.database.guilds.write(interaction.guild!.id, { "autoPublish": data });
                     config = await client.database.guilds.read(interaction.guild!.id);
                     data = _.cloneDeep(config.autoPublish);
+                    await client.memory.forceUpdate(interaction.guild!.id);
                     break;
                 }
             }
diff --git a/src/commands/settings/logs/attachment.ts b/src/commands/settings/logs/attachment.ts
index 238b8b9..8f0b257 100644
--- a/src/commands/settings/logs/attachment.ts
+++ b/src/commands/settings/logs/attachment.ts
@@ -93,6 +93,7 @@
                         "logging.attachments.channel": channel
                     });
                     data = await client.database.guilds.read(interaction.guild!.id);
+                    await client.memory.forceUpdate(interaction.guild!.id);
                     break;
                 }
             }
diff --git a/src/commands/settings/logs/events.ts b/src/commands/settings/logs/events.ts
index eeef8fb..05d6928 100644
--- a/src/commands/settings/logs/events.ts
+++ b/src/commands/settings/logs/events.ts
@@ -139,6 +139,7 @@
                     await client.database.guilds.write(interaction.guild!.id, {"logging.logs": data});
                     config = await client.database.guilds.read(interaction.guild!.id);
                     data = Object.assign({}, config.logging.logs);
+                    await client.memory.forceUpdate(interaction.guild!.id)
                     break;
                 }
                 case "remove": {
diff --git a/src/commands/settings/logs/warnings.ts b/src/commands/settings/logs/warnings.ts
index 84772e6..4d9a3fa 100644
--- a/src/commands/settings/logs/warnings.ts
+++ b/src/commands/settings/logs/warnings.ts
@@ -81,6 +81,7 @@
                         "logging.warnings.channel": channel
                     });
                     data = await client.database.guilds.read(interaction.guild!.id);
+                    await client.memory.forceUpdate(interaction.guild!.id);
                     break;
                 }
             }
diff --git a/src/commands/settings/rolemenu.ts b/src/commands/settings/rolemenu.ts
index cccb6f6..ae174b3 100644
--- a/src/commands/settings/rolemenu.ts
+++ b/src/commands/settings/rolemenu.ts
@@ -436,8 +436,9 @@
                     break;
                 }
                 case "save": {
-                    client.database.guilds.write(interaction.guild.id, {"roleMenu.options": currentObject});
+                    await client.database.guilds.write(interaction.guild.id, {"roleMenu.options": currentObject});
                     modified = false;
+                    await client.memory.forceUpdate(interaction.guild.id);
                     break;
                 }
             }
diff --git a/src/commands/settings/stats.ts b/src/commands/settings/stats.ts
index d46b57e..ecab612 100644
--- a/src/commands/settings/stats.ts
+++ b/src/commands/settings/stats.ts
@@ -378,9 +378,10 @@
                     break;
                 }
                 case "save": {
-                    client.database.guilds.write(interaction.guild.id, {stats: currentObject});
+                    await client.database.guilds.write(interaction.guild.id, {stats: currentObject});
                     singleNotify("statsChannelDeleted", interaction.guild.id, true);
                     modified = false;
+                    await client.memory.forceUpdate(interaction.guild.id);
                     break;
                 }
             }
@@ -400,4 +401,4 @@
 
 export { command };
 export { callback };
-export { check };
\ No newline at end of file
+export { check };
diff --git a/src/commands/settings/tickets.ts b/src/commands/settings/tickets.ts
index 2e046bf..838defb 100644
--- a/src/commands/settings/tickets.ts
+++ b/src/commands/settings/tickets.ts
@@ -135,6 +135,7 @@
                     await i.deferUpdate();
                     await client.database.guilds.write(interaction.guild.id, { tickets: ticketData });
                     changesMade = false;
+                    await client.memory.forceUpdate(interaction.guild.id);
                     break;
                 }
                 case "enabled": {
diff --git a/src/commands/settings/tracks.ts b/src/commands/settings/tracks.ts
index d9d485d..39efede 100644
--- a/src/commands/settings/tracks.ts
+++ b/src/commands/settings/tracks.ts
@@ -413,6 +413,7 @@
                 case "save": {
                     client.database.guilds.write(interaction.guild!.id, {tracks: tracks});
                     modified = false;
+                    await client.memory.forceUpdate(interaction.guild!.id);
                     break;
                 }
             }
diff --git a/src/commands/settings/verify.ts b/src/commands/settings/verify.ts
index c440b75..9c091a1 100644
--- a/src/commands/settings/verify.ts
+++ b/src/commands/settings/verify.ts
@@ -88,6 +88,7 @@
                     client.database.guilds.write(interaction.guild.id, {"verify": data} )
                     config = await client.database.guilds.read(interaction.guild.id);
                     data = Object.assign({}, config.verify);
+                    await client.memory.forceUpdate(interaction.guild.id);
                     break
                 }
                 case "switch": {
diff --git a/src/commands/settings/welcome.ts b/src/commands/settings/welcome.ts
index 7584624..b2d484c 100644
--- a/src/commands/settings/welcome.ts
+++ b/src/commands/settings/welcome.ts
@@ -223,6 +223,7 @@
                     await client.database.guilds.write(interaction.guild!.id, {"welcome": data});
                     config = await client.database.guilds.read(interaction.guild!.id);
                     data = Object.assign({}, config.welcome);
+                    await client.memory.forceUpdate(interaction.guild!.id)
                     break;
                 }
                 case "channelDM": {
@@ -297,4 +298,4 @@
     return autocompletions;
 };
 
-export { command, callback, check, autocomplete };
\ No newline at end of file
+export { command, callback, check, autocomplete };
diff --git a/src/config/default.ts b/src/config/default.ts
new file mode 100644
index 0000000..18069fa
--- /dev/null
+++ b/src/config/default.ts
@@ -0,0 +1,133 @@
+import type { GuildConfig } from "../utils/database.js";
+
+export default {
+    id: "default",
+    version: 1,
+    singleEventNotifications: {
+        statsChannelDeleted: false
+    },
+    filters: {
+        images: {
+            NSFW: false,
+            size: false
+        },
+        malware: false,
+        wordFilter: {
+            enabled: false,
+            words: {
+                strict: [],
+                loose: []
+            },
+            allowed: {
+                users: [],
+                roles: [],
+                channels: []
+            }
+        },
+        invite: {
+            enabled: false,
+            allowed: {
+                users: [],
+                roles: [],
+                channels: []
+            }
+        },
+        pings: {
+            mass: 5,
+            everyone: true,
+            roles: true,
+            allowed: {
+                users: [],
+                roles: [],
+                channels: [],
+                rolesToMention: []
+            }
+        },
+        clean: {
+            channels: [],
+            allowed: {
+                users: [],
+                roles: []
+            }
+        }
+    },
+    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: false,
+            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,
+        },
+        role: {
+            role: null,
+            text: null,
+            link: null,
+        },
+        nick: {
+            text: null,
+            link: null,
+        }
+    },
+    tracks: [],
+    roleMenu: {
+        enabled: false,
+        allowWebUI: false,
+        options: [],
+    },
+    tags: {},
+    autoPublish: {
+        enabled: false,
+        channels: []
+    }
+} as GuildConfig;
diff --git a/src/events/messageCreate.ts b/src/events/messageCreate.ts
index 4f525fc..e98477b 100644
--- a/src/events/messageCreate.ts
+++ b/src/events/messageCreate.ts
@@ -5,7 +5,7 @@
 import getEmojiByName from "../utils/getEmojiByName.js";
 import client from "../utils/client.js";
 import { callback as statsChannelUpdate } from "../reflex/statsChannelUpdate.js";
-import { Message, ThreadChannel } from "discord.js";
+import { ChannelType, Message, ThreadChannel } from "discord.js";
 
 export const event = "messageCreate";
 
@@ -32,7 +32,11 @@
         if(!roleAllow && !userAllow) return await message.delete();
     }
 
-    if (config.autoPublish.enabled && config.autoPublish.channels.includes(message.channel.id)) {
+    if (config.autoPublish.enabled 
+        && config.autoPublish.channels.includes(message.channel.id)
+        && message.channel.type === ChannelType.GuildAnnouncement
+        && message.reference === null
+    ) {
         await message.crosspost();
     }
 
diff --git a/src/index.ts b/src/index.ts
index 12f6659..ddcd97b 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,3 +1,5 @@
+import "@total-typescript/ts-reset";
+
 import runServer from "./api/index.js";
 import client from "./utils/client.js";
 import config from "./config/main.js";
diff --git a/src/utils/database.ts b/src/utils/database.ts
index c1728c3..a60cf74 100644
--- a/src/utils/database.ts
+++ b/src/utils/database.ts
@@ -263,7 +263,7 @@
                 }
             }
             if(!data) return null;
-            doc = JSON.parse(Buffer.from(data).toString());
+            doc = JSON.parse(Buffer.from(data).toString()) as TranscriptSchema;
         }
         if(!doc) return null;
         return doc;
@@ -294,7 +294,7 @@
                 }
             }
             if(!data) return null;
-            doc = JSON.parse(Buffer.from(data).toString());
+            doc = JSON.parse(Buffer.from(data).toString()) as TranscriptSchema;
         }
         if(!doc) return null;
         for(const message of doc.messages) {