djs-builder 0.7.3 → 0.7.5

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
 
@@ -393,6 +392,1057 @@ console.log(
393
392
 
394
393
  ---
395
394
 
395
+ <details>
396
+ <summary>CreateModal 🔳</summary>
397
+
398
+ **🔳 CreateModal – Easily create Discord Modals with Text Inputs, Menus, Files, and Labels ✨**
399
+
400
+ `CreateModal` is a powerful utility to build Discord **Modals**. It supports:
401
+
402
+ - **Text Inputs** 📝
403
+ - **Select Menus** 🎯 (`string`, `role`, `user`, `channel`)
404
+ - **File Uploads** 📎
405
+ - **Text Displays** 🏷️
406
+
407
+ ---
408
+
409
+ ### 📌 Example Usage:
410
+
411
+ ```js
412
+ const { CreateModal } = require("djs-builder");
413
+
414
+ const modal = CreateModal({
415
+ id: "myModal",
416
+ title: "User Information",
417
+ components: [
418
+ {
419
+ type: "textInput",
420
+ components: [
421
+ {
422
+ label: "Your Name",
423
+ id: "name",
424
+ style: 1, // 1: Short, 2: Paragraph
425
+ placeholder: "Enter your name",
426
+ required: true,
427
+ minLength: 2,
428
+ maxLength: 50,
429
+ },
430
+ ],
431
+ },
432
+ {
433
+ type: "menu",
434
+ components: {
435
+ type: "string",
436
+ options: {
437
+ id: "favoriteColor",
438
+ placeholder: "Choose your favorite color",
439
+ min: 1,
440
+ max: 1,
441
+ data: [
442
+ {
443
+ label: "Red",
444
+ value: "red",
445
+ description: "A bold color",
446
+ emoji: "🔴",
447
+ default: false,
448
+ },
449
+ {
450
+ label: "Blue",
451
+ value: "blue",
452
+ description: "A calm color",
453
+ emoji: "🔵",
454
+ },
455
+ ],
456
+ label: "label",
457
+ value: "value",
458
+ description: "description",
459
+ emoji: "emoji",
460
+ disabled: false,
461
+ },
462
+ },
463
+ },
464
+ {
465
+ type: "file",
466
+ components: {
467
+ id: "avatar",
468
+ label: "Upload Avatar",
469
+ description: "Optional avatar image",
470
+ },
471
+ },
472
+ {
473
+ type: "label",
474
+ components: {
475
+ label: "Thank you for your input!",
476
+ },
477
+ },
478
+ ],
479
+ });
480
+
481
+ // Show the modal
482
+ await interaction.showModal(modal);
483
+ ```
484
+
485
+ ---
486
+
487
+ ### 📔 Examples for Each Component Type:
488
+
489
+ #### 🔹 Text Input Example:
490
+
491
+ ```js
492
+ {
493
+ type: "textInput",
494
+ components: [
495
+ {
496
+ label: "Your Age",
497
+ id: "age",
498
+ style: 1, // Short input
499
+ placeholder: "Enter your age",
500
+ required: true,
501
+ minLength: 1,
502
+ maxLength: 3,
503
+ value: "18", // Pre-filled
504
+ },
505
+ ],
506
+ },
507
+ ```
508
+
509
+ #### 🔹 Menu Example:
510
+
511
+ ```js
512
+ {
513
+ type: "menu",
514
+ components: {
515
+ type: "string",
516
+ options: {
517
+ id: "country",
518
+ placeholder: "Select your country",
519
+ min: 1,
520
+ max: 1,
521
+ data: [
522
+ {
523
+ name: "USA",
524
+ id: "usa",
525
+ desc: "United States",
526
+ icon: "🇺🇸",
527
+ default: true, // This option is pre-selected
528
+ },
529
+ {
530
+ name: "Canada",
531
+ id: "canada",
532
+ desc: "Canada",
533
+ icon: "🇨🇦",
534
+ },
535
+ ],
536
+ label: "name", // Maps to 'name' field in data
537
+ value: "id", // Maps to 'id' field in data
538
+ description: "desc", // Maps to 'desc' field
539
+ emoji: "icon", // Maps to 'icon' field
540
+ disabled: false,
541
+ },
542
+ },
543
+ },
544
+ ```
545
+
546
+ #### 🔹 File Example:
547
+
548
+ ```js
549
+ {
550
+ type: "file",
551
+ components: {
552
+ id: "document",
553
+ label: "Upload Document",
554
+ description: "Upload a PDF or image",
555
+ },
556
+ },
557
+ ```
558
+
559
+ #### 🔹 Label Example:
560
+
561
+ ```js
562
+ {
563
+ type: "label",
564
+ components: {
565
+ label: "Please fill out the form above.",
566
+ },
567
+ },
568
+ ```
569
+
570
+ ---
571
+
572
+ ### �📖 Explanation
573
+
574
+ #### 🔹 Text Input
575
+
576
+ - `label` → Label for the input field
577
+ - `id` → customId for the input
578
+ - `style` → 1: Short, 2: Paragraph
579
+ - `placeholder` → Placeholder text
580
+ - `required` → true/false
581
+ - `minLength` / `maxLength` → Min/Max characters
582
+ - `value` → Pre-filled value
583
+
584
+ #### 🔹 Menu
585
+
586
+ Same as CreateRow select menus.
587
+
588
+ - `type` → `"string" | "user" | "role" | "channel"`
589
+ - `id` → customId for menu
590
+ - `placeholder` → Text shown before selection
591
+ - `min` / `max` → Min/Max selectable values
592
+ - `data` → Options array (for string select only)
593
+
594
+ - `label` → Visible text (maps to the field specified in `label` key)
595
+ - `value` → Internal value (maps to the field specified in `value` key)
596
+ - `description` → Short description (maps to the field specified in `description` key)
597
+ - `emoji` → Option emoji (maps to the field specified in `emoji` key)
598
+ - `default` → Pre-selected option (true/false in data array)
599
+
600
+ - `label` → Key in data to use as label (e.g., "name")
601
+ - `value` → Key in data to use as value (e.g., "id")
602
+ - `description` → Key in data to use as description (e.g., "desc")
603
+ - `emoji` → Key in data to use as emoji (e.g., "icon")
604
+ - `disabled` → Disable menu completely
605
+ - `defaultValues` → Pre-selected user/role/channel options (for non-string menus)
606
+ - `channelTypes` → Restrict selectable channel types (for channel menu)
607
+
608
+ #### 🔹 File
609
+
610
+ - `id` → customId for the file upload
611
+ - `label` → Label
612
+ - `description` → Description
613
+
614
+ #### 🔹 Label
615
+
616
+ - `label` → Text to display
617
+
618
+ ---
619
+
620
+ ### 🔹 Notes
621
+
622
+ - Supports multiple components in one modal
623
+ - Fully customizable with Discord.js ModalBuilder
624
+
625
+ </details>
626
+
627
+ ---
628
+
629
+ <details>
630
+ <summary>CreateComponents 🧩</summary>
631
+
632
+ **🧩 CreateComponents – Build Advanced Discord UI Components with Containers, Sections & Media ✨**
633
+
634
+ `CreateComponents` is a powerful utility to build Discord's **new UI components**. It supports:
635
+
636
+ - **Text Displays** 📝
637
+ - **Separators** ➖
638
+ - **Media Galleries** 🖼️
639
+ - **File Attachments** 📎
640
+ - **Buttons** 🔘
641
+ - **Select Menus** 🎯 (`string`, `role`, `user`, `channel`)
642
+ - **Sections with Accessories** 📦 (Thumbnails & Buttons)
643
+ - **Containers** 📦 (Group all components together)
644
+
645
+ ---
646
+
647
+ ### 📌 Example Usage (Array Mode):
648
+
649
+ ```js
650
+ const { CreateComponents } = require("djs-builder");
651
+
652
+ const components = await CreateComponents("array", [
653
+ {
654
+ type: "text",
655
+ content: "Welcome to our server! 🎉",
656
+ },
657
+ {
658
+ type: "separator",
659
+ divider: true,
660
+ spacing: 1, // 1: Small, 2: Large
661
+ },
662
+ {
663
+ type: "media",
664
+ links: [
665
+ "https://example.com/image1.png",
666
+ {
667
+ url: "https://example.com/image2.png",
668
+ description: "A cool image",
669
+ spoiler: true,
670
+ },
671
+ ],
672
+ },
673
+ {
674
+ type: "button",
675
+ components: [
676
+ {
677
+ id: "btn_1",
678
+ style: 1, // 1: Primary, 2: Secondary, 3: Success, 4: Danger, 5: Link
679
+ label: "Click Me!",
680
+ emoji: "🚀",
681
+ },
682
+ {
683
+ id: "btn_2",
684
+ style: 3,
685
+ label: "Confirm",
686
+ },
687
+ ],
688
+ },
689
+ ]);
690
+
691
+ // Send the components
692
+ await channel.send({ components });
693
+ ```
694
+
695
+ ---
696
+
697
+ ### 📌 Example Usage (Container Mode):
698
+
699
+ ```js
700
+ const { CreateComponents } = require("djs-builder");
701
+
702
+ const components = await CreateComponents("container", [
703
+ {
704
+ type: "text",
705
+ content: "# 📢 Server Announcement\nWelcome everyone!",
706
+ },
707
+ {
708
+ type: "separator",
709
+ divider: true,
710
+ },
711
+ {
712
+ type: "section",
713
+ content: "Check out our latest updates and news!",
714
+ accessory: {
715
+ type: "thumbnail",
716
+ url: "https://example.com/thumbnail.png",
717
+ description: "News Image",
718
+ },
719
+ },
720
+ {
721
+ type: "section",
722
+ content: "**Click below to get your roles!**",
723
+ accessory: {
724
+ type: "button",
725
+ id: "get_roles",
726
+ style: 1,
727
+ label: "Get Roles",
728
+ emoji: "🎭",
729
+ },
730
+ },
731
+ {
732
+ type: "media",
733
+ links: ["https://example.com/banner.png"],
734
+ },
735
+ {
736
+ type: "button",
737
+ components: [
738
+ { id: "rules", style: 2, label: "📜 Rules", emoji: "📜" },
739
+ { id: "help", style: 2, label: "❓ Help", emoji: "❓" },
740
+ { style: 5, label: "🌐 Website", url: "https://example.com" },
741
+ ],
742
+ },
743
+ ]);
744
+
745
+ // Send with container
746
+ await channel.send({ components, flags: 32768 }); // flags for components v2
747
+ ```
748
+
749
+ ---
750
+
751
+ ### 📜 Examples for Each Component Type:
752
+
753
+ ---
754
+
755
+ <details>
756
+ <summary>🔹 Text Component Examples</summary>
757
+
758
+ #### 📌 Simple Text:
759
+
760
+ ```js
761
+ {
762
+ type: "text",
763
+ content: "Hello World! 👋",
764
+ }
765
+ ```
766
+
767
+ #### 📌 Text with Markdown:
768
+
769
+ ```js
770
+ {
771
+ type: "text",
772
+ content: "# 📢 Announcement\n**Important:** Server maintenance tonight!",
773
+ }
774
+ ```
775
+
776
+ #### 📌 Text with Multiple Lines:
777
+
778
+ ```js
779
+ {
780
+ type: "text",
781
+ content: `## 🎮 Game Stats
782
+
783
+ **Player:** Ahmed
784
+ **Level:** 50
785
+ **XP:** 12,500 / 15,000
786
+ **Rank:** Diamond 💎`,
787
+ }
788
+ ```
789
+
790
+ #### 📌 Text with Emojis & Formatting:
791
+
792
+ ```js
793
+ {
794
+ type: "text",
795
+ content: ">>> 💡 **Tip:** Use `/help` to see all commands!\n\n*This message will auto-delete in 30 seconds*",
796
+ }
797
+ ```
798
+
799
+ </details>
800
+
801
+ ---
802
+
803
+ <details>
804
+ <summary>➖ Separator Component Examples</summary>
805
+
806
+ **➖ Separator – Add spacing and dividers between components**
807
+
808
+ The separator component allows you to add visual breaks between other components with customizable spacing and divider lines.
809
+
810
+ ---
811
+
812
+ ### 📖 Separator Options
813
+
814
+ | Option | Type | Default | Description |
815
+ | --------- | --------- | ------- | -------------------------------------------------- |
816
+ | `type` | `string` | — | Must be `"separator"` |
817
+ | `divider` | `boolean` | `false` | Show a horizontal dividing line |
818
+ | `spacing` | `number` | `1` | Spacing size: `1` (Small) or `2` (Large) |
819
+
820
+ ---
821
+
822
+ #### 📌 Simple Divider Line:
823
+
824
+ ```js
825
+ {
826
+ type: "separator",
827
+ divider: true,
828
+ }
829
+ ```
830
+ **Result:** A thin horizontal line appears between components.
831
+
832
+ ---
833
+
834
+ #### 📌 Separator without Line (Spacing Only):
835
+
836
+ ```js
837
+ {
838
+ type: "separator",
839
+ divider: false,
840
+ spacing: 2, // Large spacing
841
+ }
842
+ ```
843
+ **Result:** Empty space without any visible line - useful for visual grouping.
844
+
845
+ ---
846
+
847
+ #### 📌 Small Spacing with Divider:
848
+
849
+ ```js
850
+ {
851
+ type: "separator",
852
+ divider: true,
853
+ spacing: 1, // Small spacing (default)
854
+ }
855
+ ```
856
+ **Result:** A divider line with minimal padding above and below.
857
+
858
+ ---
859
+
860
+ #### 📌 Large Spacing with Divider:
861
+
862
+ ```js
863
+ {
864
+ type: "separator",
865
+ divider: true,
866
+ spacing: 2, // Large spacing
867
+ }
868
+ ```
869
+ **Result:** A divider line with more padding - creates stronger visual separation.
870
+
871
+ ---
872
+
873
+ ### 💡 When to Use Each Option:
874
+
875
+ | Scenario | `divider` | `spacing` |
876
+ | ------------------------------------- | --------- | --------- |
877
+ | Separate major sections | `true` | `2` |
878
+ | Separate sub-sections | `true` | `1` |
879
+ | Group related items visually | `false` | `1` |
880
+ | Create breathing room between content | `false` | `2` |
881
+ | Minimal separation | `false` | `1` |
882
+
883
+ </details>
884
+
885
+ ---
886
+
887
+ <details>
888
+ <summary>🖼️ Media Gallery Examples</summary>
889
+
890
+ **🖼️ Media Gallery – Display images in a beautiful gallery format**
891
+
892
+ The media component creates an image gallery that can display one or multiple images. Each image can be a simple URL string or a detailed object with additional options.
893
+
894
+
895
+ ---
896
+
897
+ ### 📌 Format 1: Simple String URLs
898
+
899
+ The simplest way - just pass image URLs as strings:
900
+
901
+ ```js
902
+ {
903
+ type: "media",
904
+ links: ["https://example.com/image.png"],
905
+ }
906
+ ```
907
+
908
+ ---
909
+
910
+ ### 📌 Format 2: Object with Full Options
911
+
912
+ For more control, use objects with url, description, and spoiler:
913
+
914
+ ```js
915
+ {
916
+ type: "media",
917
+ links: [
918
+ {
919
+ url: "https://example.com/image.png",
920
+ description: "A beautiful sunset",
921
+ spoiler: false,
922
+ },
923
+ ],
924
+ }
925
+ ```
926
+
927
+ ---
928
+
929
+ ### 📌 Single Image with Spoiler:
930
+
931
+ ```js
932
+ {
933
+ type: "media",
934
+ links: [
935
+ {
936
+ url: "https://example.com/spoiler.png",
937
+ description: "⚠️ Spoiler Alert!",
938
+ spoiler: true,
939
+ },
940
+ ],
941
+ }
942
+ ```
943
+
944
+ ---
945
+
946
+ ### 📌 Multiple Images (Simple Strings):
947
+
948
+ ```js
949
+ {
950
+ type: "media",
951
+ links: [
952
+ "https://example.com/image1.png",
953
+ "https://example.com/image2.png",
954
+ "https://example.com/image3.png",
955
+ "https://example.com/image4.png",
956
+ ],
957
+ }
958
+ ```
959
+ **Result:** A 2x2 gallery grid of images.
960
+
961
+ ---
962
+
963
+ ### 📌 Mixed Format (Strings + Objects):
964
+
965
+ You can mix simple strings with detailed objects in the same array:
966
+
967
+ ```js
968
+ {
969
+ type: "media",
970
+ links: [
971
+ // Simple string - just the URL
972
+ "https://example.com/public-image.png",
973
+
974
+ // Object with description
975
+ {
976
+ url: "https://example.com/special-image.png",
977
+ description: "Limited Edition Art",
978
+ },
979
+
980
+ // Object with spoiler
981
+ {
982
+ url: "https://example.com/secret-image.png",
983
+ description: "Secret Content",
984
+ spoiler: true,
985
+ },
986
+
987
+ // Another simple string
988
+ "https://example.com/another-image.png",
989
+ ],
990
+ }
991
+ ```
992
+
993
+ ---
994
+
995
+ ### 📌 Meme/Artwork Gallery with Spoilers:
996
+
997
+ ```js
998
+ {
999
+ type: "media",
1000
+ links: [
1001
+ {
1002
+ url: "https://example.com/meme1.png",
1003
+ description: "Funny meme #1",
1004
+ spoiler: false,
1005
+ },
1006
+ {
1007
+ url: "https://example.com/meme2.png",
1008
+ description: "Funny meme #2",
1009
+ spoiler: false,
1010
+ },
1011
+ {
1012
+ url: "https://example.com/nsfw-meme.png",
1013
+ description: "⚠️ Slightly inappropriate",
1014
+ spoiler: true, // Hidden behind blur
1015
+ },
1016
+ ],
1017
+ }
1018
+ ```
1019
+
1020
+ ---
1021
+
1022
+ ### 💡 Tips for Media Galleries:
1023
+
1024
+ | Images Count | Display Layout |
1025
+ | ------------ | ---------------------- |
1026
+ | 1 image | Full width single image |
1027
+ | 2 images | Side by side |
1028
+ | 3 images | 1 large + 2 small |
1029
+ | 4+ images | Grid layout |
1030
+
1031
+ - Use `description` for accessibility and context
1032
+ - Use `spoiler: true` for sensitive/spoiler content
1033
+ - Mix formats freely - strings for quick images, objects for detailed ones
1034
+ - Images are displayed in the order provided
1035
+
1036
+ </details>
1037
+
1038
+ ---
1039
+
1040
+ <details>
1041
+ <summary>📎 File Component Examples</summary>
1042
+
1043
+ #### 📌 Simple File Attachment:
1044
+
1045
+ ```js
1046
+ {
1047
+ type: "file",
1048
+ url: "attachment://document.pdf",
1049
+ }
1050
+ ```
1051
+
1052
+
1053
+
1054
+ #### 📌 Full Example with File:
1055
+
1056
+ ```js
1057
+ const { CreateComponents } = require("djs-builder");
1058
+ const { AttachmentBuilder } = require("discord.js");
1059
+
1060
+ const file = new AttachmentBuilder("./myfile.txt", { name: "myfile.txt" });
1061
+
1062
+ const components = await CreateComponents("container", [
1063
+ {
1064
+ type: "text",
1065
+ content: "📄 **Here is your requested file:**",
1066
+ },
1067
+ {
1068
+ type: "file",
1069
+ url: "attachment://myfile.txt",
1070
+ },
1071
+ ]);
1072
+
1073
+ await channel.send({ components, files: [file], flags: 32768 });
1074
+ ```
1075
+
1076
+ </details>
1077
+
1078
+ ---
1079
+
1080
+ <details>
1081
+ <summary>🔘 Button Component Examples</summary>
1082
+
1083
+ #### 📌 Button with Emoji:
1084
+
1085
+ ```js
1086
+ {
1087
+ type: "button",
1088
+ components: [
1089
+ {
1090
+ id: "like_btn",
1091
+ style: 3, // Success (Green)
1092
+ label: "Like",
1093
+ emoji: "👍",
1094
+ },
1095
+ ],
1096
+ }
1097
+ ```
1098
+
1099
+ #### 📌 Multiple Buttons in Row:
1100
+
1101
+ ```js
1102
+ {
1103
+ type: "button",
1104
+ components: [
1105
+ { id: "btn_yes", style: 3, label: "Yes", emoji: "✅" },
1106
+ { id: "btn_no", style: 4, label: "No", emoji: "❌" },
1107
+ { id: "btn_maybe", style: 2, label: "Maybe", emoji: "🤔" },
1108
+ ],
1109
+ }
1110
+ ```
1111
+
1112
+ #### 📌 All Button Styles:
1113
+
1114
+ ```js
1115
+ {
1116
+ type: "button",
1117
+ components: [
1118
+ { id: "primary", style: 1, label: "Primary", emoji: "🔵" }, // Blue
1119
+ { id: "secondary", style: 2, label: "Secondary", emoji: "⚪" }, // Gray
1120
+ { id: "success", style: 3, label: "Success", emoji: "🟢" }, // Green
1121
+ { id: "danger", style: 4, label: "Danger", emoji: "🔴" }, // Red
1122
+ { style: 5, label: "Link", emoji: "🔗", url: "https://discord.com" }, // Link
1123
+ ],
1124
+ }
1125
+ ```
1126
+
1127
+
1128
+ </details>
1129
+
1130
+ ---
1131
+
1132
+ <details>
1133
+ <summary>🎯 Menu Component Examples</summary>
1134
+
1135
+ #### 📌 String Select Menu (Basic):
1136
+
1137
+ ```js
1138
+ {
1139
+ type: "menu",
1140
+ components: {
1141
+ type: "string",
1142
+ options: {
1143
+ id: "color_select",
1144
+ placeholder: "🎨 Choose a color",
1145
+ data: [
1146
+ { name: "Red", id: "red", icon: "🔴" },
1147
+ { name: "Blue", id: "blue", icon: "🔵" },
1148
+ { name: "Green", id: "green", icon: "🟢" },
1149
+ ],
1150
+ label: "name",
1151
+ value: "id",
1152
+ emoji: "icon",
1153
+ },
1154
+ },
1155
+ }
1156
+ ```
1157
+
1158
+ #### 📌 String Select with Description:
1159
+
1160
+ ```js
1161
+ {
1162
+ type: "menu",
1163
+ components: {
1164
+ type: "string",
1165
+ options: {
1166
+ id: "role_select",
1167
+ placeholder: "🎭 Select your role",
1168
+ data: [
1169
+ { name: "Gamer", id: "gamer", desc: "For gaming enthusiasts", icon: "🎮" },
1170
+ { name: "Artist", id: "artist", desc: "For creative people", icon: "🎨" },
1171
+ { name: "Developer", id: "dev", desc: "For coders & programmers", icon: "💻" },
1172
+ { name: "Music Lover", id: "music", desc: "For music fans", icon: "🎵" },
1173
+ ],
1174
+ label: "name",
1175
+ value: "id",
1176
+ description: "desc",
1177
+ emoji: "icon",
1178
+ },
1179
+ },
1180
+ }
1181
+ ```
1182
+
1183
+ #### 📌 String Select with Min/Max:
1184
+
1185
+ ```js
1186
+ {
1187
+ type: "menu",
1188
+ components: {
1189
+ type: "string",
1190
+ options: {
1191
+ id: "games_select",
1192
+ placeholder: "🎮 Select your favorite games (2-4)",
1193
+ min: 2,
1194
+ max: 4,
1195
+ data: [
1196
+ { name: "Minecraft", id: "mc", icon: "⛏️" },
1197
+ { name: "Fortnite", id: "fn", icon: "🔫" },
1198
+ { name: "Valorant", id: "val", icon: "🎯" },
1199
+ { name: "League of Legends", id: "lol", icon: "⚔️" },
1200
+ { name: "Rocket League", id: "rl", icon: "🚗" },
1201
+ ],
1202
+ label: "name",
1203
+ value: "id",
1204
+ emoji: "icon",
1205
+ },
1206
+ },
1207
+ }
1208
+ ```
1209
+
1210
+
1211
+ #### 📌 User Select (Multiple):
1212
+
1213
+ ```js
1214
+ {
1215
+ type: "menu",
1216
+ components: {
1217
+ type: "user",
1218
+ options: {
1219
+ id: "users_select",
1220
+ placeholder: "👥 Select users to invite (1-5)",
1221
+ min: 1,
1222
+ max: 5,
1223
+ },
1224
+ },
1225
+ }
1226
+ ```
1227
+
1228
+ #### 📌 Role Select Menu:
1229
+
1230
+ ```js
1231
+ {
1232
+ type: "menu",
1233
+ components: {
1234
+ type: "role",
1235
+ options: {
1236
+ id: "role_select",
1237
+ placeholder: "🎭 Select a role",
1238
+ min: 1,
1239
+ max: 1,
1240
+ },
1241
+ },
1242
+ }
1243
+ ```
1244
+
1245
+
1246
+ #### 📌 Channel Select Menu:
1247
+
1248
+ ```js
1249
+ {
1250
+ type: "menu",
1251
+ components: {
1252
+ type: "channel",
1253
+ options: {
1254
+ id: "channel_select",
1255
+ placeholder: "📢 Select a channel",
1256
+ min: 1,
1257
+ max: 1,
1258
+ },
1259
+ },
1260
+ }
1261
+ ```
1262
+
1263
+ #### 📌 Channel Select with Type Filter:
1264
+
1265
+ ```js
1266
+ const { ChannelType } = require("discord.js");
1267
+
1268
+ {
1269
+ type: "menu",
1270
+ components: {
1271
+ type: "channel",
1272
+ options: {
1273
+ id: "text_channel_select",
1274
+ placeholder: "💬 Select a text channel",
1275
+ channelTypes: [ChannelType.GuildText, ChannelType.GuildAnnouncement],
1276
+ },
1277
+ },
1278
+ }
1279
+ ```
1280
+
1281
+ #### 📌 Menu with Default Values (User/Role/Channel):
1282
+
1283
+ ```js
1284
+ {
1285
+ type: "menu",
1286
+ components: {
1287
+ type: "user",
1288
+ options: {
1289
+ id: "user_select_default",
1290
+ placeholder: "👤 Select users",
1291
+ min: 1,
1292
+ max: 3,
1293
+ defaultValues: [
1294
+ { id: "123456789012345678", type: "user" },
1295
+ { id: "987654321098765432", type: "user" },
1296
+ ],
1297
+ },
1298
+ },
1299
+ }
1300
+ ```
1301
+
1302
+ </details>
1303
+
1304
+ ---
1305
+
1306
+ <details>
1307
+ <summary>📦 Section Component Examples</summary>
1308
+
1309
+
1310
+ #### 📌 Section with Thumbnail (Product):
1311
+
1312
+ ```js
1313
+ {
1314
+ type: "section",
1315
+ content: "🛒 **iPhone 15 Pro**\n💰 Price: $999\n⭐ Rating: 4.8/5\n📦 In Stock: Yes",
1316
+ accessory: {
1317
+ type: "thumbnail",
1318
+ url: "https://example.com/iphone.png",
1319
+ description: "iPhone 15 Pro Image",
1320
+ },
1321
+ }
1322
+ ```
1323
+
1324
+ #### 📌 Section with Button :
1325
+
1326
+ ```js
1327
+ {
1328
+ type: "section",
1329
+ content: "🎁 **Daily Reward**\nClick to claim your daily reward!\n💎 **+100 Coins**",
1330
+ accessory: {
1331
+ type: "button",
1332
+ id: "claim_daily",
1333
+ style: 3,
1334
+ label: "Claim",
1335
+ emoji: "🎁",
1336
+ },
1337
+ }
1338
+ ```
1339
+
1340
+
1341
+
1342
+
1343
+ </details>
1344
+
1345
+ ---
1346
+
1347
+
1348
+ ### 📖 Component Types Explanation
1349
+
1350
+ #### 🔹 Text
1351
+
1352
+ - `type` → `"text"`
1353
+ - `content` → The text content to display (supports Markdown)
1354
+
1355
+ #### 🔹 Separator
1356
+
1357
+ - `type` → `"separator"`
1358
+ - `divider` → Show a dividing line (true/false)
1359
+ - `spacing` → Spacing size (1: Small, 2: Large)
1360
+
1361
+ #### 🔹 Media Gallery
1362
+
1363
+ - `type` → `"media"`
1364
+ - `links` → Array of image URLs or objects with:
1365
+ - `url` → Image URL
1366
+ - `description` → Alt text for the image
1367
+ - `spoiler` → Hide behind spoiler (true/false)
1368
+
1369
+ #### 🔹 File
1370
+
1371
+ - `type` → `"file"`
1372
+ - `url` → File URL or attachment reference
1373
+ - `spoiler` → Hide behind spoiler (true/false)
1374
+
1375
+ #### 🔹 Button
1376
+
1377
+ - `type` → `"button"`
1378
+ - `components` → Array of button objects:
1379
+ - `id` → customId (required for non-link buttons)
1380
+ - `style` → 1: Primary, 2: Secondary, 3: Success, 4: Danger, 5: Link
1381
+ - `label` → Button text
1382
+ - `emoji` → Button emoji
1383
+ - `disabled` → Disable button (true/false)
1384
+ - `url` → URL for link buttons (style: 5)
1385
+
1386
+ #### 🔹 Menu
1387
+
1388
+ - `type` → `"menu"`
1389
+ - `components` → Object containing:
1390
+ - `type` → `"string" | "user" | "role" | "channel"`
1391
+ - `options` → Menu configuration:
1392
+ - `id` → customId
1393
+ - `placeholder` → Placeholder text
1394
+ - `min` / `max` → Min/Max selectable values
1395
+ - `data` → Options array (for string select)
1396
+ - `label` → Key in data for label
1397
+ - `value` → Key in data for value
1398
+ - `emoji` → Key in data for emoji
1399
+ - `description` → Key in data for description
1400
+ - `channelTypes` → Channel types filter (for channel menu)
1401
+ - `defaultValues` → Pre-selected values
1402
+
1403
+ #### 🔹 Section
1404
+
1405
+ - `type` → `"section"`
1406
+ - `content` → Text content for the section
1407
+ - `accessory` → Side component:
1408
+ - **Button Accessory:**
1409
+ - `type` → `"button"`
1410
+ - `id` → customId
1411
+ - `style` → Button style
1412
+ - `label` → Button text
1413
+ - `emoji` → Button emoji
1414
+ - `url` → URL (for link buttons)
1415
+ - **Thumbnail Accessory:**
1416
+ - `type` → `"thumbnail"`
1417
+ - `url` → Image URL
1418
+ - `description` → Image description
1419
+
1420
+ ---
1421
+
1422
+ ### 🔹 Mode Differences
1423
+
1424
+ | Feature | `"array"` Mode | `"container"` Mode |
1425
+ | ---------------- | ----------------------- | ------------------------- |
1426
+ | Return Type | Array of components | Single ContainerBuilder |
1427
+ | Usage | Standard messages | Components V2 messages |
1428
+ | Sections Support | ✅ | ✅ |
1429
+ | Grouping | Individual components | All grouped in container |
1430
+ | Flags Required | ❌ | ✅ (flags: 32768) |
1431
+
1432
+ ---
1433
+
1434
+ ### 🔹 Notes
1435
+
1436
+ - Use `"container"` mode for Discord's **Components V2** (newer UI)
1437
+ - Use `"array"` mode for standard component arrays
1438
+ - Sections can have either a **button** or **thumbnail** as accessory, not both
1439
+ - Media galleries support multiple images in a single component
1440
+ - All components are fully customizable 🎨
1441
+
1442
+ </details>
1443
+
1444
+ ---
1445
+
396
1446
  <details>
397
1447
  <summary>Wait ⏰</summary>
398
1448
 
@@ -412,148 +1462,811 @@ console.log(
412
1462
  ```js
413
1463
  const { Wait } = require("djs-builder");
414
1464
 
415
- const response = await Wait({
416
- context: message, // Message or Interaction object
417
- userId: message.author.id, // Optional: filter by user
418
- type: "both", // "message" | "interaction" | "both"
419
- time: 30000, // Time in ms
420
- message_Wait: message, // Required if waiting for buttons/selects
421
- });
1465
+ const response = await Wait({
1466
+ context: message, // Message or Interaction object
1467
+ userId: message.author.id, // Optional: filter by user
1468
+ type: "both", // "message" | "interaction" | "both"
1469
+ time: 30000, // Time in ms
1470
+ message_Wait: message, // Required if waiting for buttons/selects
1471
+ });
1472
+
1473
+ if (!response) return console.log("⏱️ Timeout!");
1474
+ console.log("✅ Collected:", response);
1475
+ ```
1476
+
1477
+ ---
1478
+
1479
+ ### 🔹 Options
1480
+
1481
+ - `context` → The message or interaction context
1482
+ - `userId` → Only collect from this user (optional)
1483
+ - `type` → `"message" | "interaction" | "both"`
1484
+ - `time` → Timeout in milliseconds
1485
+ - `message_Wait` → Message containing buttons/select menus (for interaction/both type)
1486
+
1487
+ ---
1488
+
1489
+ ### 🔹 Notes
1490
+
1491
+ - Supports **automatic cleanup** of collectors after completion
1492
+ - Can return **Message**, **Interaction**, or **ModalSubmitInteraction**
1493
+
1494
+ </details>
1495
+
1496
+ ---
1497
+
1498
+ <details>
1499
+ <summary>GetUser 👤</summary>
1500
+
1501
+ **👤 GetUser – Fetch a GuildMember easily from a message ✨**
1502
+
1503
+ `GetUser` helps to detect a **target member** in multiple ways:
1504
+
1505
+ 1. Mention (`@User`)
1506
+ 2. User ID (`123456789012345678`)
1507
+ 3. Reply to another message
1508
+
1509
+ ---
1510
+
1511
+ ### 📌 Example Usage:
1512
+
1513
+ ```js
1514
+ const { GetUser } = require("djs-builder");
1515
+
1516
+ const data = await GetUser(message);
1517
+
1518
+ if (!data) return message.reply("❌ Could not find the user.");
1519
+
1520
+ const member = data.user; // GuildMember object
1521
+ const args = data.args; // Remaining arguments
1522
+ const reason = args.join(" ") || "No reason provided";
1523
+
1524
+ await member.ban({ reason });
1525
+ message.reply(`🚫 ${member.user.tag} was banned for: ${reason}`);
1526
+ ```
1527
+
1528
+ ---
1529
+
1530
+ ### 🔹 Returns
1531
+
1532
+ ```js
1533
+ {
1534
+ user: <GuildMember>, // Targeted member
1535
+ args: [ "arg1", "arg2" ] // Remaining message arguments
1536
+ }
1537
+ ```
1538
+
1539
+ ---
1540
+
1541
+ ### 🔹 Detection Methods
1542
+
1543
+ - **Mention:** `!ban @Ahmed Spamming`
1544
+ - **User ID:** `!ban 123456789012345678 Spamming`
1545
+ - **Reply:** `Reply to user's message with !ban`
1546
+
1547
+ ---
1548
+
1549
+ ### 🔹 Notes
1550
+
1551
+ - Automatically handles missing users
1552
+ - Returns `null` if user not found
1553
+ - Works in any text channel of the guild
1554
+
1555
+ </details>
1556
+
1557
+ ---
1558
+
1559
+ <details>
1560
+ <summary>Logging System 🛡️</summary>
1561
+
1562
+ ## 🛡️ Logging System – Track Everything in Your Server
1563
+
1564
+ The **Logging System** is a powerful feature that keeps track of almost everything happening inside your Discord server 🔍.
1565
+ From **messages** 📝 to **channels** 📂, **roles** 🎭, **invites** 🔗, and even **voice state changes** 🎙️ – nothing goes unnoticed!
1566
+
1567
+ > **Note 1**: Using `database: true` requires a **MongoDB** connection. | **Note 2**: You can import the **Log** model for direct database access 💾.
1568
+
1569
+ ---
1570
+
1571
+ ### 📦 Module Exports
1572
+
1573
+ ```js
1574
+ const { log, Log } = require("djs-builder");
1575
+ ```
1576
+
1577
+ - `log(client, options)` → Start the logging system with your configuration 🚀.
1578
+ - `Log` → The Mongoose model for direct database access and custom modifications 💾.
1579
+
1580
+ ---
1581
+
1582
+ ### ✨ Features
1583
+
1584
+ - 📝 **Messages** – Deleted & edited messages are logged with details.
1585
+ - 📂 **Channels** – Creation, deletion, and updates are tracked.
1586
+ - 🎭 **Roles** – Created, deleted, and updated roles, including member role changes.
1587
+ - 🎙️ **Voice State** – Joins, leaves, and moves between channels.
1588
+ - 🔗 **Invites** – Created invites & usage tracking.
1589
+ - 😀 **Emojis & Stickers** – Added, removed, or updated.
1590
+ - 👤 **Members** – Join, leave, kick, ban, and unban events.
1591
+ - 🚨 **Audit Log Integration** – Fetches the executor (who did what).
1592
+ - 🎨 **Beautiful Embeds** – Every log is shown in a clean, styled embed with timestamps.
1593
+ - 🗄️ **Caching System** – Fast performance with built-in data caching.
1594
+
1595
+ ---
1596
+
1597
+ ### 📊 Database Schema
1598
+
1599
+ The logging system uses the following data structure:
1600
+
1601
+ ```js
1602
+ {
1603
+ guildId: String, // 🏠 Server ID (required)
1604
+ channelId: String, // 📢 Default log channel ID
1605
+ channels: Object, // 📂 Custom channels per event type (optional)
1606
+ colors: Object, // 🎨 Custom colors per event type (optional)
1607
+ disable: Array, // 🚫 Array of disabled event types (optional)
1608
+ }
1609
+ ```
1610
+
1611
+ ---
1612
+
1613
+ <details>
1614
+ <summary>📋 Supported Event Types</summary>
1615
+
1616
+ ### 📋 Supported Event Types
1617
+
1618
+ | Event Type | Description |
1619
+ | ------------------- | ------------------------- |
1620
+ | `messageDelete` | Message deleted 📝 |
1621
+ | `messageUpdate` | Message edited ✏️ |
1622
+ | `channelCreate` | Channel created 📁 |
1623
+ | `channelDelete` | Channel deleted 🗑️ |
1624
+ | `channelUpdate` | Channel updated ⚙️ |
1625
+ | `guildMemberAdd` | Member joined 🎉 |
1626
+ | `guildMemberRemove` | Member left/kicked 🚪 |
1627
+ | `guildBanAdd` | Member banned 🔨 |
1628
+ | `guildBanRemove` | Member unbanned 🤗 |
1629
+ | `roleCreate` | Role created 🏅 |
1630
+ | `roleDelete` | Role deleted ❌ |
1631
+ | `roleUpdate` | Role updated 🔄 |
1632
+ | `guildMemberUpdate` | Member roles changed 👤 |
1633
+ | `voiceStateUpdate` | Voice channel activity 🎤 |
1634
+ | `inviteCreate` | Invite created 🔗 |
1635
+ | `emojiCreate` | Emoji added 😀 |
1636
+ | `emojiDelete` | Emoji removed 🚫 |
1637
+ | `emojiUpdate` | Emoji updated 🔄 |
1638
+ | `stickerCreate` | Sticker added ✨ |
1639
+ | `stickerDelete` | Sticker removed 🗑️ |
1640
+ | `stickerUpdate` | Sticker updated 🌀 |
1641
+
1642
+ </details>
1643
+
1644
+ ---
1645
+
1646
+ <details>
1647
+ <summary>⚡ Method Using Database (Recommended) 🗄️</summary>
1648
+
1649
+ ### 🗄️ Using MongoDB Database
1650
+
1651
+ This method stores log configuration in MongoDB, allowing dynamic management via commands.
1652
+
1653
+ **⚡ Setup in `clientReady` Event:**
1654
+
1655
+ ```js
1656
+ const { log } = require("djs-builder");
1657
+
1658
+ module.exports = {
1659
+ name: "clientReady",
1660
+ async run(client) {
1661
+ // Start logging with database mode
1662
+ await log(client, {
1663
+ database: true, // 🗄️ Uses MongoDB to store/fetch config
1664
+ });
1665
+
1666
+ console.log("✅ Logging system started with database mode!");
1667
+ },
1668
+ };
1669
+ ```
1670
+
1671
+ ---
1672
+
1673
+ ### 💡 How It Works
1674
+
1675
+ - ✅ The system automatically fetches log configuration for each guild from MongoDB.
1676
+ - 🛠️ You can manage settings via slash commands (see management command below).
1677
+ - 🎨 Supports per-guild customization for channels, colors, and disabled events.
1678
+ - 📖 **Important**: If you use database mode, see the [Log Management Command](#-slash-command-for-log-management-) below to edit data.
1679
+
1680
+ </details>
1681
+
1682
+ ---
1683
+
1684
+ <details>
1685
+ <summary>⚡ Method Using Custom Data Array 📋</summary>
1686
+
1687
+ ### 📋 Using Custom Data Array
1688
+
1689
+ This method uses a predefined array of configurations – perfect for simple setups or testing.
1690
+
1691
+ **⚡ Setup in `clientReady` Event:**
1692
+
1693
+ ```js
1694
+ const { log } = require("djs-builder");
1695
+
1696
+ module.exports = {
1697
+ name: "clientReady",
1698
+ async run(client) {
1699
+ // Define your log configurations
1700
+ const logData = [
1701
+ {
1702
+ guildId: "123456789012345678", // 🏠 Server ID
1703
+ channelId: "987654321098765432", // 📢 Default log channel
1704
+ channels: {
1705
+ // 📂 Custom channels (optional)
1706
+ messageDelete: "111111111111111111",
1707
+ voiceStateUpdate: "222222222222222222",
1708
+ },
1709
+ colors: {
1710
+ // 🎨 Custom colors (optional)
1711
+ messageDelete: "DarkRed",
1712
+ channelCreate: "DarkGreen",
1713
+ },
1714
+ disable: ["inviteCreate"], // 🚫 Disabled events (optional)
1715
+ },
1716
+ // Add more guild configurations...
1717
+ {
1718
+ guildId: "999888777666555444",
1719
+ channelId: "444555666777888999",
1720
+ },
1721
+ ];
1722
+
1723
+ // Start logging with custom data
1724
+ await log(client, {
1725
+ database: false, // 📋 Uses custom array
1726
+ Data: logData, // 📊 Your configurations
1727
+ });
422
1728
 
423
- if (!response) return console.log("⏱️ Timeout!");
424
- console.log("✅ Collected:", response);
1729
+ console.log(" Logging system started with custom data!");
1730
+ },
1731
+ };
425
1732
  ```
426
1733
 
427
1734
  ---
428
1735
 
429
- ### 🔹 Options
1736
+ ### 🎨 Supported Colors
430
1737
 
431
- - `context` The message or interaction context
432
- - `userId` → Only collect from this user (optional)
433
- - `type` → `"message" | "interaction" | "both"`
434
- - `time` → Timeout in milliseconds
435
- - `message_Wait` → Message containing buttons/select menus (for interaction/both type)
1738
+ `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`.
436
1739
 
437
1740
  ---
438
1741
 
439
- ### 🔹 Notes
1742
+ ### 🌐 Multi-Guild Support
440
1743
 
441
- - Supports **automatic cleanup** of collectors after completion
442
- - Can return **Message**, **Interaction**, or **ModalSubmitInteraction**
1744
+ > 💡 **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!
443
1745
 
444
1746
  </details>
445
1747
 
446
1748
  ---
447
1749
 
448
1750
  <details>
449
- <summary>GetUser 👤</summary>
1751
+ <summary>🔧 Direct Database Access with Log Model 💾</summary>
450
1752
 
451
- **👤 GetUser Fetch a GuildMember easily from a message ✨**
1753
+ ### 💾 Using the Log Model Directly
452
1754
 
453
- `GetUser` helps to detect a **target member** in multiple ways:
1755
+ You can import the `Log` Mongoose model to create, update, or delete log configurations programmatically.
454
1756
 
455
- 1. Mention (`@User`)
456
- 2. User ID (`123456789012345678`)
457
- 3. Reply to another message
1757
+ **📥 Import the Model:**
458
1758
 
459
- ---
1759
+ ```js
1760
+ const { Log } = require("djs-builder");
1761
+ ```
460
1762
 
461
- ### 📌 Example Usage:
1763
+ **➕ Create New Configuration:**
462
1764
 
463
1765
  ```js
464
- const { GetUser } = require("djs-builder");
1766
+ const { Log } = require("djs-builder");
1767
+
1768
+ // Create a new log configuration for a guild
1769
+ const newConfig = await Log.create({
1770
+ guildId: "123456789012345678",
1771
+ channelId: "987654321098765432",
1772
+ channels: {
1773
+ messageDelete: "111111111111111111",
1774
+ },
1775
+ colors: {
1776
+ messageDelete: "Red",
1777
+ },
1778
+ disable: [],
1779
+ });
465
1780
 
466
- const data = await GetUser(message);
1781
+ console.log("✅ Log configuration created!", newConfig);
1782
+ ```
467
1783
 
468
- if (!data) return message.reply("❌ Could not find the user.");
1784
+ **✏️ Update Existing Configuration:**
469
1785
 
470
- const member = data.user; // GuildMember object
471
- const args = data.args; // Remaining arguments
472
- const reason = args.join(" ") || "No reason provided";
1786
+ ```js
1787
+ const { Log } = require("djs-builder");
473
1788
 
474
- await member.ban({ reason });
475
- message.reply(`🚫 ${member.user.tag} was banned for: ${reason}`);
1789
+ // Update log channel
1790
+ await Log.findOneAndUpdate(
1791
+ { guildId: "123456789012345678" },
1792
+ { channelId: "NEW_CHANNEL_ID" },
1793
+ { upsert: true } // Create if doesn't exist
1794
+ );
1795
+
1796
+ // Add event to disable list
1797
+ await Log.findOneAndUpdate(
1798
+ { guildId: "123456789012345678" },
1799
+ { $push: { disable: "voiceStateUpdate" } }
1800
+ );
1801
+
1802
+ // Remove event from disable list
1803
+ await Log.findOneAndUpdate(
1804
+ { guildId: "123456789012345678" },
1805
+ { $pull: { disable: "voiceStateUpdate" } }
1806
+ );
1807
+
1808
+ // Update specific channel for an event
1809
+ await Log.findOneAndUpdate(
1810
+ { guildId: "123456789012345678" },
1811
+ { $set: { "channels.messageDelete": "NEW_CHANNEL_ID" } }
1812
+ );
1813
+
1814
+ // Update specific color for an event
1815
+ await Log.findOneAndUpdate(
1816
+ { guildId: "123456789012345678" },
1817
+ { $set: { "colors.messageDelete": "DarkRed" } }
1818
+ );
476
1819
  ```
477
1820
 
478
- ---
1821
+ **🗑️ Delete Configuration:**
479
1822
 
480
- ### 🔹 Returns
1823
+ ```js
1824
+ const { Log } = require("djs-builder");
1825
+
1826
+ await Log.findOneAndDelete({ guildId: "123456789012345678" });
1827
+ console.log("🗑️ Log configuration deleted!");
1828
+ ```
1829
+
1830
+ **📊 Fetch Configuration:**
481
1831
 
482
1832
  ```js
483
- {
484
- user: <GuildMember>, // Targeted member
485
- args: [ "arg1", "arg2" ] // Remaining message arguments
1833
+ const { Log } = require("djs-builder");
1834
+
1835
+ const config = await Log.findOne({ guildId: "123456789012345678" });
1836
+ if (config) {
1837
+ console.log("📢 Log Channel:", config.channelId);
1838
+ console.log("📂 Custom Channels:", config.channels);
1839
+ console.log("🎨 Custom Colors:", config.colors);
1840
+ console.log("🚫 Disabled Events:", config.disable);
486
1841
  }
487
1842
  ```
488
1843
 
1844
+ </details>
1845
+
489
1846
  ---
490
1847
 
491
- ### 🔹 Detection Methods
1848
+ <details>
1849
+ <summary>🌐 Dashboard Integration – Manage Logs from Web Panel 🖥️</summary>
492
1850
 
493
- - **Mention:** `!ban @Ahmed Spamming`
494
- - **User ID:** `!ban 123456789012345678 Spamming`
495
- - **Reply:** `Reply to user's message with !ban`
1851
+ ### 🖥️ Web Dashboard for Log Management
496
1852
 
497
- ---
1853
+ When you use **database mode** (`database: true`), you can manage the logging system directly from the **djs-builder Dashboard**! 🎛️
498
1854
 
499
- ### 🔹 Notes
1855
+ ---
500
1856
 
501
- - Automatically handles missing users
502
- - Returns `null` if user not found
503
- - Works in any text channel of the guild
1857
+ #### Dashboard Features for Logs
504
1858
 
505
- </details>
1859
+ | Feature | Description |
1860
+ | ---------------------- | -------------------------------------------- |
1861
+ | 📢 **Default Channel** | Set the main channel for all logs |
1862
+ | 📂 **Custom Channels** | Assign specific channels for each event type |
1863
+ | 🎨 **Custom Colors** | Choose embed colors for each event type |
1864
+ | 🔄 **Toggle Events** | Enable/Disable specific event types |
1865
+ | 📊 **Statistics** | View enabled/disabled events count |
1866
+ | 🗑️ **Reset** | Clear all log settings with one click |
506
1867
 
507
1868
  ---
508
1869
 
509
- <details>
510
- <summary>Logging System 🛡️</summary>
1870
+ #### 🚀 How to Access
511
1871
 
512
- The **Logging System** is a powerful feature that keeps track of almost everything happening inside your Discord server 🔍.
513
- From **messages** 📝 to **channels** 📂, **roles** 🎭, **invites** 🔗, and even **voice state changes** 🎙️ – nothing goes unnoticed!
1872
+ 1. Navigate to your dashboard (e.g., `http://localhost:3000`)
1873
+ 2. Log in with Discord OAuth2
1874
+ 3. Select a server
1875
+ 4. Click on **"سجلات المراقبة"** (Logs) in the sidebar
514
1876
 
515
1877
  ---
516
1878
 
517
- ### Features
1879
+ #### ⚠️ Important Notes
518
1880
 
519
- - 📝 **Messages** Deleted & edited messages are logged with details.
520
- - 📂 **Channels** – Creation, deletion, and updates are tracked.
521
- - 🎭 **Roles** Created, deleted, and updated roles, including member role changes.
522
- - 🎙️ **Voice State** Joins, leaves, and moves between channels.
523
- - 🔗 **Invites** – Created invites & usage tracking.
524
- - 😀 **Emojis & Stickers** – Added, removed, or updated.
525
- - 🚨 **Audit Log Integration** – Fetches the executor (who did what).
526
- - 🎨 **Beautiful Embeds** – Every log is shown in a clean, styled embed with timestamps.
1881
+ **When `database: true`:**
1882
+
1883
+ - Full editing capabilities from dashboard
1884
+ - Changes are saved automatically to MongoDB
1885
+ - Real-time updates
1886
+
1887
+ **When `database: false` (Custom Data Array):**
1888
+
1889
+ - ⚠️ Dashboard shows **read-only** mode
1890
+ - ⚠️ A warning banner appears at the top
1891
+ - ⚠️ You must edit settings in your code
1892
+
1893
+ </details>
527
1894
 
528
1895
  ---
529
1896
 
530
- ### ⚙️ Setup Example
1897
+ <details>
1898
+ <summary>🎮 Slash Command for Log Management 🛠️</summary>
1899
+
1900
+ ### 🛠️ Complete Log Management Slash Command
1901
+
1902
+ This command allows server administrators to manage the logging system via Discord.
531
1903
 
532
- Using the `log` function is very simple ⚡.
533
- Just place this code inside an event (like `clientReady`) to start logging:
1904
+ > ⚠️ **Important**: This command requires `database: true` mode to work properly.
534
1905
 
535
1906
  ```js
536
- const { log } = require("djs-builder");
1907
+ const { Log, getLogConfigData } = require("djs-builder");
1908
+ const {
1909
+ SlashCommandBuilder,
1910
+ PermissionFlagsBits,
1911
+ EmbedBuilder,
1912
+ ChannelType,
1913
+ } = require("discord.js");
1914
+
1915
+ // All supported event types (21 events)
1916
+ const EVENT_TYPES = [
1917
+ { name: "Message Delete", value: "messageDelete" },
1918
+ { name: "Message Update", value: "messageUpdate" },
1919
+ { name: "Channel Create", value: "channelCreate" },
1920
+ { name: "Channel Delete", value: "channelDelete" },
1921
+ { name: "Channel Update", value: "channelUpdate" },
1922
+ { name: "Member Join", value: "guildMemberAdd" },
1923
+ { name: "Member Leave", value: "guildMemberRemove" },
1924
+ { name: "Member Ban", value: "guildBanAdd" },
1925
+ { name: "Member Unban", value: "guildBanRemove" },
1926
+ { name: "Role Create", value: "roleCreate" },
1927
+ { name: "Role Delete", value: "roleDelete" },
1928
+ { name: "Role Update", value: "roleUpdate" },
1929
+ { name: "Member Role Update", value: "guildMemberUpdate" },
1930
+ { name: "Voice State", value: "voiceStateUpdate" },
1931
+ { name: "Invite Create", value: "inviteCreate" },
1932
+ { name: "Emoji Create", value: "emojiCreate" },
1933
+ { name: "Emoji Delete", value: "emojiDelete" },
1934
+ { name: "Emoji Update", value: "emojiUpdate" },
1935
+ { name: "Sticker Create", value: "stickerCreate" },
1936
+ { name: "Sticker Delete", value: "stickerDelete" },
1937
+ { name: "Sticker Update", value: "stickerUpdate" },
1938
+ ];
1939
+
1940
+ // Helper function to clear cache after updates
1941
+ function clearLogCache(guildId) {
1942
+ const logData = getLogConfigData();
1943
+ if (logData.clearCache) logData.clearCache(guildId);
1944
+ }
537
1945
 
538
1946
  module.exports = {
539
- name: "clientReady",
540
- async run(client) {
541
- await log(
542
- client,
543
- "GUILD_ID", // 🏠 Guild ID (server)
544
- "CHANNEL_ID" // 📢 Channel ID for logs
545
- );
1947
+ data: new SlashCommandBuilder()
1948
+ .setName("logs")
1949
+ .setDescription("🛡️ Manage the server logging system")
1950
+ .setDefaultMemberPermissions(PermissionFlagsBits.Administrator)
1951
+ .addSubcommand((sub) =>
1952
+ sub
1953
+ .setName("setup")
1954
+ .setDescription("📢 Set up the default log channel")
1955
+ .addChannelOption((opt) =>
1956
+ opt
1957
+ .setName("channel")
1958
+ .setDescription("The channel to send logs to")
1959
+ .addChannelTypes(ChannelType.GuildText)
1960
+ .setRequired(true)
1961
+ )
1962
+ )
1963
+ .addSubcommand((sub) =>
1964
+ sub
1965
+ .setName("channel")
1966
+ .setDescription("📂 Set a specific channel for an event type")
1967
+ .addStringOption((opt) =>
1968
+ opt
1969
+ .setName("event")
1970
+ .setDescription("The event type")
1971
+ .setRequired(true)
1972
+ .addChoices(...EVENT_TYPES)
1973
+ )
1974
+ .addChannelOption((opt) =>
1975
+ opt
1976
+ .setName("channel")
1977
+ .setDescription("The channel for this event")
1978
+ .addChannelTypes(ChannelType.GuildText)
1979
+ .setRequired(true)
1980
+ )
1981
+ )
1982
+ .addSubcommand((sub) =>
1983
+ sub
1984
+ .setName("color")
1985
+ .setDescription("🎨 Set a custom color for an event type")
1986
+ .addStringOption((opt) =>
1987
+ opt
1988
+ .setName("event")
1989
+ .setDescription("The event type")
1990
+ .setRequired(true)
1991
+ .addChoices(...EVENT_TYPES)
1992
+ )
1993
+ .addStringOption((opt) =>
1994
+ opt
1995
+ .setName("color")
1996
+ .setDescription("Color name or hex code (e.g., Red, #FF5733)")
1997
+ .setRequired(true)
1998
+ )
1999
+ )
2000
+ .addSubcommand((sub) =>
2001
+ sub
2002
+ .setName("toggle")
2003
+ .setDescription("🔄 Enable or disable an event type")
2004
+ .addStringOption((opt) =>
2005
+ opt
2006
+ .setName("event")
2007
+ .setDescription("The event type")
2008
+ .setRequired(true)
2009
+ .addChoices(...EVENT_TYPES)
2010
+ )
2011
+ .addStringOption((opt) =>
2012
+ opt
2013
+ .setName("action")
2014
+ .setDescription("Enable or disable")
2015
+ .setRequired(true)
2016
+ .addChoices(
2017
+ { name: "Enable", value: "enable" },
2018
+ { name: "Disable", value: "disable" }
2019
+ )
2020
+ )
2021
+ )
2022
+ .addSubcommand((sub) =>
2023
+ sub.setName("view").setDescription("📊 View current log configuration")
2024
+ )
2025
+ .addSubcommand((sub) =>
2026
+ sub
2027
+ .setName("reset")
2028
+ .setDescription("🗑️ Reset all log settings for this server")
2029
+ ),
2030
+
2031
+ async run(client, interaction) {
2032
+ await interaction.deferReply({ ephemeral: true });
2033
+
2034
+ const subcommand = interaction.options.getSubcommand();
2035
+ const guildId = interaction.guild.id;
2036
+
2037
+ // ═══════════════════════════════════════════════════════
2038
+ // 📢 SETUP - Set default log channel
2039
+ // ═══════════════════════════════════════════════════════
2040
+ if (subcommand === "setup") {
2041
+ const channel = interaction.options.getChannel("channel");
2042
+
2043
+ await Log.findOneAndUpdate(
2044
+ { guildId },
2045
+ { guildId, channelId: channel.id },
2046
+ { upsert: true, new: true }
2047
+ );
2048
+
2049
+ clearLogCache(guildId); // Clear cache to apply changes immediately
2050
+
2051
+ const embed = new EmbedBuilder()
2052
+ .setTitle("✅ Logging System Setup")
2053
+ .setDescription(`Logs will now be sent to ${channel}`)
2054
+ .setColor("Green")
2055
+ .setTimestamp();
2056
+
2057
+ return interaction.editReply({ embeds: [embed] });
2058
+ }
2059
+
2060
+ // ═══════════════════════════════════════════════════════
2061
+ // 📂 CHANNEL - Set specific channel for event
2062
+ // ═══════════════════════════════════════════════════════
2063
+ if (subcommand === "channel") {
2064
+ const event = interaction.options.getString("event");
2065
+ const channel = interaction.options.getChannel("channel");
2066
+
2067
+ await Log.findOneAndUpdate(
2068
+ { guildId },
2069
+ { $set: { [`channels.${event}`]: channel.id } },
2070
+ { upsert: true }
2071
+ );
2072
+
2073
+ clearLogCache(guildId);
2074
+
2075
+ const eventName =
2076
+ EVENT_TYPES.find((e) => e.value === event)?.name || event;
2077
+ const embed = new EmbedBuilder()
2078
+ .setTitle("📂 Event Channel Updated")
2079
+ .setDescription(`**${eventName}** logs will now be sent to ${channel}`)
2080
+ .setColor("Blue")
2081
+ .setTimestamp();
2082
+
2083
+ return interaction.editReply({ embeds: [embed] });
2084
+ }
2085
+
2086
+ // ═══════════════════════════════════════════════════════
2087
+ // 🎨 COLOR - Set custom color for event
2088
+ // ═══════════════════════════════════════════════════════
2089
+ if (subcommand === "color") {
2090
+ const event = interaction.options.getString("event");
2091
+ const color = interaction.options.getString("color");
2092
+
2093
+ await Log.findOneAndUpdate(
2094
+ { guildId },
2095
+ { $set: { [`colors.${event}`]: color } },
2096
+ { upsert: true }
2097
+ );
2098
+
2099
+ clearLogCache(guildId);
2100
+
2101
+ const eventName =
2102
+ EVENT_TYPES.find((e) => e.value === event)?.name || event;
2103
+
2104
+ // Try to use the color, fallback to Blue if invalid
2105
+ let embedColor;
2106
+ try {
2107
+ embedColor = color;
2108
+ } catch {
2109
+ embedColor = "Blue";
2110
+ }
2111
+
2112
+ const embed = new EmbedBuilder()
2113
+ .setTitle("🎨 Event Color Updated")
2114
+ .setDescription(
2115
+ `**${eventName}** embeds will now use color: \`${color}\``
2116
+ )
2117
+ .setColor(embedColor)
2118
+ .setTimestamp();
2119
+
2120
+ return interaction.editReply({ embeds: [embed] });
2121
+ }
2122
+
2123
+ // ═══════════════════════════════════════════════════════
2124
+ // 🔄 TOGGLE - Enable/Disable event
2125
+ // ═══════════════════════════════════════════════════════
2126
+ if (subcommand === "toggle") {
2127
+ const event = interaction.options.getString("event");
2128
+ const action = interaction.options.getString("action");
2129
+
2130
+ if (action === "disable") {
2131
+ await Log.findOneAndUpdate(
2132
+ { guildId },
2133
+ { $addToSet: { disable: event } },
2134
+ { upsert: true }
2135
+ );
2136
+ } else {
2137
+ await Log.findOneAndUpdate(
2138
+ { guildId },
2139
+ { $pull: { disable: event } },
2140
+ { upsert: true }
2141
+ );
2142
+ }
2143
+
2144
+ clearLogCache(guildId);
2145
+
2146
+ const eventName =
2147
+ EVENT_TYPES.find((e) => e.value === event)?.name || event;
2148
+ const embed = new EmbedBuilder()
2149
+ .setTitle(
2150
+ action === "disable" ? "🚫 Event Disabled" : "✅ Event Enabled"
2151
+ )
2152
+ .setDescription(`**${eventName}** logging has been ${action}d`)
2153
+ .setColor(action === "disable" ? "Red" : "Green")
2154
+ .setTimestamp();
2155
+
2156
+ return interaction.editReply({ embeds: [embed] });
2157
+ }
2158
+
2159
+ // ═══════════════════════════════════════════════════════
2160
+ // 📊 VIEW - Show current configuration
2161
+ // ═══════════════════════════════════════════════════════
2162
+ if (subcommand === "view") {
2163
+ const config = await Log.findOne({ guildId });
2164
+
2165
+ if (!config) {
2166
+ return interaction.editReply({
2167
+ content:
2168
+ "❌ No logging configuration found for this server. Use `/logs setup` first!",
2169
+ });
2170
+ }
2171
+
2172
+ const channelsList = config.channels
2173
+ ? Object.entries(config.channels)
2174
+ .map(([k, v]) => {
2175
+ const eventName = EVENT_TYPES.find((e) => e.value === k)?.name || k;
2176
+ return `• **${eventName}**: <#${v}>`;
2177
+ })
2178
+ .join("\n") || "None"
2179
+ : "None";
2180
+
2181
+ const colorsList = config.colors
2182
+ ? Object.entries(config.colors)
2183
+ .map(([k, v]) => {
2184
+ const eventName = EVENT_TYPES.find((e) => e.value === k)?.name || k;
2185
+ return `• **${eventName}**: \`${v}\``;
2186
+ })
2187
+ .join("\n") || "None"
2188
+ : "None";
2189
+
2190
+ const disabledList =
2191
+ config.disable?.length > 0
2192
+ ? config.disable.map((e) => {
2193
+ const eventName = EVENT_TYPES.find((ev) => ev.value === e)?.name || e;
2194
+ return `• ${eventName}`;
2195
+ }).join("\n")
2196
+ : "None";
2197
+
2198
+ const enabledCount = EVENT_TYPES.length - (config.disable?.length || 0);
2199
+
2200
+ const embed = new EmbedBuilder()
2201
+ .setTitle("📊 Log Configuration")
2202
+ .setDescription(`**${enabledCount}/${EVENT_TYPES.length}** events are enabled`)
2203
+ .setColor("Blue")
2204
+ .addFields(
2205
+ {
2206
+ name: "📢 Default Channel",
2207
+ value: config.channelId ? `<#${config.channelId}>` : "Not set",
2208
+ inline: true,
2209
+ },
2210
+ {
2211
+ name: "📂 Custom Channels",
2212
+ value: channelsList.slice(0, 1024) || "None",
2213
+ inline: false,
2214
+ },
2215
+ {
2216
+ name: "🎨 Custom Colors",
2217
+ value: colorsList.slice(0, 1024) || "None",
2218
+ inline: false,
2219
+ },
2220
+ {
2221
+ name: "🚫 Disabled Events",
2222
+ value: disabledList.slice(0, 1024) || "None",
2223
+ inline: false,
2224
+ }
2225
+ )
2226
+ .setFooter({ text: `Guild ID: ${guildId}` })
2227
+ .setTimestamp();
2228
+
2229
+ return interaction.editReply({ embeds: [embed] });
2230
+ }
2231
+
2232
+ // ═══════════════════════════════════════════════════════
2233
+ // 🗑️ RESET - Delete all configuration
2234
+ // ═══════════════════════════════════════════════════════
2235
+ if (subcommand === "reset") {
2236
+ await Log.findOneAndDelete({ guildId });
2237
+
2238
+ clearLogCache(guildId);
2239
+
2240
+ const embed = new EmbedBuilder()
2241
+ .setTitle("🗑️ Configuration Reset")
2242
+ .setDescription(
2243
+ "All logging settings have been deleted for this server."
2244
+ )
2245
+ .setColor("Red")
2246
+ .setTimestamp();
2247
+
2248
+ return interaction.editReply({ embeds: [embed] });
2249
+ }
546
2250
  },
