djs-builder 0.7.2 → 0.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -73,11 +73,10 @@ const starterOptions = {
73
73
 
74
74
  // 🌐 Dashboard Configuration (Full docs at the end of this page)
75
75
  dashboard: {
76
- clientID: "YOUR_DISCORD_CLIENT_ID", // 🔑 Discord Application Client ID
77
76
  clientSecret: "YOUR_DISCORD_CLIENT_SECRET", // 🔐 Discord Application Client Secret
78
- callbackURL: "http://localhost:3000/auth/discord/callback", // 🔗 OAuth2 Callback URL
79
- sessionSecret: "your-super-secret-key", // 🔒 Session encryption secret
80
- port: 3000, // 🌍 Dashboard port (default: 3000)
77
+ callbackURL: "http://localhost:3000/auth/discord/callback", // 🔗 OAuth2 Callback URL (OPTINAL)
78
+ sessionSecret: "your-super-secret-key", // 🔒 Session encryption secret
79
+ port: 3000, // 🌍 Dashboard port (OPTINAL / default: 3000)
81
80
  },
82
81
  };
83
82
 
@@ -507,11 +506,26 @@ message.reply(`🚫 ${member.user.tag} was banned for: ${reason}`);
507
506
  ---
508
507
 
509
508
  <details>
510
- <summary>Logging System 🛡️</summary>
509
+ <summary>Logging System 🛡️</summary>
510
+
511
+ ## 🛡️ Logging System – Track Everything in Your Server
511
512
 
512
513
  The **Logging System** is a powerful feature that keeps track of almost everything happening inside your Discord server 🔍.
513
514
  From **messages** 📝 to **channels** 📂, **roles** 🎭, **invites** 🔗, and even **voice state changes** 🎙️ – nothing goes unnoticed!
514
515
 
516
+ > **Note 1**: Using `database: true` requires a **MongoDB** connection. | **Note 2**: You can import the **Log** model for direct database access 💾.
517
+
518
+ ---
519
+
520
+ ### 📦 Module Exports
521
+
522
+ ```js
523
+ const { log, Log } = require("djs-builder");
524
+ ```
525
+
526
+ - `log(client, options)` → Start the logging system with your configuration 🚀.
527
+ - `Log` → The Mongoose model for direct database access and custom modifications 💾.
528
+
515
529
  ---
516
530
 
517
531
  ### ✨ Features
@@ -522,15 +536,70 @@ From **messages** 📝 to **channels** 📂, **roles** 🎭, **invites** 🔗, a
522
536
  - 🎙️ **Voice State** – Joins, leaves, and moves between channels.
523
537
  - 🔗 **Invites** – Created invites & usage tracking.
524
538
  - 😀 **Emojis & Stickers** – Added, removed, or updated.
539
+ - 👤 **Members** – Join, leave, kick, ban, and unban events.
525
540
  - 🚨 **Audit Log Integration** – Fetches the executor (who did what).
526
541
  - 🎨 **Beautiful Embeds** – Every log is shown in a clean, styled embed with timestamps.
542
+ - 🗄️ **Caching System** – Fast performance with built-in data caching.
543
+
544
+ ---
545
+
546
+ ### 📊 Database Schema
547
+
548
+ The logging system uses the following data structure:
549
+
550
+ ```js
551
+ {
552
+ guildId: String, // 🏠 Server ID (required)
553
+ channelId: String, // 📢 Default log channel ID
554
+ channels: Object, // 📂 Custom channels per event type (optional)
555
+ colors: Object, // 🎨 Custom colors per event type (optional)
556
+ disable: Array, // 🚫 Array of disabled event types (optional)
557
+ }
558
+ ```
527
559
 
528
560
  ---
529
561
 
530
- ### ⚙️ Setup Example
562
+ <details>
563
+ <summary>📋 Supported Event Types</summary>
564
+
565
+ ### 📋 Supported Event Types
566
+
567
+ | Event Type | Description |
568
+ | ------------------- | ------------------------- |
569
+ | `messageDelete` | Message deleted 📝 |
570
+ | `messageUpdate` | Message edited ✏️ |
571
+ | `channelCreate` | Channel created 📁 |
572
+ | `channelDelete` | Channel deleted 🗑️ |
573
+ | `channelUpdate` | Channel updated ⚙️ |
574
+ | `guildMemberAdd` | Member joined 🎉 |
575
+ | `guildMemberRemove` | Member left/kicked 🚪 |
576
+ | `guildBanAdd` | Member banned 🔨 |
577
+ | `guildBanRemove` | Member unbanned 🤗 |
578
+ | `roleCreate` | Role created 🏅 |
579
+ | `roleDelete` | Role deleted ❌ |
580
+ | `roleUpdate` | Role updated 🔄 |
581
+ | `guildMemberUpdate` | Member roles changed 👤 |
582
+ | `voiceStateUpdate` | Voice channel activity 🎤 |
583
+ | `inviteCreate` | Invite created 🔗 |
584
+ | `emojiCreate` | Emoji added 😀 |
585
+ | `emojiDelete` | Emoji removed 🚫 |
586
+ | `emojiUpdate` | Emoji updated 🔄 |
587
+ | `stickerCreate` | Sticker added ✨ |
588
+ | `stickerDelete` | Sticker removed 🗑️ |
589
+ | `stickerUpdate` | Sticker updated 🌀 |
590
+
591
+ </details>
592
+
593
+ ---
531
594
 
532
- Using the `log` function is very simple ⚡.
533
- Just place this code inside an event (like `clientReady`) to start logging:
595
+ <details>
596
+ <summary>⚡ Method Using Database (Recommended) 🗄️</summary>
597
+
598
+ ### 🗄️ Using MongoDB Database
599
+
600
+ This method stores log configuration in MongoDB, allowing dynamic management via commands.
601
+
602
+ **⚡ Setup in `clientReady` Event:**
534
603
 
535
604
  ```js
536
605
  const { log } = require("djs-builder");
@@ -538,11 +607,12 @@ const { log } = require("djs-builder");
538
607
  module.exports = {
539
608
  name: "clientReady",
540
609
  async run(client) {
541
- await log(
542
- client,
543
- "GUILD_ID", // 🏠 Guild ID (server)
544
- "CHANNEL_ID" // 📢 Channel ID for logs
545
- );
610
+ // Start logging with database mode
611
+ await log(client, {
612
+ database: true, // 🗄️ Uses MongoDB to store/fetch config
613
+ });
614
+
615
+ console.log("✅ Logging system started with database mode!");
546
616
  },
547
617
  };
548
618
  ```