547
2251
  };
548
2252
  ```
549
2253
 
2254
+ </details>
2255
+
550
2256
  ---
551
2257
 
552
- ### 💡 How It Works
2258
+ ### 💡 Tips & Notes
553
2259
 
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!
2260
+ - 🔄 **Caching**: The system caches guild configurations for better performance.
2261
+ - 🔐 **Permissions**: Make sure your bot has `View Audit Log` permission for full functionality.
2262
+ - 📢 **Invite Tracking**: Uses `discord-inviter` package for accurate invite tracking.
2263
+ - 🎨 **Default Colors**: Each event type has sensible default colors if not customized.
2264
+ - 🚫 **Disabled Events**: Events in the `disable` array will be completely ignored.
2265
+ - 📂 **Channel Fallback**: If no specific channel is set for an event, it uses `channelId`.
2266
+ - 💾 **Database Mode**: Recommended for multi-server bots with dynamic configuration needs.
2267
+ - 🌐 **Dashboard Integration**: When using database mode, you can manage logs via the web dashboard!
2268
+
2269
+ ---
557
2270
 
558
2271
  </details>
559
2272
 
@@ -809,55 +2522,54 @@ const { Gstart } = require("djs-builder");
809
2522
  const { EmbedBuilder } = require("discord.js");
810
2523
 
811
2524
  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,
2525
+ name: "gstart",
2526
+ description: "Starts a new highly-customized giveaway.",
2527
+ run: async (client, message, args) => {
2528
+ // ⏰ Giveaway ends in 48 hours
2529
+ const twoDays = Date.now() + 48 * 60 * 60 * 1000;
2530
+ const channelId = "YOUR_GIVEAWAY_CHANNEL_ID"; // 📢 Target Channel
824
2531
 
825
- // 🎨 Customization for the STARTING EMBED
826
-       embed: {
2532
+ await Gstart({
2533
+ context: message,
2534
+ endTime: twoDays,
2535
+ winers: 5, // 5 lucky winners! 🏆
2536
+ channelId: channelId,
827
2537
 
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
-       },
2538
+ // 🎨 Customization for the STARTING EMBED
2539
+ embed: {
2540
+ custom: new EmbedBuilder().setTitle("Raw Embed"), // 💡 You can use 'custom' to pass a raw Discord.js EmbedBuilder JSON
2541
+ title: "🎉 **HUGE SERVER BOOST GIVEAWAY!**",
2542
+ description:
2543
+ "Click the button below to enter for a chance to win a free server boost!",
2544
+ color: "Blue", // Any valid Discord color
2545
+ image: "https://yourimage.com/banner.png", // image URL
2546
+ thumbnail: message.guild.iconURL(),
2547
+ },
835
2548
 
836
2549
  // 🛑 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
-       },
2550
+ endEmbed: {
2551
+ custom: new EmbedBuilder().setTitle("Raw Embed"), // 💡 You can use 'custom' to pass a raw Discord.js EmbedBuilder JSON
2552
+ title: "🛑 Giveaway Has Concluded!",
2553
+ description: "Congratulations to the winners! Check the message below.",
2554
+ color: "Green", // Eimage and Ethumbnail can also be set here
2555
+ },
844
2556
 
845
2557
  // 🖱️ 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
-       },
2558
+ reaction: {
2559
+ type: "button", // Use 'reaction' for an emoji reaction
2560
+ emoji: "✅", // The emoji displayed on the button
2561
+ label: "Enter Giveaway!", // The text label
2562
+ style: 3, // Button style: Primary(1), Secondary(2), Success(3), Danger(4)
2563
+ id: "djs-builder-giveaway", // Custom ID for the button
2564
+ },
853
2565
 
854
2566
  // 🔒 Requirements (Optional)
855
2567
  requirements: {
856
2568
  requiredRoles: ["123456789012345678"], // 🛡️ User MUST have this role to join (Button Only)
857
2569
  },
858
-     });
859
-     message.reply("🎉 Giveaway started successfully!");
860
-   },
2570
+ });
2571
+ message.reply("🎉 Giveaway started successfully!");
2572
+ },
861
2573
  };
862
2574
  ```
863
2575
 
@@ -1103,14 +2815,14 @@ module.exports = {
1103
2815
  const result = await GaddUser(
1104
2816
  interaction.message.id,
1105
2817
  interaction.user.id,
1106
- interaction.guild
2818
+ interaction.guild
1107
2819
  );
1108
2820
 
1109
2821
  if (result?.error) {
1110
2822
  // Handles both "User Already Joined" and "Missing Roles" errors
1111
2823
  if (result.error === "❌ User Already Joined") {
1112
- // ... (Leave button logic)
1113
- const row = await CreateRow([
2824
+ // ... (Leave button logic)
2825
+ const row = await CreateRow([
1114
2826
  [
1115
2827
  {
1116
2828
  label: "Leave Giveaway",
@@ -1120,16 +2832,17 @@ module.exports = {
1120
2832
  ],
1121
2833
  ]);
1122
2834
  return interaction.reply({
1123
- content: "⚠️ You have **already joined** this giveaway! You can **leave** by clicking the button below.",
2835
+ content:
2836
+ "⚠️ You have **already joined** this giveaway! You can **leave** by clicking the button below.",
1124
2837
  components: row,
1125
- flags: 64,
2838
+ flags: 64,
1126
2839
  });
1127
2840
  }
1128
-
2841
+
1129
2842
  // Show error (e.g. Missing Role)
1130
2843
  return interaction.reply({
1131
- content: result.error,
1132
- flags: 64
2844
+ content: result.error,
2845
+ flags: 64,
1133
2846
  });
1134
2847
  }
1135
2848
 
@@ -1139,7 +2852,6 @@ module.exports = {
1139
2852
  });
1140
2853
  }
1141
2854
 
1142
-
1143
2855
  // 2. Handle Leave Button Click (Dynamically Generated ID)
1144
2856
  if (
1145
2857
  interaction.customId &&
@@ -1534,7 +3246,7 @@ module.exports = {
1534
3246
  channelId: channel.id,
1535
3247
  winers: winnerCount,
1536
3248
  endTime: endTimeMs,
1537
- prize : prize,
3249
+ prize: prize,
1538
3250
  embed: {
1539
3251
  title: `🎉 ${prize} Giveaway!`,
1540
3252
  image: image,
@@ -1810,7 +3522,6 @@ module.exports = {
1810
3522
 
1811
3523
  ---
1812
3524
 
1813
-
1814
3525
  <details>
1815
3526
  <summary>Blacklist System 🚫</summary>
1816
3527
 
@@ -1882,10 +3593,12 @@ console.log("Role unblacklisted! 🔓");
1882
3593
  Returns an array of blacklisted items for a guild. You can optionally filter by type (`user`, `role`, `channel`).
1883
3594
 
1884
3595
  **Parameters:**
3596
+
1885
3597
  - `guildId` (String): The ID of the guild.
1886
3598
  - `type` (String, optional): The type to filter by (`user`, `role`, `channel`).
1887
3599
 
1888
3600
  **Example:**
3601
+
1889
3602
  ```js
1890
3603
  // Get all blacklisted items
1891
3604
  const allBlacklisted = await getBlacklist("GUILD_ID");
@@ -1910,35 +3623,80 @@ Output:
1910
3623
  You can create a slash command to manage the blacklist easily.
1911
3624
 
1912
3625
  ```js
1913
- const { addToBlacklist, removeFromBlacklist, isBlacklisted, getBlacklist } = require("djs-builder");
1914
- const { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder } = require("discord.js");
3626
+ const {
3627
+ addToBlacklist,
3628
+ removeFromBlacklist,
3629
+ isBlacklisted,
3630
+ getBlacklist,
3631
+ } = require("djs-builder");
3632
+ const {
3633
+ SlashCommandBuilder,
3634
+ PermissionFlagsBits,
3635
+ EmbedBuilder,
3636
+ } = require("discord.js");
1915
3637
 
1916
3638
  module.exports = {
1917
3639
  data: new SlashCommandBuilder()
1918
3640
  .setName("blacklist")
1919
3641
  .setDescription("Manage the blacklist")
1920
3642
  .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"))
3643
+ .addSubcommand((sub) =>
3644
+ sub
3645
+ .setName("add")
3646
+ .setDescription("Add to blacklist")
3647
+ .addUserOption((opt) =>
3648
+ opt.setName("user").setDescription("User to blacklist")
3649
+ )
3650
+ .addRoleOption((opt) =>
3651
+ opt.setName("role").setDescription("Role to blacklist")
3652
+ )
3653
+ .addChannelOption((opt) =>
3654
+ opt.setName("channel").setDescription("Channel to blacklist")
3655
+ )
1926
3656
  )
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"))
3657
+ .addSubcommand((sub) =>
3658
+ sub
3659
+ .setName("remove")
3660
+ .setDescription("Remove from blacklist")
3661
+ .addUserOption((opt) =>
3662
+ opt.setName("user").setDescription("User to remove")
3663
+ )
3664
+ .addRoleOption((opt) =>
3665
+ opt.setName("role").setDescription("Role to remove")
3666
+ )
3667
+ .addChannelOption((opt) =>
3668
+ opt.setName("channel").setDescription("Channel to remove")
3669
+ )
1932
3670
  )
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"))
3671
+ .addSubcommand((sub) =>
3672
+ sub
3673
+ .setName("check")
3674
+ .setDescription("Check if a target is blacklisted")
3675
+ .addUserOption((opt) =>
3676
+ opt.setName("user").setDescription("User to check")
3677
+ )
3678
+ .addRoleOption((opt) =>
3679
+ opt.setName("role").setDescription("Role to check")
3680
+ )
3681
+ .addChannelOption((opt) =>
3682
+ opt.setName("channel").setDescription("Channel to check")
3683
+ )
1938
3684
  )
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" }))
3685
+ .addSubcommand((sub) =>
3686
+ sub
3687
+ .setName("list")
3688
+ .setDescription("List all blacklisted items")
3689
+ .addStringOption((opt) =>
3690
+ opt
3691
+ .setName("type")
3692
+ .setDescription("Filter by type")
3693
+ .addChoices(
3694
+ { name: "User", value: "user" },
3695
+ { name: "Role", value: "role" },
3696
+ { name: "Channel", value: "channel" },
3697
+ { name: "All", value: "all" }
3698
+ )
3699
+ )
1942
3700
  ),
1943
3701
  async run(interaction) {
1944
3702
  const sub = interaction.options.getSubcommand();
@@ -1948,54 +3706,95 @@ module.exports = {
1948
3706
  const guildId = interaction.guild.id;
1949
3707
 
1950
3708
  if (sub === "list") {
1951
- const type = interaction.options.getString("type");
1952
- if (type !== "all") {
3709
+ const type = interaction.options.getString("type");
3710
+ if (type !== "all") {
1953
3711
  const list = await getBlacklist(guildId, type);
1954
3712
 
1955
- if (!list.length) return interaction.reply({ content: "✅ No blacklisted items found.", flags : 64 });
3713
+ if (!list.length)
3714
+ return interaction.reply({
3715
+ content: "✅ No blacklisted items found.",
3716
+ flags: 64,
3717
+ });
1956
3718
 
1957
3719
  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 {
3720
+ .setTitle("🚫 Blacklist")
3721
+ .setColor("Red")
3722
+ .setDescription(
3723
+ list
3724
+ .map(
3725
+ (item) =>
3726
+ `• **${item.type.toUpperCase()}**: <${
3727
+ item.type === "channel"
3728
+ ? "#"
3729
+ : item.type === "role"
3730
+ ? "@&"
3731
+ : "@"
3732
+ }${item.id}> (\`${item.id}\`)`
3733
+ )
3734
+ .join("\n")
3735
+ .slice(0, 4000)
3736
+ );
3737
+
3738
+ return interaction.reply({ embeds: [embed], flags: 64 });
3739
+ } else {
1964
3740
  const list = await getBlacklist(guildId);
1965
- if (!list.length) return interaction.reply({ content: "✅ No blacklisted items found.", flags : 64 });
3741
+ if (!list.length)
3742
+ return interaction.reply({
3743
+ content: "✅ No blacklisted items found.",
3744
+ flags: 64,
3745
+ });
1966
3746
 
1967
3747
  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");
3748
+ const roles = list.filter((i) => i.type === "role");
3749
+ const users = list.filter((i) => i.type === "user");
3750
+ const channels = list.filter((i) => i.type === "channel");
1971
3751
 
1972
3752
  if (users.length) {
1973
- const userEmbed = new EmbedBuilder()
3753
+ const userEmbed = new EmbedBuilder()
1974
3754
  .setTitle("🚫 Blacklisted Users")
1975
3755
  .setColor("Red")
1976
- .setDescription(users.map(item => `• <@${item.id}> (\`${item.id}\`)`).join("\n").slice(0, 4000));
1977
- embeds.push(userEmbed);
3756
+ .setDescription(
3757
+ users
3758
+ .map((item) => `• <@${item.id}> (\`${item.id}\`)`)
3759
+ .join("\n")
3760
+ .slice(0, 4000)
3761
+ );
3762
+ embeds.push(userEmbed);
1978
3763
  }
1979
- if( roles.length) {
1980
- const roleEmbed = new EmbedBuilder()
3764
+ if (roles.length) {
3765
+ const roleEmbed = new EmbedBuilder()
1981
3766
  .setTitle("🚫 Blacklisted Roles")
1982
3767
  .setColor("Red")
1983
- .setDescription(roles.map(item => `• <@&${item.id}> (\`${item.id}\`)`).join("\n").slice(0, 4000));
1984
- embeds.push(roleEmbed);
3768
+ .setDescription(
3769
+ roles
3770
+ .map((item) => `• <@&${item.id}> (\`${item.id}\`)`)
3771
+ .join("\n")
3772
+ .slice(0, 4000)
3773
+ );
3774
+ embeds.push(roleEmbed);
1985
3775
  }
1986
- if( channels.length) {
1987
- const channelEmbed = new EmbedBuilder()
3776
+ if (channels.length) {
3777
+ const channelEmbed = new EmbedBuilder()
1988
3778
  .setTitle("🚫 Blacklisted Channels")
1989
3779
  .setColor("Red")
1990
- .setDescription(channels.map(item => `• <#${item.id}> (\`${item.id}\`)`).join("\n").slice(0, 4000));
1991
- embeds.push(channelEmbed);
3780
+ .setDescription(
3781
+ channels
3782
+ .map((item) => `• <#${item.id}> (\`${item.id}\`)`)
3783
+ .join("\n")
3784
+ .slice(0, 4000)
3785
+ );
3786
+ embeds.push(channelEmbed);
1992
3787
  }
1993
- return interaction.reply({ embeds, flags : 64 });
3788
+ return interaction.reply({ embeds, flags: 64 });
3789
+ }
1994
3790
  }
1995
- }
1996
-
3791
+
1997
3792
  if (!user && !role && !channel) {
1998
- return interaction.reply({ content: "⚠️ You must provide at least one option (User, Role, or Channel).", flags : 64 });
3793
+ return interaction.reply({
3794
+ content:
3795
+ "⚠️ You must provide at least one option (User, Role, or Channel).",
3796
+ flags: 64,
3797
+ });
1999
3798
  }
2000
3799
  const target = user || role || channel;
2001
3800
  const type = user ? "user" : role ? "role" : "channel";
@@ -2003,18 +3802,25 @@ module.exports = {
2003
3802
 
2004
3803
  if (sub === "add") {
2005
3804
  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.`);
3805
+ if (success)
3806
+ interaction.reply(`✅ Added **${type}** ${target} to blacklist.`);
3807
+ else
3808
+ interaction.reply(`⚠️ **${type}** ${target} is already blacklisted.`);
2008
3809
  } else if (sub === "remove") {
2009
3810
  const success = await removeFromBlacklist(guildId, type, id);
2010
- if (success) interaction.reply(`✅ Removed **${type}** ${target} from blacklist.`);
3811
+ if (success)
3812
+ interaction.reply(`✅ Removed **${type}** ${target} from blacklist.`);
2011
3813
  else interaction.reply(`⚠️ **${type}** ${target} is not blacklisted.`);
2012
3814
  } else if (sub === "check") {
2013
3815
  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.`);
3816
+ if (isBlocked)
3817
+ interaction.reply(
3818
+ `🚫 **${type}** ${target} is currently **blacklisted**.`
3819
+ );
3820
+ else
3821
+ interaction.reply(`✅ **${type}** ${target} is **not** blacklisted.`);
2016
3822
  }
2017
- }
3823
+ },
2018
3824
  };
2019
3825
  ```
2020
3826
 
@@ -2160,6 +3966,7 @@ The **Dashboard System** is a modern, lightweight web-based control panel for yo
2160
3966
  - 📜 **Commands Viewer** – Browse all slash and prefix commands.
2161
3967
  - 🏆 **Level System Management** – View leaderboards, manage user XP and levels.
2162
3968
  - 🎉 **Giveaway Control** – Pause, resume, end, reroll, or delete giveaways.
3969
+ - 🦾 **Logging System Control** – Manage log channels, colors, and event toggles.
2163
3970
  - 🚫 **Blacklist Management** – Add/remove users, roles, or channels from blacklist.
2164
3971
  - 🎨 **Modern UI** – Beautiful, responsive design with dark mode support.
2165
3972
 
@@ -2191,11 +3998,10 @@ const starterOptions = {
2191
3998
 
2192
3999
  // 🌐 Dashboard Configuration
2193
4000
  dashboard: {
2194
- clientID: "YOUR_DISCORD_CLIENT_ID", // 🔑 Discord Application Client ID
2195
4001
  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)
4002
+ callbackURL: "http://localhost:3000/auth/discord/callback", // 🔗 OAuth2 Callback URL (OPTINAL)
4003
+ sessionSecret: "your-super-secret-key", // 🔒 Session encryption secret
4004
+ port: 3000, // 🌍 Dashboard port (OPTINAL / default: 3000)
2199
4005
  },
2200
4006
 
2201
4007
  // ... other options (Status, database, anticrash, etc.)
@@ -2229,11 +4035,10 @@ client.once("ready", () => {
2229
4035
 
2230
4036
  // 🌐 Start the Dashboard
2231
4037
  dashboard(client, {
2232
- clientID: "YOUR_DISCORD_CLIENT_ID", // 🔑 Discord Application Client ID
2233
4038
  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)
4039
+ callbackURL: "http://localhost:3000/auth/discord/callback", // 🔗 OAuth2 Callback URL (OPTINAL)
4040
+ sessionSecret: "your-super-secret-key", // 🔒 Session encryption secret
4041
+ port: 3000, // 🌍 Dashboard port (OPTINAL / default: 3000)
2237
4042
  });
2238
4043
  });
2239
4044
  ```
@@ -2249,15 +4054,16 @@ client.once("ready", () => {
2249
4054
 
2250
4055
  ### 📌 Dashboard Routes
2251
4056
 
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 |
4057
+ | Route | Description |
4058
+ | ------------------------------- | ---------------------------- |
4059
+ | `/` | 🏠 Homepage with bot stats |
4060
+ | `/login` | 🔐 Login page |
4061
+ | `/dashboard` | 📊 Server selection |
4062
+ | `/dashboard/:guildId` | 🏠 Server overview |
4063
+ | `/dashboard/:guildId/commands` | 📜 Commands list |
4064
+ | `/dashboard/:guildId/levels` | 🏆 Level leaderboard |
4065
+ | `/dashboard/:guildId/giveaways` | 🎉 Giveaway management |
4066
+ | `/dashboard/:guildId/logs` | 🛡️ Logging system management |
2261
4067
 
2262
4068
  ---
2263
4069
 
@@ -2290,7 +4096,13 @@ POST /api/:guildId/giveaway/end
2290
4096
  POST /api/:guildId/giveaway/reroll
2291
4097
  POST /api/:guildId/giveaway/delete
2292
4098
 
2293
- // 🚫 Blacklist management
4099
+ // �️ Logging system management
4100
+ POST /api/:guildId/logs/channel // Set default log channel
4101
+ POST /api/:guildId/logs/toggle // Enable/disable event type
4102
+ POST /api/:guildId/logs/event // Update event settings (channel, color)
4103
+ POST /api/:guildId/logs/reset // Reset all log settings
4104
+
4105
+ // �🚫 Blacklist management
2294
4106
  POST /api/guild/:guildId/blacklist // Add to blacklist
2295
4107
  DELETE /api/guild/:guildId/blacklist // Remove from blacklist
2296
4108
  ```
@@ -2304,13 +4116,12 @@ DELETE /api/guild/:guildId/blacklist // Remove from blacklist
2304
4116
 
2305
4117
  ### 🔧 Configuration Options
2306
4118
 
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) |
4119
+ | Option | Type | Required | Description |
4120
+ | --------------- | -------- | -------- | ---------------------------------------------------- |
4121
+ | `clientSecret` | `string` | ✅ | 🔐 Your Discord Application Client Secret |
4122
+ | `callbackURL` | `string` | ✅ | 🔗 OAuth2 redirect URL (must match Discord settings) |
4123
+ | `sessionSecret` | `string` | ✅ | 🔒 Secret key for session encryption |
4124
+ | `port` | `number` | | 🌍 Port to run the dashboard (default: 3000) |
2314
4125
 
2315
4126
  ---
2316
4127
 
@@ -2318,16 +4129,17 @@ DELETE /api/guild/:guildId/blacklist // Remove from blacklist
2318
4129
 
2319
4130
  The dashboard uses **EJS** templates located in the `views` folder:
2320
4131
 
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 |
4132
+ | File | Description |
4133
+ | --------------- | ---------------------------- |
4134
+ | `index.ejs` | 🏠 Homepage |
4135
+ | `login.ejs` | 🔐 Login page |
4136
+ | `dashboard.ejs` | 📊 Server selection |
4137
+ | `guild.ejs` | 🏠 Server overview |
4138
+ | `commands.ejs` | 📜 Commands list |
4139
+ | `levels.ejs` | 🏆 Level management |
4140
+ | `giveaways.ejs` | 🎉 Giveaway management |
4141
+ | `logs.ejs` | 🛡️ Logging system management |
4142
+ | `404.ejs` | ❌ Not found page |
2331
4143
 
2332
4144
  </details>
2333
4145