@@ -551,9 +621,601 @@ module.exports = {
551
621
 
552
622
  ### 💡 How It Works
553
623
 
554
- - ✅ Pass your **Client**, **Guild ID**, and **Log Channel ID**.
555
- - 🔔 Instantly starts tracking events and sending them to the log channel.
556
- - 🧰 No extra setup required plug and play!
624
+ - ✅ The system automatically fetches log configuration for each guild from MongoDB.
625
+ - 🛠️ You can manage settings via slash commands (see management command below).
626
+ - 🎨 Supports per-guild customization for channels, colors, and disabled events.
627
+ - 📖 **Important**: If you use database mode, see the [Log Management Command](#-slash-command-for-log-management-) below to edit data.
628
+
629
+ </details>
630
+
631
+ ---
632
+
633
+ <details>
634
+ <summary>⚡ Method Using Custom Data Array 📋</summary>
635
+
636
+ ### 📋 Using Custom Data Array
637
+
638
+ This method uses a predefined array of configurations – perfect for simple setups or testing.
639
+
640
+ **⚡ Setup in `clientReady` Event:**
641
+
642
+ ```js
643
+ const { log } = require("djs-builder");
644
+
645
+ module.exports = {
646
+ name: "clientReady",
647
+ async run(client) {
648
+ // Define your log configurations
649
+ const logData = [
650
+ {
651
+ guildId: "123456789012345678", // 🏠 Server ID
652
+ channelId: "987654321098765432", // 📢 Default log channel
653
+ channels: {
654
+ // 📂 Custom channels (optional)
655
+ messageDelete: "111111111111111111",
656
+ voiceStateUpdate: "222222222222222222",
657
+ },
658
+ colors: {
659
+ // 🎨 Custom colors (optional)
660
+ messageDelete: "DarkRed",
661
+ channelCreate: "DarkGreen",
662
+ },
663
+ disable: ["inviteCreate"], // 🚫 Disabled events (optional)
664
+ },
665
+ // Add more guild configurations...
666
+ {
667
+ guildId: "999888777666555444",
668
+ channelId: "444555666777888999",
669
+ },
670
+ ];
671
+
672
+ // Start logging with custom data
673
+ await log(client, {
674
+ database: false, // 📋 Uses custom array
675
+ Data: logData, // 📊 Your configurations
676
+ });
677
+
678
+ console.log("✅ Logging system started with custom data!");
679
+ },
680
+ };
681
+ ```
682
+
683
+ ---
684
+
685
+ ### 🎨 Supported Colors
686
+
687
+ `Default`, `White`, `Aqua`, `Green`, `Blue`, `Yellow`, `Purple`, `LuminousVividPink`, `Fuchsia`, `Gold`, `Orange`, `Red`, `Grey`, `Navy`, `DarkAqua`, `DarkGreen`, `DarkBlue`, `DarkPurple`, `DarkVividPink`, `DarkGold`, `DarkOrange`, `DarkRed`, `DarkGrey`, `DarkerGrey`, `LightGrey`, `DarkNavy`, `Blurple`, `Greyple`, `DarkButNotBlack`, `NotQuiteBlack`, `Random`, or any **Hex Color** like `#FF5733`.
688
+
689
+ ---
690
+
691
+ ### 🌐 Multi-Guild Support
692
+
693
+ > 💡 **Tip:** You can add configurations for multiple guilds in the same array. Each guild can have its own unique settings for channels, colors, and disabled events!
694
+
695
+ </details>
696
+
697
+ ---
698
+
699
+ <details>
700
+ <summary>🔧 Direct Database Access with Log Model 💾</summary>
701
+
702
+ ### 💾 Using the Log Model Directly
703
+
704
+ You can import the `Log` Mongoose model to create, update, or delete log configurations programmatically.
705
+
706
+ **📥 Import the Model:**
707
+
708
+ ```js
709
+ const { Log } = require("djs-builder");
710
+ ```
711
+
712
+ **➕ Create New Configuration:**
713
+
714
+ ```js
715
+ const { Log } = require("djs-builder");
716
+
717
+ // Create a new log configuration for a guild
718
+ const newConfig = await Log.create({
719
+ guildId: "123456789012345678",
720
+ channelId: "987654321098765432",
721
+ channels: {
722
+ messageDelete: "111111111111111111",
723
+ },
724
+ colors: {
725
+ messageDelete: "Red",
726
+ },
727
+ disable: [],
728
+ });
729
+
730
+ console.log("✅ Log configuration created!", newConfig);
731
+ ```
732
+
733
+ **✏️ Update Existing Configuration:**
734
+
735
+ ```js
736
+ const { Log } = require("djs-builder");
737
+
738
+ // Update log channel
739
+ await Log.findOneAndUpdate(
740
+ { guildId: "123456789012345678" },
741
+ { channelId: "NEW_CHANNEL_ID" },
742
+ { upsert: true } // Create if doesn't exist
743
+ );
744
+
745
+ // Add event to disable list
746
+ await Log.findOneAndUpdate(
747
+ { guildId: "123456789012345678" },
748
+ { $push: { disable: "voiceStateUpdate" } }
749
+ );
750
+
751
+ // Remove event from disable list
752
+ await Log.findOneAndUpdate(
753
+ { guildId: "123456789012345678" },
754
+ { $pull: { disable: "voiceStateUpdate" } }
755
+ );
756
+
757
+ // Update specific channel for an event
758
+ await Log.findOneAndUpdate(
759
+ { guildId: "123456789012345678" },
760
+ { $set: { "channels.messageDelete": "NEW_CHANNEL_ID" } }
761
+ );
762
+
763
+ // Update specific color for an event
764
+ await Log.findOneAndUpdate(
765
+ { guildId: "123456789012345678" },
766
+ { $set: { "colors.messageDelete": "DarkRed" } }
767
+ );
768
+ ```
769
+
770
+ **🗑️ Delete Configuration:**
771
+
772
+ ```js
773
+ const { Log } = require("djs-builder");
774
+
775
+ await Log.findOneAndDelete({ guildId: "123456789012345678" });
776
+ console.log("🗑️ Log configuration deleted!");
777
+ ```
778
+
779
+ **📊 Fetch Configuration:**
780
+
781
+ ```js
782
+ const { Log } = require("djs-builder");
783
+
784
+ const config = await Log.findOne({ guildId: "123456789012345678" });
785
+ if (config) {
786
+ console.log("📢 Log Channel:", config.channelId);
787
+ console.log("📂 Custom Channels:", config.channels);
788
+ console.log("🎨 Custom Colors:", config.colors);
789
+ console.log("🚫 Disabled Events:", config.disable);
790
+ }
791
+ ```
792
+
793
+ </details>
794
+
795
+ ---
796
+
797
+ <details>
798
+ <summary>🌐 Dashboard Integration – Manage Logs from Web Panel 🖥️</summary>
799
+
800
+ ### 🖥️ Web Dashboard for Log Management
801
+
802
+ When you use **database mode** (`database: true`), you can manage the logging system directly from the **djs-builder Dashboard**! 🎛️
803
+
804
+ ---
805
+
806
+ #### ✨ Dashboard Features for Logs
807
+
808
+ | Feature | Description |
809
+ | ---------------------- | -------------------------------------------- |
810
+ | 📢 **Default Channel** | Set the main channel for all logs |
811
+ | 📂 **Custom Channels** | Assign specific channels for each event type |
812
+ | 🎨 **Custom Colors** | Choose embed colors for each event type |
813
+ | 🔄 **Toggle Events** | Enable/Disable specific event types |
814
+ | 📊 **Statistics** | View enabled/disabled events count |
815
+ | 🗑️ **Reset** | Clear all log settings with one click |
816
+
817
+ ---
818
+
819
+ #### 🚀 How to Access
820
+
821
+ 1. Navigate to your dashboard (e.g., `http://localhost:3000`)
822
+ 2. Log in with Discord OAuth2
823
+ 3. Select a server
824
+ 4. Click on **"سجلات المراقبة"** (Logs) in the sidebar
825
+
826
+ ---
827
+
828
+ #### ⚠️ Important Notes
829
+
830
+ **When `database: true`:**
831
+
832
+ - ✅ Full editing capabilities from dashboard
833
+ - ✅ Changes are saved automatically to MongoDB
834
+ - ✅ Real-time updates
835
+
836
+ **When `database: false` (Custom Data Array):**
837
+
838
+ - ⚠️ Dashboard shows **read-only** mode
839
+ - ⚠️ A warning banner appears at the top
840
+ - ⚠️ You must edit settings in your code
841
+
842
+ </details>
843
+
844
+ ---
845
+
846
+ <details>
847
+ <summary>🎮 Slash Command for Log Management 🛠️</summary>
848
+
849
+ ### 🛠️ Complete Log Management Slash Command
850
+
851
+ This command allows server administrators to manage the logging system via Discord.
852
+
853
+ > ⚠️ **Important**: This command requires `database: true` mode to work properly.
854
+
855
+ ```js
856
+ const { Log, getLogConfigData } = require("djs-builder");
857
+ const {
858
+ SlashCommandBuilder,
859
+ PermissionFlagsBits,
860
+ EmbedBuilder,
861
+ ChannelType,
862
+ } = require("discord.js");
863
+
864
+ // All supported event types (21 events)
865
+ const EVENT_TYPES = [
866
+ { name: "Message Delete", value: "messageDelete" },
867
+ { name: "Message Update", value: "messageUpdate" },
868
+ { name: "Channel Create", value: "channelCreate" },
869
+ { name: "Channel Delete", value: "channelDelete" },
870
+ { name: "Channel Update", value: "channelUpdate" },
871
+ { name: "Member Join", value: "guildMemberAdd" },
872
+ { name: "Member Leave", value: "guildMemberRemove" },
873
+ { name: "Member Ban", value: "guildBanAdd" },
874
+ { name: "Member Unban", value: "guildBanRemove" },
875
+ { name: "Role Create", value: "roleCreate" },
876
+ { name: "Role Delete", value: "roleDelete" },
877
+ { name: "Role Update", value: "roleUpdate" },
878
+ { name: "Member Role Update", value: "guildMemberUpdate" },
879
+ { name: "Voice State", value: "voiceStateUpdate" },
880
+ { name: "Invite Create", value: "inviteCreate" },
881
+ { name: "Emoji Create", value: "emojiCreate" },
882
+ { name: "Emoji Delete", value: "emojiDelete" },
883
+ { name: "Emoji Update", value: "emojiUpdate" },
884
+ { name: "Sticker Create", value: "stickerCreate" },
885
+ { name: "Sticker Delete", value: "stickerDelete" },
886
+ { name: "Sticker Update", value: "stickerUpdate" },
887
+ ];
888
+
889
+ // Helper function to clear cache after updates
890
+ function clearLogCache(guildId) {
891
+ const logData = getLogConfigData();
892
+ if (logData.clearCache) logData.clearCache(guildId);
893
+ }
894
+
895
+ module.exports = {
896
+ data: new SlashCommandBuilder()
897
+ .setName("logs")
898
+ .setDescription("🛡️ Manage the server logging system")
899
+ .setDefaultMemberPermissions(PermissionFlagsBits.Administrator)
900
+ .addSubcommand((sub) =>
901
+ sub
902
+ .setName("setup")
903
+ .setDescription("📢 Set up the default log channel")
904
+ .addChannelOption((opt) =>
905
+ opt
906
+ .setName("channel")
907
+ .setDescription("The channel to send logs to")
908
+ .addChannelTypes(ChannelType.GuildText)
909
+ .setRequired(true)
910
+ )
911
+ )
912
+ .addSubcommand((sub) =>
913
+ sub
914
+ .setName("channel")
915
+ .setDescription("📂 Set a specific channel for an event type")
916
+ .addStringOption((opt) =>
917
+ opt
918
+ .setName("event")
919
+ .setDescription("The event type")
920
+ .setRequired(true)
921
+ .addChoices(...EVENT_TYPES)
922
+ )
923
+ .addChannelOption((opt) =>
924
+ opt
925
+ .setName("channel")
926
+ .setDescription("The channel for this event")
927
+ .addChannelTypes(ChannelType.GuildText)
928
+ .setRequired(true)
929
+ )
930
+ )
931
+ .addSubcommand((sub) =>
932
+ sub
933
+ .setName("color")
934
+ .setDescription("🎨 Set a custom color for an event type")
935
+ .addStringOption((opt) =>
936
+ opt
937
+ .setName("event")
938
+ .setDescription("The event type")
939
+ .setRequired(true)
940
+ .addChoices(...EVENT_TYPES)
941
+ )
942
+ .addStringOption((opt) =>
943
+ opt
944
+ .setName("color")
945
+ .setDescription("Color name or hex code (e.g., Red, #FF5733)")
946
+ .setRequired(true)
947
+ )
948
+ )
949
+ .addSubcommand((sub) =>
950
+ sub
951
+ .setName("toggle")
952
+ .setDescription("🔄 Enable or disable an event type")
953
+ .addStringOption((opt) =>
954
+ opt
955
+ .setName("event")
956
+ .setDescription("The event type")
957
+ .setRequired(true)
958
+ .addChoices(...EVENT_TYPES)
959
+ )
960
+ .addStringOption((opt) =>
961
+ opt
962
+ .setName("action")
963
+ .setDescription("Enable or disable")
964
+ .setRequired(true)
965
+ .addChoices(
966
+ { name: "Enable", value: "enable" },
967
+ { name: "Disable", value: "disable" }
968
+ )
969
+ )
970
+ )
971
+ .addSubcommand((sub) =>
972
+ sub.setName("view").setDescription("📊 View current log configuration")
973
+ )
974
+ .addSubcommand((sub) =>
975
+ sub
976
+ .setName("reset")
977
+ .setDescription("🗑️ Reset all log settings for this server")
978
+ ),
979
+
980
+ async run(client, interaction) {
981
+ await interaction.deferReply({ ephemeral: true });
982
+
983
+ const subcommand = interaction.options.getSubcommand();
984
+ const guildId = interaction.guild.id;
985
+
986
+ // ═══════════════════════════════════════════════════════
987
+ // 📢 SETUP - Set default log channel
988
+ // ═══════════════════════════════════════════════════════
989
+ if (subcommand === "setup") {
990
+ const channel = interaction.options.getChannel("channel");
991
+
992
+ await Log.findOneAndUpdate(
993
+ { guildId },
994
+ { guildId, channelId: channel.id },
995
+ { upsert: true, new: true }
996
+ );
997
+
998
+ clearLogCache(guildId); // Clear cache to apply changes immediately
999
+
1000
+ const embed = new EmbedBuilder()
1001
+ .setTitle("✅ Logging System Setup")
1002
+ .setDescription(`Logs will now be sent to ${channel}`)
1003
+ .setColor("Green")
1004
+ .setTimestamp();
1005
+
1006
+ return interaction.editReply({ embeds: [embed] });
1007
+ }
1008
+
1009
+ // ═══════════════════════════════════════════════════════
1010
+ // 📂 CHANNEL - Set specific channel for event
1011
+ // ═══════════════════════════════════════════════════════
1012
+ if (subcommand === "channel") {
1013
+ const event = interaction.options.getString("event");
1014
+ const channel = interaction.options.getChannel("channel");
1015
+
1016
+ await Log.findOneAndUpdate(
1017
+ { guildId },
1018
+ { $set: { [`channels.${event}`]: channel.id } },
1019
+ { upsert: true }
1020
+ );
1021
+
1022
+ clearLogCache(guildId);
1023
+
1024
+ const eventName =
1025
+ EVENT_TYPES.find((e) => e.value === event)?.name || event;
1026
+ const embed = new EmbedBuilder()
1027
+ .setTitle("📂 Event Channel Updated")
1028
+ .setDescription(`**${eventName}** logs will now be sent to ${channel}`)
1029
+ .setColor("Blue")
1030
+ .setTimestamp();
1031
+
1032
+ return interaction.editReply({ embeds: [embed] });
1033
+ }
1034
+
1035
+ // ═══════════════════════════════════════════════════════
1036
+ // 🎨 COLOR - Set custom color for event
1037
+ // ═══════════════════════════════════════════════════════
1038
+ if (subcommand === "color") {
1039
+ const event = interaction.options.getString("event");
1040
+ const color = interaction.options.getString("color");
1041
+
1042
+ await Log.findOneAndUpdate(
1043
+ { guildId },
1044
+ { $set: { [`colors.${event}`]: color } },
1045
+ { upsert: true }
1046
+ );
1047
+
1048
+ clearLogCache(guildId);
1049
+
1050
+ const eventName =
1051
+ EVENT_TYPES.find((e) => e.value === event)?.name || event;
1052
+
1053
+ // Try to use the color, fallback to Blue if invalid
1054
+ let embedColor;
1055
+ try {
1056
+ embedColor = color;
1057
+ } catch {
1058
+ embedColor = "Blue";
1059
+ }
1060
+
1061
+ const embed = new EmbedBuilder()
1062
+ .setTitle("🎨 Event Color Updated")
1063
+ .setDescription(
1064
+ `**${eventName}** embeds will now use color: \`${color}\``
1065
+ )
1066
+ .setColor(embedColor)
1067
+ .setTimestamp();
1068
+
1069
+ return interaction.editReply({ embeds: [embed] });
1070
+ }
1071
+
1072
+ // ═══════════════════════════════════════════════════════
1073
+ // 🔄 TOGGLE - Enable/Disable event
1074
+ // ═══════════════════════════════════════════════════════
1075
+ if (subcommand === "toggle") {
1076
+ const event = interaction.options.getString("event");
1077
+ const action = interaction.options.getString("action");
1078
+
1079
+ if (action === "disable") {
1080
+ await Log.findOneAndUpdate(
1081
+ { guildId },
1082
+ { $addToSet: { disable: event } },
1083
+ { upsert: true }
1084
+ );
1085
+ } else {
1086
+ await Log.findOneAndUpdate(
1087
+ { guildId },
1088
+ { $pull: { disable: event } },
1089
+ { upsert: true }
1090
+ );
1091
+ }
1092
+
1093
+ clearLogCache(guildId);
1094
+
1095
+ const eventName =
1096
+ EVENT_TYPES.find((e) => e.value === event)?.name || event;
1097
+ const embed = new EmbedBuilder()
1098
+ .setTitle(
1099
+ action === "disable" ? "🚫 Event Disabled" : "✅ Event Enabled"
1100
+ )
1101
+ .setDescription(`**${eventName}** logging has been ${action}d`)
1102
+ .setColor(action === "disable" ? "Red" : "Green")
1103
+ .setTimestamp();
1104
+
1105
+ return interaction.editReply({ embeds: [embed] });
1106
+ }
1107
+
1108
+ // ═══════════════════════════════════════════════════════
1109
+ // 📊 VIEW - Show current configuration
1110
+ // ═══════════════════════════════════════════════════════
1111
+ if (subcommand === "view") {
1112
+ const config = await Log.findOne({ guildId });
1113
+
1114
+ if (!config) {
1115
+ return interaction.editReply({
1116
+ content:
1117
+ "❌ No logging configuration found for this server. Use `/logs setup` first!",
1118
+ });
1119
+ }
1120
+
1121
+ const channelsList = config.channels
1122
+ ? Object.entries(config.channels)
1123
+ .map(([k, v]) => {
1124
+ const eventName = EVENT_TYPES.find((e) => e.value === k)?.name || k;
1125
+ return `• **${eventName}**: <#${v}>`;
1126
+ })
1127
+ .join("\n") || "None"
1128
+ : "None";
1129
+
1130
+ const colorsList = config.colors
1131
+ ? Object.entries(config.colors)
1132
+ .map(([k, v]) => {
1133
+ const eventName = EVENT_TYPES.find((e) => e.value === k)?.name || k;
1134
+ return `• **${eventName}**: \`${v}\``;
1135
+ })
1136
+ .join("\n") || "None"
1137
+ : "None";
1138
+
1139
+ const disabledList =
1140
+ config.disable?.length > 0
1141
+ ? config.disable.map((e) => {
1142
+ const eventName = EVENT_TYPES.find((ev) => ev.value === e)?.name || e;
1143
+ return `• ${eventName}`;
1144
+ }).join("\n")
1145
+ : "None";
1146
+
1147
+ const enabledCount = EVENT_TYPES.length - (config.disable?.length || 0);
1148
+
1149
+ const embed = new EmbedBuilder()
1150
+ .setTitle("📊 Log Configuration")
1151
+ .setDescription(`**${enabledCount}/${EVENT_TYPES.length}** events are enabled`)
1152
+ .setColor("Blue")
1153
+ .addFields(
1154
+ {
1155
+ name: "📢 Default Channel",
1156
+ value: config.channelId ? `<#${config.channelId}>` : "Not set",
1157
+ inline: true,
1158
+ },
1159
+ {
1160
+ name: "📂 Custom Channels",
1161
+ value: channelsList.slice(0, 1024) || "None",
1162
+ inline: false,
1163
+ },
1164
+ {
1165
+ name: "🎨 Custom Colors",
1166
+ value: colorsList.slice(0, 1024) || "None",
1167
+ inline: false,
1168
+ },
1169
+ {
1170
+ name: "🚫 Disabled Events",
1171
+ value: disabledList.slice(0, 1024) || "None",
1172
+ inline: false,
1173
+ }
1174
+ )
1175
+ .setFooter({ text: `Guild ID: ${guildId}` })
1176
+ .setTimestamp();
1177
+
1178
+ return interaction.editReply({ embeds: [embed] });
1179
+ }
1180
+
1181
+ // ═══════════════════════════════════════════════════════
1182
+ // 🗑️ RESET - Delete all configuration
1183
+ // ═══════════════════════════════════════════════════════
1184
+ if (subcommand === "reset") {
1185
+ await Log.findOneAndDelete({ guildId });
1186
+
1187
+ clearLogCache(guildId);
1188
+
1189
+ const embed = new EmbedBuilder()
1190
+ .setTitle("🗑️ Configuration Reset")
1191
+ .setDescription(
1192
+ "All logging settings have been deleted for this server."
1193
+ )
1194
+ .setColor("Red")
1195
+ .setTimestamp();
1196
+
1197
+ return interaction.editReply({ embeds: [embed] });
1198
+ }
1199
+ },
1200
+ };
1201
+ ```
1202
+
1203
+ </details>
1204
+
1205
+ ---
1206
+
1207
+ ### 💡 Tips & Notes
1208
+
1209
+ - 🔄 **Caching**: The system caches guild configurations for better performance.
1210
+ - 🔐 **Permissions**: Make sure your bot has `View Audit Log` permission for full functionality.
1211
+ - 📢 **Invite Tracking**: Uses `discord-inviter` package for accurate invite tracking.
1212
+ - 🎨 **Default Colors**: Each event type has sensible default colors if not customized.
1213
+ - 🚫 **Disabled Events**: Events in the `disable` array will be completely ignored.
1214
+ - 📂 **Channel Fallback**: If no specific channel is set for an event, it uses `channelId`.
1215
+ - 💾 **Database Mode**: Recommended for multi-server bots with dynamic configuration needs.
1216
+ - 🌐 **Dashboard Integration**: When using database mode, you can manage logs via the web dashboard!
1217
+
1218
+ ---
557
1219
 
558
1220
  </details>
559
1221
 
@@ -809,55 +1471,54 @@ const { Gstart } = require("djs-builder");
809
1471
  const { EmbedBuilder } = require("discord.js");
810
1472
 
811
1473
  module.exports = {
812
-   name: "gstart",
813
-   description: "Starts a new highly-customized giveaway.",
814
-   run: async (client, message, args) => {
815
-     // ⏰ Giveaway ends in 48 hours
816
- const twoDays = Date.now() + (48 * 60 * 60 * 1000);
817
- const channelId = 'YOUR_GIVEAWAY_CHANNEL_ID'; // 📢 Target Channel
818
-
819
-     await Gstart({
820
-       context: message,
821
-       endTime: twoDays,
822
-       winers: 5, // 5 lucky winners! 🏆
823
-       channelId: channelId,
1474
+ name: "gstart",
1475
+ description: "Starts a new highly-customized giveaway.",
1476
+ run: async (client, message, args) => {
1477
+ // ⏰ Giveaway ends in 48 hours
1478
+ const twoDays = Date.now() + 48 * 60 * 60 * 1000;
1479
+ const channelId = "YOUR_GIVEAWAY_CHANNEL_ID"; // 📢 Target Channel
824
1480
 
825
- // 🎨 Customization for the STARTING EMBED
826
-       embed: {
1481
+ await Gstart({
1482
+ context: message,
1483
+ endTime: twoDays,
1484
+ winers: 5, // 5 lucky winners! 🏆
1485
+ channelId: channelId,
827
1486
 
828
- custom: new EmbedBuilder().setTitle("Raw Embed"),// 💡 You can use 'custom' to pass a raw Discord.js EmbedBuilder JSON
829
-             title: "🎉 **HUGE SERVER BOOST GIVEAWAY!**",
830
-             description: "Click the button below to enter for a chance to win a free server boost!",
831
-             color: "Blue", // Any valid Discord color
832
- image: "https://yourimage.com/banner.png", // image URL
833
-             thumbnail: message.guild.iconURL(),
834
-       },
1487
+ // 🎨 Customization for the STARTING EMBED
1488
+ embed: {
1489
+ custom: new EmbedBuilder().setTitle("Raw Embed"), // 💡 You can use 'custom' to pass a raw Discord.js EmbedBuilder JSON
1490
+ title: "🎉 **HUGE SERVER BOOST GIVEAWAY!**",
1491
+ description:
1492
+ "Click the button below to enter for a chance to win a free server boost!",
1493
+ color: "Blue", // Any valid Discord color
1494
+ image: "https://yourimage.com/banner.png", // image URL
1495
+ thumbnail: message.guild.iconURL(),
1496
+ },
835
1497
 
836
1498
  // 🛑 Customization for the ENDED EMBED
837
-       endEmbed: {
838
- custom: new EmbedBuilder().setTitle("Raw Embed"),// 💡 You can use 'custom' to pass a raw Discord.js EmbedBuilder JSON
839
-             title: "🛑 Giveaway Has Concluded!",
840
-             description: "Congratulations to the winners! Check the message below.",
841
-             color: "Green",
842
-             // Eimage and Ethumbnail can also be set here
843
-       },
1499
+ endEmbed: {
1500
+ custom: new EmbedBuilder().setTitle("Raw Embed"), // 💡 You can use 'custom' to pass a raw Discord.js EmbedBuilder JSON
1501
+ title: "🛑 Giveaway Has Concluded!",
1502
+ description: "Congratulations to the winners! Check the message below.",
1503
+ color: "Green", // Eimage and Ethumbnail can also be set here
1504
+ },
844
1505
 
845
1506
  // 🖱️ Button Entry Method
846
-       reaction: {
847
-         type: "button", // Use 'reaction' for an emoji reaction
848
-         emoji: "✅", // The emoji displayed on the button
849
-         label: "Enter Giveaway!", // The text label
850
-         style: 3, // Button style: Primary(1), Secondary(2), Success(3), Danger(4)
851
-         id: "djs-builder-giveaway", // Custom ID for the button
852
-       },
1507
+ reaction: {
1508
+ type: "button", // Use 'reaction' for an emoji reaction
1509
+ emoji: "✅", // The emoji displayed on the button
1510
+ label: "Enter Giveaway!", // The text label
1511
+ style: 3, // Button style: Primary(1), Secondary(2), Success(3), Danger(4)
1512
+ id: "djs-builder-giveaway", // Custom ID for the button
1513
+ },
853
1514
 
854
1515
  // 🔒 Requirements (Optional)
855
1516
  requirements: {
856
1517
  requiredRoles: ["123456789012345678"], // 🛡️ User MUST have this role to join (Button Only)
857
1518
  },
858
-     });
859
-     message.reply("🎉 Giveaway started successfully!");
860
-   },
1519
+ });
1520
+ message.reply("🎉 Giveaway started successfully!");
1521
+ },
861
1522
  };
862
1523
  ```
863
1524
 
@@ -1103,14 +1764,14 @@ module.exports = {
1103
1764
  const result = await GaddUser(
1104
1765
  interaction.message.id,
1105
1766
  interaction.user.id,
1106
- interaction.guild
1767
+ interaction.guild
1107
1768
  );
1108
1769
 
1109
1770
  if (result?.error) {
1110
1771
  // Handles both "User Already Joined" and "Missing Roles" errors
1111
1772
  if (result.error === "❌ User Already Joined") {
1112
- // ... (Leave button logic)
1113
- const row = await CreateRow([
1773
+ // ... (Leave button logic)
1774
+ const row = await CreateRow([
1114
1775
  [
1115
1776
  {
1116
1777
  label: "Leave Giveaway",
@@ -1120,16 +1781,17 @@ module.exports = {
1120
1781
  ],
1121
1782
  ]);
1122
1783
  return interaction.reply({
1123
- content: "⚠️ You have **already joined** this giveaway! You can **leave** by clicking the button below.",
1784
+ content:
1785
+ "⚠️ You have **already joined** this giveaway! You can **leave** by clicking the button below.",
1124
1786
  components: row,
1125
- flags: 64,
1787
+ flags: 64,
1126
1788
  });
1127
1789
  }
1128
-
1790
+
1129
1791
  // Show error (e.g. Missing Role)
1130
1792
  return interaction.reply({
1131
- content: result.error,
1132
- flags: 64
1793
+ content: result.error,
1794
+ flags: 64,
1133
1795
  });
1134
1796
  }
1135
1797
 
@@ -1139,7 +1801,6 @@ module.exports = {
1139
1801
  });
1140
1802
  }
1141
1803
 
1142
-
1143
1804
  // 2. Handle Leave Button Click (Dynamically Generated ID)
1144
1805
  if (
1145
1806
  interaction.customId &&
@@ -1534,7 +2195,7 @@ module.exports = {
1534
2195
  channelId: channel.id,
1535
2196
  winers: winnerCount,
1536
2197
  endTime: endTimeMs,
1537
- prize : prize,
2198
+ prize: prize,
1538
2199
  embed: {
1539
2200
  title: `🎉 ${prize} Giveaway!`,
1540
2201
  image: image,
@@ -1810,7 +2471,6 @@ module.exports = {
1810
2471
 
1811
2472
  ---
1812
2473
 
1813
-
1814
2474
  <details>
1815
2475
  <summary>Blacklist System 🚫</summary>
1816
2476
 
@@ -1882,10 +2542,12 @@ console.log("Role unblacklisted! 🔓");
1882
2542
  Returns an array of blacklisted items for a guild. You can optionally filter by type (`user`, `role`, `channel`).
1883
2543
 
1884
2544
  **Parameters:**
2545
+
1885
2546
  - `guildId` (String): The ID of the guild.
1886
2547
  - `type` (String, optional): The type to filter by (`user`, `role`, `channel`).
1887
2548
 
1888
2549
  **Example:**
2550
+
1889
2551
  ```js
1890
2552
  // Get all blacklisted items
1891
2553
  const allBlacklisted = await getBlacklist("GUILD_ID");
@@ -1910,35 +2572,80 @@ Output:
1910
2572
  You can create a slash command to manage the blacklist easily.
1911
2573
 
1912
2574
  ```js
1913
- const { addToBlacklist, removeFromBlacklist, isBlacklisted, getBlacklist } = require("djs-builder");
1914
- const { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder } = require("discord.js");
2575
+ const {
2576
+ addToBlacklist,
2577
+ removeFromBlacklist,
2578
+ isBlacklisted,
2579
+ getBlacklist,
2580
+ } = require("djs-builder");
2581
+ const {
2582
+ SlashCommandBuilder,
2583
+ PermissionFlagsBits,
2584
+ EmbedBuilder,
2585
+ } = require("discord.js");
1915
2586
 
1916
2587
  module.exports = {
1917
2588
  data: new SlashCommandBuilder()
1918
2589
  .setName("blacklist")
1919
2590
  .setDescription("Manage the blacklist")
1920
2591
  .setDefaultMemberPermissions(PermissionFlagsBits.Administrator)
1921
- .addSubcommand(sub =>
1922
- sub.setName("add").setDescription("Add to blacklist")
1923
- .addUserOption(opt => opt.setName("user").setDescription("User to blacklist"))
1924
- .addRoleOption(opt => opt.setName("role").setDescription("Role to blacklist"))
1925
- .addChannelOption(opt => opt.setName("channel").setDescription("Channel to blacklist"))
2592
+ .addSubcommand((sub) =>
2593
+ sub
2594
+ .setName("add")
2595
+ .setDescription("Add to blacklist")
2596
+ .addUserOption((opt) =>
2597
+ opt.setName("user").setDescription("User to blacklist")
2598
+ )
2599
+ .addRoleOption((opt) =>
2600
+ opt.setName("role").setDescription("Role to blacklist")
2601
+ )
2602
+ .addChannelOption((opt) =>
2603
+ opt.setName("channel").setDescription("Channel to blacklist")
2604
+ )
1926
2605
  )
1927
- .addSubcommand(sub =>
1928
- sub.setName("remove").setDescription("Remove from blacklist")
1929
- .addUserOption(opt => opt.setName("user").setDescription("User to remove"))
1930
- .addRoleOption(opt => opt.setName("role").setDescription("Role to remove"))
1931
- .addChannelOption(opt => opt.setName("channel").setDescription("Channel to remove"))
2606
+ .addSubcommand((sub) =>
2607
+ sub
2608
+ .setName("remove")
2609
+ .setDescription("Remove from blacklist")
2610
+ .addUserOption((opt) =>
2611
+ opt.setName("user").setDescription("User to remove")
2612
+ )
2613
+ .addRoleOption((opt) =>
2614
+ opt.setName("role").setDescription("Role to remove")
2615
+ )
2616
+ .addChannelOption((opt) =>
2617
+ opt.setName("channel").setDescription("Channel to remove")
2618
+ )
1932
2619
  )
1933
- .addSubcommand(sub =>
1934
- sub.setName("check").setDescription("Check if a target is blacklisted")
1935
- .addUserOption(opt => opt.setName("user").setDescription("User to check"))
1936
- .addRoleOption(opt => opt.setName("role").setDescription("Role to check"))
1937
- .addChannelOption(opt => opt.setName("channel").setDescription("Channel to check"))
2620
+ .addSubcommand((sub) =>
2621
+ sub
2622
+ .setName("check")
2623
+ .setDescription("Check if a target is blacklisted")
2624
+ .addUserOption((opt) =>
2625
+ opt.setName("user").setDescription("User to check")
2626
+ )
2627
+ .addRoleOption((opt) =>
2628
+ opt.setName("role").setDescription("Role to check")
2629
+ )
2630
+ .addChannelOption((opt) =>
2631
+ opt.setName("channel").setDescription("Channel to check")
2632
+ )
1938
2633
  )
1939
- .addSubcommand(sub =>
1940
- sub.setName("list").setDescription("List all blacklisted items")
1941
- .addStringOption(opt => opt.setName("type").setDescription("Filter by type").addChoices({ name: "User", value: "user" }, { name: "Role", value: "role" }, { name: "Channel", value: "channel" } , { name: "All", value: "all" }))
2634
+ .addSubcommand((sub) =>
2635
+ sub
2636
+ .setName("list")
2637
+ .setDescription("List all blacklisted items")
2638
+ .addStringOption((opt) =>
2639
+ opt
2640
+ .setName("type")
2641
+ .setDescription("Filter by type")
2642
+ .addChoices(
2643
+ { name: "User", value: "user" },
2644
+ { name: "Role", value: "role" },
2645
+ { name: "Channel", value: "channel" },
2646
+ { name: "All", value: "all" }
2647
+ )
2648
+ )
1942
2649
  ),
1943
2650
  async run(interaction) {
1944
2651
  const sub = interaction.options.getSubcommand();
@@ -1948,54 +2655,95 @@ module.exports = {
1948
2655
  const guildId = interaction.guild.id;
1949
2656
 
1950
2657
  if (sub === "list") {
1951
- const type = interaction.options.getString("type");
1952
- if (type !== "all") {
2658
+ const type = interaction.options.getString("type");
2659
+ if (type !== "all") {
1953
2660
  const list = await getBlacklist(guildId, type);
1954
2661
 
1955
- if (!list.length) return interaction.reply({ content: "✅ No blacklisted items found.", flags : 64 });
2662
+ if (!list.length)
2663
+ return interaction.reply({
2664
+ content: "✅ No blacklisted items found.",
2665
+ flags: 64,
2666
+ });
1956
2667
 
1957
2668
  const embed = new EmbedBuilder()
1958
- .setTitle("🚫 Blacklist")
1959
- .setColor("Red")
1960
- .setDescription(list.map(item => `• **${item.type.toUpperCase()}**: <${item.type === 'channel' ? '#' : item.type === 'role' ? '@&' : '@'}${item.id}> (\`${item.id}\`)`).join("\n").slice(0, 4000));
1961
-
1962
- return interaction.reply({ embeds: [embed], flags : 64 });
1963
- } else {
2669
+ .setTitle("🚫 Blacklist")
2670
+ .setColor("Red")
2671
+ .setDescription(
2672
+ list
2673
+ .map(
2674
+ (item) =>
2675
+ `• **${item.type.toUpperCase()}**: <${
2676
+ item.type === "channel"
2677
+ ? "#"
2678
+ : item.type === "role"
2679
+ ? "@&"
2680
+ : "@"
2681
+ }${item.id}> (\`${item.id}\`)`
2682
+ )
2683
+ .join("\n")
2684
+ .slice(0, 4000)
2685
+ );
2686
+
2687
+ return interaction.reply({ embeds: [embed], flags: 64 });
2688
+ } else {
1964
2689
  const list = await getBlacklist(guildId);
1965
- if (!list.length) return interaction.reply({ content: "✅ No blacklisted items found.", flags : 64 });
2690
+ if (!list.length)
2691
+ return interaction.reply({
2692
+ content: "✅ No blacklisted items found.",
2693
+ flags: 64,
2694
+ });
1966
2695
 
1967
2696
  const embeds = [];
1968
- const roles = list.filter(i => i.type === "role");
1969
- const users = list.filter(i => i.type === "user");
1970
- const channels = list.filter(i => i.type === "channel");
2697
+ const roles = list.filter((i) => i.type === "role");
2698
+ const users = list.filter((i) => i.type === "user");
2699
+ const channels = list.filter((i) => i.type === "channel");
1971
2700
 
1972
2701
  if (users.length) {
1973
- const userEmbed = new EmbedBuilder()
2702
+ const userEmbed = new EmbedBuilder()
1974
2703
  .setTitle("🚫 Blacklisted Users")
1975
2704
  .setColor("Red")
1976
- .setDescription(users.map(item => `• <@${item.id}> (\`${item.id}\`)`).join("\n").slice(0, 4000));
1977
- embeds.push(userEmbed);
2705
+ .setDescription(
2706
+ users
2707
+ .map((item) => `• <@${item.id}> (\`${item.id}\`)`)
2708
+ .join("\n")
2709
+ .slice(0, 4000)
2710
+ );
2711
+ embeds.push(userEmbed);
1978
2712
  }
1979
- if( roles.length) {
1980
- const roleEmbed = new EmbedBuilder()
2713
+ if (roles.length) {
2714
+ const roleEmbed = new EmbedBuilder()
1981
2715
  .setTitle("🚫 Blacklisted Roles")
1982
2716
  .setColor("Red")
1983
- .setDescription(roles.map(item => `• <@&${item.id}> (\`${item.id}\`)`).join("\n").slice(0, 4000));
1984
- embeds.push(roleEmbed);
2717
+ .setDescription(
2718
+ roles
2719
+ .map((item) => `• <@&${item.id}> (\`${item.id}\`)`)
2720
+ .join("\n")
2721
+ .slice(0, 4000)
2722
+ );
2723
+ embeds.push(roleEmbed);
1985
2724
  }
1986
- if( channels.length) {
1987
- const channelEmbed = new EmbedBuilder()
2725
+ if (channels.length) {
2726
+ const channelEmbed = new EmbedBuilder()
1988
2727
  .setTitle("🚫 Blacklisted Channels")
1989
2728
  .setColor("Red")
1990
- .setDescription(channels.map(item => `• <#${item.id}> (\`${item.id}\`)`).join("\n").slice(0, 4000));
1991
- embeds.push(channelEmbed);
2729
+ .setDescription(
2730
+ channels
2731
+ .map((item) => `• <#${item.id}> (\`${item.id}\`)`)
2732
+ .join("\n")
2733
+ .slice(0, 4000)
2734
+ );
2735
+ embeds.push(channelEmbed);
1992
2736
  }
1993
- return interaction.reply({ embeds, flags : 64 });
2737
+ return interaction.reply({ embeds, flags: 64 });
2738
+ }
1994
2739
  }
1995
- }
1996
-
2740
+
1997
2741
  if (!user && !role && !channel) {
1998
- return interaction.reply({ content: "⚠️ You must provide at least one option (User, Role, or Channel).", flags : 64 });
2742
+ return interaction.reply({
2743
+ content:
2744
+ "⚠️ You must provide at least one option (User, Role, or Channel).",
2745
+ flags: 64,
2746
+ });
1999
2747
  }
2000
2748
  const target = user || role || channel;
2001
2749
  const type = user ? "user" : role ? "role" : "channel";
@@ -2003,18 +2751,25 @@ module.exports = {
2003
2751
 
2004
2752
  if (sub === "add") {
2005
2753
  const success = await addToBlacklist(guildId, type, id);
2006
- if (success) interaction.reply(`✅ Added **${type}** ${target} to blacklist.`);
2007
- else interaction.reply(`⚠️ **${type}** ${target} is already blacklisted.`);
2754
+ if (success)
2755
+ interaction.reply(`✅ Added **${type}** ${target} to blacklist.`);
2756
+ else
2757
+ interaction.reply(`⚠️ **${type}** ${target} is already blacklisted.`);
2008
2758
  } else if (sub === "remove") {
2009
2759
  const success = await removeFromBlacklist(guildId, type, id);
2010
- if (success) interaction.reply(`✅ Removed **${type}** ${target} from blacklist.`);
2760
+ if (success)
2761
+ interaction.reply(`✅ Removed **${type}** ${target} from blacklist.`);
2011
2762
  else interaction.reply(`⚠️ **${type}** ${target} is not blacklisted.`);
2012
2763
  } else if (sub === "check") {
2013
2764
  const isBlocked = await isBlacklisted(guildId, type, id);
2014
- if (isBlocked) interaction.reply(`🚫 **${type}** ${target} is currently **blacklisted**.`);
2015
- else interaction.reply(`✅ **${type}** ${target} is **not** blacklisted.`);
2765
+ if (isBlocked)
2766
+ interaction.reply(
2767
+ `🚫 **${type}** ${target} is currently **blacklisted**.`
2768
+ );
2769
+ else
2770
+ interaction.reply(`✅ **${type}** ${target} is **not** blacklisted.`);
2016
2771
  }
2017
- }
2772
+ },
2018
2773
  };
2019
2774
  ```
2020
2775
 
@@ -2160,6 +2915,7 @@ The **Dashboard System** is a modern, lightweight web-based control panel for yo
2160
2915
  - 📜 **Commands Viewer** – Browse all slash and prefix commands.
2161
2916
  - 🏆 **Level System Management** – View leaderboards, manage user XP and levels.
2162
2917
  - 🎉 **Giveaway Control** – Pause, resume, end, reroll, or delete giveaways.
2918
+ - 🦾 **Logging System Control** – Manage log channels, colors, and event toggles.
2163
2919
  - 🚫 **Blacklist Management** – Add/remove users, roles, or channels from blacklist.
2164
2920
  - 🎨 **Modern UI** – Beautiful, responsive design with dark mode support.
2165
2921
 
@@ -2191,11 +2947,10 @@ const starterOptions = {
2191
2947
 
2192
2948
  // 🌐 Dashboard Configuration
2193
2949
  dashboard: {
2194
- clientID: "YOUR_DISCORD_CLIENT_ID", // 🔑 Discord Application Client ID
2195
2950
  clientSecret: "YOUR_DISCORD_CLIENT_SECRET", // 🔐 Discord Application Client Secret
2196
- callbackURL: "http://localhost:3000/auth/discord/callback", // 🔗 OAuth2 Callback URL
2197
- sessionSecret: "your-super-secret-key", // 🔒 Session encryption secret
2198
- port: 3000, // 🌍 Dashboard port (default: 3000)
2951
+ callbackURL: "http://localhost:3000/auth/discord/callback", // 🔗 OAuth2 Callback URL (OPTINAL)
2952
+ sessionSecret: "your-super-secret-key", // 🔒 Session encryption secret
2953
+ port: 3000, // 🌍 Dashboard port (OPTINAL / default: 3000)
2199
2954
  },
2200
2955
 
2201
2956
  // ... other options (Status, database, anticrash, etc.)
@@ -2229,11 +2984,10 @@ client.once("ready", () => {
2229
2984
 
2230
2985
  // 🌐 Start the Dashboard
2231
2986
  dashboard(client, {
2232
- clientID: "YOUR_DISCORD_CLIENT_ID", // 🔑 Discord Application Client ID
2233
2987
  clientSecret: "YOUR_DISCORD_CLIENT_SECRET", // 🔐 Discord Application Client Secret
2234
- callbackURL: "http://localhost:3000/auth/discord/callback", // 🔗 OAuth2 Callback URL
2235
- sessionSecret: "your-super-secret-key", // 🔒 Session encryption secret
2236
- port: 3000, // 🌍 Dashboard port (default: 3000)
2988
+ callbackURL: "http://localhost:3000/auth/discord/callback", // 🔗 OAuth2 Callback URL (OPTINAL)
2989
+ sessionSecret: "your-super-secret-key", // 🔒 Session encryption secret
2990
+ port: 3000, // 🌍 Dashboard port (OPTINAL / default: 3000)
2237
2991
  });
2238
2992
  });
2239
2993
  ```
@@ -2249,15 +3003,16 @@ client.once("ready", () => {
2249
3003
 
2250
3004
  ### 📌 Dashboard Routes
2251
3005
 
2252
- | Route | Description |
2253
- |-------|-------------|
2254
- | `/` | 🏠 Homepage with bot stats |
2255
- | `/login` | 🔐 Login page |
2256
- | `/dashboard` | 📊 Server selection |
2257
- | `/dashboard/:guildId` | 🏠 Server overview |
2258
- | `/dashboard/:guildId/commands` | 📜 Commands list |
2259
- | `/dashboard/:guildId/levels` | 🏆 Level leaderboard |
2260
- | `/dashboard/:guildId/giveaways` | 🎉 Giveaway management |
3006
+ | Route | Description |
3007
+ | ------------------------------- | ---------------------------- |
3008
+ | `/` | 🏠 Homepage with bot stats |
3009
+ | `/login` | 🔐 Login page |
3010
+ | `/dashboard` | 📊 Server selection |
3011
+ | `/dashboard/:guildId` | 🏠 Server overview |
3012
+ | `/dashboard/:guildId/commands` | 📜 Commands list |
3013
+ | `/dashboard/:guildId/levels` | 🏆 Level leaderboard |
3014
+ | `/dashboard/:guildId/giveaways` | 🎉 Giveaway management |
3015
+ | `/dashboard/:guildId/logs` | 🛡️ Logging system management |
2261
3016
 
2262
3017
  ---
2263
3018
 
@@ -2290,7 +3045,13 @@ POST /api/:guildId/giveaway/end
2290
3045
  POST /api/:guildId/giveaway/reroll
2291
3046
  POST /api/:guildId/giveaway/delete
2292
3047
 
2293
- // 🚫 Blacklist management
3048
+ // �️ Logging system management
3049
+ POST /api/:guildId/logs/channel // Set default log channel
3050
+ POST /api/:guildId/logs/toggle // Enable/disable event type
3051
+ POST /api/:guildId/logs/event // Update event settings (channel, color)
3052
+ POST /api/:guildId/logs/reset // Reset all log settings
3053
+
3054
+ // �🚫 Blacklist management
2294
3055
  POST /api/guild/:guildId/blacklist // Add to blacklist
2295
3056
  DELETE /api/guild/:guildId/blacklist // Remove from blacklist
2296
3057
  ```
@@ -2304,13 +3065,12 @@ DELETE /api/guild/:guildId/blacklist // Remove from blacklist
2304
3065
 
2305
3066
  ### 🔧 Configuration Options
2306
3067
 
2307
- | Option | Type | Required | Description |
2308
- |--------|------|----------|-------------|
2309
- | `clientID` | `string` | ✅ | 🔑 Your Discord Application Client ID |
2310
- | `clientSecret` | `string` | ✅ | 🔐 Your Discord Application Client Secret |
2311
- | `callbackURL` | `string` | ✅ | 🔗 OAuth2 redirect URL (must match Discord settings) |
2312
- | `sessionSecret` | `string` | | 🔒 Secret key for session encryption |
2313
- | `port` | `number` | ❌ | 🌍 Port to run the dashboard (default: 3000) |
3068
+ | Option | Type | Required | Description |
3069
+ | --------------- | -------- | -------- | ---------------------------------------------------- |
3070
+ | `clientSecret` | `string` | ✅ | 🔐 Your Discord Application Client Secret |
3071
+ | `callbackURL` | `string` | ✅ | 🔗 OAuth2 redirect URL (must match Discord settings) |
3072
+ | `sessionSecret` | `string` | ✅ | 🔒 Secret key for session encryption |
3073
+ | `port` | `number` | | 🌍 Port to run the dashboard (default: 3000) |
2314
3074
 
2315
3075
  ---
2316
3076
 
@@ -2318,16 +3078,17 @@ DELETE /api/guild/:guildId/blacklist // Remove from blacklist
2318
3078
 
2319
3079
  The dashboard uses **EJS** templates located in the `views` folder:
2320
3080
 
2321
- | File | Description |
2322
- |------|-------------|
2323
- | `index.ejs` | 🏠 Homepage |
2324
- | `login.ejs` | 🔐 Login page |
2325
- | `dashboard.ejs` | 📊 Server selection |
2326
- | `guild.ejs` | 🏠 Server overview |
2327
- | `commands.ejs` | 📜 Commands list |
2328
- | `levels.ejs` | 🏆 Level management |
2329
- | `giveaways.ejs` | 🎉 Giveaway management |
2330
- | `404.ejs` | Not found page |
3081
+ | File | Description |
3082
+ | --------------- | ---------------------------- |
3083
+ | `index.ejs` | 🏠 Homepage |
3084
+ | `login.ejs` | 🔐 Login page |
3085
+ | `dashboard.ejs` | 📊 Server selection |
3086
+ | `guild.ejs` | 🏠 Server overview |
3087
+ | `commands.ejs` | 📜 Commands list |
3088
+ | `levels.ejs` | 🏆 Level management |
3089
+ | `giveaways.ejs` | 🎉 Giveaway management |
3090
+ | `logs.ejs` | 🛡️ Logging system management |
3091
+ | `404.ejs` | ❌ Not found page |
2331
3092
 
2332
3093
  </details>
2333
3094