djs-builder 0.7.0 โ†’ 0.7.1-8.1

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
@@ -5,6 +5,8 @@
5
5
  **Welcome to the ultimate Discord Bot Utilities package! ๐Ÿฅ**
6
6
  Boost your Discord bot development with ease, speed, and all-in-one features.
7
7
 
8
+ [![Discord Banner](https://api.weblutions.com/discord/invite/uYcKCZk3/)](https://discord.gg/uYcKCZk3)
9
+
8
10
  ---
9
11
 
10
12
  ## ๐Ÿ“‘ Table of Contents
@@ -64,6 +66,7 @@ const starterOptions = {
64
66
 
65
67
  database: {
66
68
  url: "mongodb://localhost:27017", // ๐Ÿ’พ MongoDB connection
69
+ dbName: "yourDatabaseName", // ๐Ÿ“ Optional: Specify database name (default: "test")
67
70
  },
68
71
 
69
72
  anticrash: {
@@ -73,11 +76,10 @@ const starterOptions = {
73
76
 
74
77
  // ๐ŸŒ Dashboard Configuration (Full docs at the end of this page)
75
78
  dashboard: {
76
- clientID: "YOUR_DISCORD_CLIENT_ID", // ๐Ÿ”‘ Discord Application Client ID
77
79
  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)
80
+ callbackURL: "http://localhost:3000/auth/discord/callback", // ๐Ÿ”— OAuth2 Callback URL (OPTINAL)
81
+ sessionSecret: "your-super-secret-key", // ๐Ÿ”’ Session encryption secret
82
+ port: 3000, // ๐ŸŒ Dashboard port (OPTINAL / default: 3000)
81
83
  },
82
84
  };
83
85
 
@@ -100,6 +102,7 @@ await starter(client, starterOptions);
100
102
 
101
103
  - Connects automatically to MongoDB ๐Ÿ’พ.
102
104
  - Useful for bots with persistent data storage.
105
+ - Specify the database name using the `dbName` option. If not specified, MongoDB uses "test" as the default database name.
103
106
 
104
107
  #### 3๏ธโƒฃ Anticrash System
105
108
 
@@ -208,6 +211,12 @@ const actionRow = new CreateRow([
208
211
  emoji: "๐Ÿš€",
209
212
  disabled: true, // Button is disabled
210
213
  },
214
+ {
215
+ style: 5,
216
+ label: "link",
217
+ emoji: "๐Ÿ”—"
218
+ url : "https://discord.gg/z9GpYsYF" // for url button
219
+ }
211
220
  ],
212
221
 
213
222
  // ๐Ÿ”น Row #2: Select Menu
@@ -242,7 +251,7 @@ const actionRow = new CreateRow([
242
251
  disabled: false, // Disable the entire menu
243
252
  defaultValues: [
244
253
  // For role/user/channel menus
245
- { id: "123456789012345678", type: "user" }, // Pre-selected
254
+ { id: "123456789012345678" }, // Pre-selected
246
255
  ],
247
256
  channelTypes: [0, 2], // Only for ChannelSelectMenu (0 = Text, 2 = Voice)
248
257
  },
@@ -261,6 +270,7 @@ const actionRow = new CreateRow([
261
270
  - `label` โ†’ Button text
262
271
  - `emoji` โ†’ Displayed emoji
263
272
  - `disabled` โ†’ true = button is unclickable
273
+ - `url` โ†’ requiier for like button (style : 5)
264
274
 
265
275
  #### ๐Ÿ”น Select Menus
266
276
 
@@ -350,210 +360,1966 @@ console.log(
350
360
 
351
361
  ---
352
362
 
353
- ### ๐Ÿ“Œ Fun Emoji example:
363
+ ### ๐Ÿ“Œ Fun Emoji example:
364
+
365
+ ```js
366
+ console.log(
367
+ CreateBar(6, 10, {
368
+ length: 12,
369
+ fill: "๐Ÿ”ฅ",
370
+ empty: "โ„๏ธ",
371
+ partialChar: "๐ŸŒŸ",
372
+ showPercent: true,
373
+ left: "ยซ",
374
+ right: "ยป",
375
+ })
376
+ );
377
+
378
+ // Output: ยซ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐ŸŒŸโ„๏ธโ„๏ธโ„๏ธโ„๏ธยป 60%
379
+ ```
380
+
381
+ ---
382
+
383
+ ### ๐Ÿ”น Options Summary
384
+
385
+ - `length` โ†’ Total number of symbols
386
+ - `fill` โ†’ Symbol for filled portion
387
+ - `empty` โ†’ Symbol for empty portion
388
+ - `partialChar` โ†’ Symbol for partial fill (e.g., half-filled)
389
+ - `showPercent` โ†’ Show percentage at the end
390
+ - `left` / `right` โ†’ Brackets or edges for the bar
391
+
392
+ ---
393
+
394
+ ### ๐Ÿ”น Notes
395
+
396
+ - Supports **fractional values** for partial fill
397
+ - Fully **customizable with any emoji or character** ๐ŸŽจ
398
+ - Great for **progress, stats, experience bars, or loading indicators**
399
+
400
+ ---
401
+
402
+ </details>
403
+
404
+ ---
405
+
406
+ <details>
407
+ <summary>CreateModal ๐Ÿ”ณ</summary>
408
+
409
+ **๐Ÿ”ณ CreateModal โ€“ Easily create Discord Modals with Text Inputs, Menus, Files, and Labels โœจ**
410
+
411
+ `CreateModal` is a powerful utility to build Discord **Modals**. It supports:
412
+
413
+ - **Text Inputs** ๐Ÿ“
414
+ - **Select Menus** ๐ŸŽฏ (`string`, `role`, `user`, `channel`)
415
+ - **File Uploads** ๐Ÿ“Ž
416
+ - **Text Displays** ๐Ÿท๏ธ
417
+
418
+ ---
419
+
420
+ ### ๐Ÿ“Œ Example Usage:
421
+
422
+ ```js
423
+ const { CreateModal } = require("djs-builder");
424
+
425
+ const modal = CreateModal({
426
+ id: "myModal",
427
+ title: "User Information",
428
+ components: [
429
+ {
430
+ type: "textInput",
431
+ components: [
432
+ {
433
+ label: "Your Name",
434
+ id: "name",
435
+ style: 1, // 1: Short, 2: Paragraph
436
+ placeholder: "Enter your name",
437
+ required: true,
438
+ minLength: 2,
439
+ maxLength: 50,
440
+ },
441
+ ],
442
+ },
443
+ {
444
+ type: "menu",
445
+ components: {
446
+ type: "string",
447
+ options: {
448
+ id: "favoriteColor",
449
+ placeholder: "Choose your favorite color",
450
+ min: 1,
451
+ max: 1,
452
+ data: [
453
+ {
454
+ label: "Red",
455
+ value: "red",
456
+ description: "A bold color",
457
+ emoji: "๐Ÿ”ด",
458
+ default: false,
459
+ },
460
+ {
461
+ label: "Blue",
462
+ value: "blue",
463
+ description: "A calm color",
464
+ emoji: "๐Ÿ”ต",
465
+ },
466
+ ],
467
+ label: "label",
468
+ value: "value",
469
+ description: "description",
470
+ emoji: "emoji",
471
+ disabled: false,
472
+ },
473
+ },
474
+ },
475
+ {
476
+ type: "file",
477
+ components: {
478
+ id: "avatar",
479
+ label: "Upload Avatar",
480
+ description: "Optional avatar image",
481
+ },
482
+ },
483
+ {
484
+ type: "text",
485
+ components: {
486
+ content: "Thank you for your input!",
487
+ },
488
+ },
489
+ ],
490
+ });
491
+
492
+ // Show the modal
493
+ await interaction.showModal(modal);
494
+ ```
495
+
496
+ ---
497
+
498
+ ### ๐Ÿ“” Examples for Each Component Type:
499
+
500
+ #### ๐Ÿ”น Text Input Example:
501
+
502
+ ```js
503
+ {
504
+ type: "textInput",
505
+ components: [
506
+ {
507
+ label: "Your Age",
508
+ id: "age",
509
+ style: 1, // Short input
510
+ placeholder: "Enter your age",
511
+ required: true,
512
+ minLength: 1,
513
+ maxLength: 3,
514
+ value: "18", // Pre-filled
515
+ },
516
+ ],
517
+ },
518
+ ```
519
+
520
+ #### ๐Ÿ”น Menu Example:
521
+
522
+ ```js
523
+ {
524
+ type: "menu",
525
+ components: {
526
+ type: "string",
527
+ options: {
528
+ id: "country",
529
+ mine_label: "Choose Your Country", // Label displayed above the menu
530
+ mine_description: "Please select your country from the list below", // Optional description
531
+ placeholder: "Select your country",
532
+ min: 1,
533
+ max: 1,
534
+ data: [
535
+ {
536
+ name: "USA",
537
+ id: "usa",
538
+ desc: "United States",
539
+ icon: "๐Ÿ‡บ๐Ÿ‡ธ",
540
+ default: true, // This option is pre-selected
541
+ },
542
+ {
543
+ name: "Canada",
544
+ id: "canada",
545
+ desc: "Canada",
546
+ icon: "๐Ÿ‡จ๐Ÿ‡ฆ",
547
+ },
548
+ ],
549
+ label: "name", // Maps to 'name' field in data
550
+ value: "id", // Maps to 'id' field in data
551
+ description: "desc", // Maps to 'desc' field
552
+ emoji: "icon", // Maps to 'icon' field
553
+ disabled: false,
554
+ },
555
+ },
556
+ },
557
+ ```
558
+
559
+ #### ๐Ÿ”น File Example:
560
+
561
+ ```js
562
+ {
563
+ type: "file",
564
+ components: {
565
+ id: "document",
566
+ label: "Upload Document",
567
+ description: "Upload a PDF or image",
568
+ },
569
+ },
570
+ ```
571
+
572
+ #### ๐Ÿ”น Label Example:
573
+
574
+ ```js
575
+ {
576
+ type: "text",
577
+ components: {
578
+ content: "Please fill out the form above.",
579
+ },
580
+ },
581
+ ```
582
+
583
+ ---
584
+
585
+ ### ๏ฟฝ๐Ÿ“– Explanation
586
+
587
+ #### ๐Ÿ”น Text Input
588
+
589
+ - `label` โ†’ Label for the input field
590
+ - `id` โ†’ customId for the input
591
+ - `style` โ†’ 1: Short, 2: Paragraph
592
+ - `placeholder` โ†’ Placeholder text
593
+ - `required` โ†’ true/false
594
+ - `minLength` / `maxLength` โ†’ Min/Max characters
595
+ - `value` โ†’ Pre-filled value
596
+
597
+ #### ๐Ÿ”น Menu
598
+
599
+ Same as CreateRow select menus.
600
+
601
+ - `type` โ†’ `"string" | "user" | "role" | "channel"`
602
+ - `id` โ†’ customId for menu
603
+ - `mine_label` โ†’ Label displayed above the menu component (defaults to "Select an option")
604
+ - `mine_description` โ†’ Description text displayed below the menu label (optional)
605
+ - `placeholder` โ†’ Text shown before selection
606
+ - `min` / `max` โ†’ Min/Max selectable values
607
+ - `data` โ†’ Options array (for string select only)
608
+
609
+ - `label` โ†’ Visible text (maps to the field specified in `label` key)
610
+ - `value` โ†’ Internal value (maps to the field specified in `value` key)
611
+ - `description` โ†’ Short description (maps to the field specified in `description` key)
612
+ - `emoji` โ†’ Option emoji (maps to the field specified in `emoji` key)
613
+ - `default` โ†’ Pre-selected option (true/false in data array)
614
+
615
+ - `label` โ†’ Key in data to use as label (e.g., "name")
616
+ - `value` โ†’ Key in data to use as value (e.g., "id")
617
+ - `description` โ†’ Key in data to use as description (e.g., "desc")
618
+ - `emoji` โ†’ Key in data to use as emoji (e.g., "icon")
619
+ - `disabled` โ†’ Disable menu completely
620
+ - `defaultValues` โ†’ Pre-selected user/role/channel options (for non-string menus)
621
+ - `channelTypes` โ†’ Restrict selectable channel types (for channel menu)
622
+
623
+ #### ๐Ÿ”น File
624
+
625
+ - `id` โ†’ customId for the file upload
626
+ - `label` โ†’ Label
627
+ - `description` โ†’ Description
628
+
629
+ #### ๐Ÿ”น text
630
+
631
+ - `content` โ†’ Text to display
632
+
633
+ ---
634
+
635
+ ### ๐Ÿ”น Notes
636
+
637
+ - Supports multiple components in one modal
638
+ - Fully customizable with Discord.js ModalBuilder
639
+
640
+ </details>
641
+
642
+ ---
643
+
644
+ <details>
645
+ <summary>CreateComponents ๐Ÿงฉ</summary>
646
+
647
+ **๐Ÿงฉ CreateComponents โ€“ Build Advanced Discord UI Components with Containers, Sections & Media โœจ**
648
+
649
+ `CreateComponents` is a powerful utility to build Discord's **new UI components**. It supports:
650
+
651
+ - **Text Displays** ๐Ÿ“
652
+ - **Separators** โž–
653
+ - **Media Galleries** ๐Ÿ–ผ๏ธ
654
+ - **File Attachments** ๐Ÿ“Ž
655
+ - **Buttons** ๐Ÿ”˜
656
+ - **Select Menus** ๐ŸŽฏ (`string`, `role`, `user`, `channel`)
657
+ - **Sections with Accessories** ๐Ÿ“ฆ (Thumbnails & Buttons)
658
+ - **Containers** ๐Ÿ“ฆ (Group all components together)
659
+
660
+ ---
661
+
662
+ ### ๐Ÿ“Œ Example Usage (Array Mode):
663
+
664
+ ```js
665
+ const { CreateComponents } = require("djs-builder");
666
+
667
+ const components = await CreateComponents("array", [
668
+ {
669
+ type: "text",
670
+ content: "Welcome to our server! ๐ŸŽ‰",
671
+ },
672
+ {
673
+ type: "separator",
674
+ divider: true,
675
+ spacing: 1, // 1: Small, 2: Large
676
+ },
677
+ {
678
+ type: "media",
679
+ links: [
680
+ "https://example.com/image1.png",
681
+ {
682
+ url: "https://example.com/image2.png",
683
+ description: "A cool image",
684
+ spoiler: true,
685
+ },
686
+ ],
687
+ },
688
+ {
689
+ type: "button",
690
+ components: [
691
+ {
692
+ id: "btn_1",
693
+ style: 1, // 1: Primary, 2: Secondary, 3: Success, 4: Danger, 5: Link
694
+ label: "Click Me!",
695
+ emoji: "๐Ÿš€",
696
+ },
697
+ {
698
+ id: "btn_2",
699
+ style: 3,
700
+ label: "Confirm",
701
+ },
702
+ ],
703
+ },
704
+ ]);
705
+
706
+ // Send the components
707
+ await channel.send({
708
+ flags: 32768,
709
+ components : components
710
+ });
711
+ ```
712
+
713
+ ---
714
+
715
+ ### ๐Ÿ“Œ Example Usage (Container Mode):
716
+
717
+ ```js
718
+ const { CreateComponents } = require("djs-builder");
719
+
720
+ const components = await CreateComponents(true, [
721
+ {
722
+ type: "text",
723
+ content: "# ๐Ÿ“ข Server Announcement\nWelcome everyone!",
724
+ },
725
+ {
726
+ type: "separator",
727
+ divider: true,
728
+ },
729
+ {
730
+ type: "section",
731
+ content: "Check out our latest updates and news!",
732
+ accessory: {
733
+ type: "thumbnail",
734
+ url: "https://example.com/thumbnail.png",
735
+ description: "News Image",
736
+ },
737
+ },
738
+ {
739
+ type: "section",
740
+ content: "**Click below to get your roles!**",
741
+ accessory: {
742
+ type: "button",
743
+ id: "get_roles",
744
+ style: 1,
745
+ label: "Get Roles",
746
+ emoji: "๐ŸŽญ",
747
+ },
748
+ },
749
+ {
750
+ type: "media",
751
+ links: ["https://example.com/banner.png"],
752
+ },
753
+ {
754
+ type: "button",
755
+ components: [
756
+ { id: "rules", style: 2, label: "๐Ÿ“œ Rules", emoji: "๐Ÿ“œ" },
757
+ { id: "help", style: 2, label: "โ“ Help", emoji: "โ“" },
758
+ { style: 5, label: "๐ŸŒ Website", url: "https://example.com" },
759
+ ],
760
+ },
761
+ ]);
762
+
763
+ // Send with container
764
+ await channel.send({ components, flags: 32768 }); // flags for components v2
765
+ ```
766
+
767
+ ---
768
+
769
+ ### ๐Ÿ“œ Examples for Each Component Type:
770
+
771
+ ---
772
+
773
+ <details>
774
+ <summary>๐Ÿ”น Text Component Examples</summary>
775
+
776
+ #### ๐Ÿ“Œ Simple Text:
777
+
778
+ ```js
779
+ {
780
+ type: "text",
781
+ content: "Hello World! ๐Ÿ‘‹",
782
+ }
783
+ ```
784
+
785
+ #### ๐Ÿ“Œ Text with Markdown:
786
+
787
+ ```js
788
+ {
789
+ type: "text",
790
+ content: "# ๐Ÿ“ข Announcement\n**Important:** Server maintenance tonight!",
791
+ }
792
+ ```
793
+
794
+ #### ๐Ÿ“Œ Text with Multiple Lines:
795
+
796
+ ```js
797
+ {
798
+ type: "text",
799
+ content: `## ๐ŸŽฎ Game Stats
800
+
801
+ **Player:** Ahmed
802
+ **Level:** 50
803
+ **XP:** 12,500 / 15,000
804
+ **Rank:** Diamond ๐Ÿ’Ž`,
805
+ }
806
+ ```
807
+
808
+ #### ๐Ÿ“Œ Text with Emojis & Formatting:
809
+
810
+ ```js
811
+ {
812
+ type: "text",
813
+ content: ">>> ๐Ÿ’ก **Tip:** Use `/help` to see all commands!\n\n*This message will auto-delete in 30 seconds*",
814
+ }
815
+ ```
816
+
817
+ </details>
818
+
819
+ ---
820
+
821
+ <details>
822
+ <summary>โž– Separator Component Examples</summary>
823
+
824
+ **โž– Separator โ€“ Add spacing and dividers between components**
825
+
826
+ The separator component allows you to add visual breaks between other components with customizable spacing and divider lines.
827
+
828
+ ---
829
+
830
+ ### ๐Ÿ“– Separator Options
831
+
832
+ | Option | Type | Default | Description |
833
+ | --------- | --------- | ------- | -------------------------------------------------- |
834
+ | `type` | `string` | โ€” | Must be `"separator"` |
835
+ | `divider` | `boolean` | `false` | Show a horizontal dividing line |
836
+ | `spacing` | `number` | `1` | Spacing size: `1` (Small) or `2` (Large) |
837
+
838
+ ---
839
+
840
+ #### ๐Ÿ“Œ Simple Divider Line:
841
+
842
+ ```js
843
+ {
844
+ type: "separator",
845
+ divider: true,
846
+ }
847
+ ```
848
+ **Result:** A thin horizontal line appears between components.
849
+
850
+ ---
851
+
852
+ #### ๐Ÿ“Œ Separator without Line (Spacing Only):
853
+
854
+ ```js
855
+ {
856
+ type: "separator",
857
+ divider: false,
858
+ spacing: 2, // Large spacing
859
+ }
860
+ ```
861
+ **Result:** Empty space without any visible line - useful for visual grouping.
862
+
863
+ ---
864
+
865
+ #### ๐Ÿ“Œ Small Spacing with Divider:
866
+
867
+ ```js
868
+ {
869
+ type: "separator",
870
+ divider: true,
871
+ spacing: 1, // Small spacing (default)
872
+ }
873
+ ```
874
+ **Result:** A divider line with minimal padding above and below.
875
+
876
+ ---
877
+
878
+ #### ๐Ÿ“Œ Large Spacing with Divider:
879
+
880
+ ```js
881
+ {
882
+ type: "separator",
883
+ divider: true,
884
+ spacing: 2, // Large spacing
885
+ }
886
+ ```
887
+ **Result:** A divider line with more padding - creates stronger visual separation.
888
+
889
+ ---
890
+
891
+ ### ๐Ÿ’ก When to Use Each Option:
892
+
893
+ | Scenario | `divider` | `spacing` |
894
+ | ------------------------------------- | --------- | --------- |
895
+ | Separate major sections | `true` | `2` |
896
+ | Separate sub-sections | `true` | `1` |
897
+ | Group related items visually | `false` | `1` |
898
+ | Create breathing room between content | `false` | `2` |
899
+ | Minimal separation | `false` | `1` |
900
+
901
+ </details>
902
+
903
+ ---
904
+
905
+ <details>
906
+ <summary>๐Ÿ–ผ๏ธ Media Gallery Examples</summary>
907
+
908
+ **๐Ÿ–ผ๏ธ Media Gallery โ€“ Display images in a beautiful gallery format**
909
+
910
+ 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.
911
+
912
+
913
+ ---
914
+
915
+ ### ๐Ÿ“Œ Format 1: Simple String URLs
916
+
917
+ The simplest way - just pass image URLs as strings:
918
+
919
+ ```js
920
+ {
921
+ type: "media",
922
+ links: ["https://example.com/image.png"],
923
+ }
924
+ ```
925
+
926
+ ---
927
+
928
+ ### ๐Ÿ“Œ Format 2: Object with Full Options
929
+
930
+ For more control, use objects with url, description, and spoiler:
931
+
932
+ ```js
933
+ {
934
+ type: "media",
935
+ links: [
936
+ {
937
+ url: "https://example.com/image.png",
938
+ description: "A beautiful sunset",
939
+ spoiler: false,
940
+ },
941
+ ],
942
+ }
943
+ ```
944
+
945
+ ---
946
+
947
+ ### ๐Ÿ“Œ Single Image with Spoiler:
948
+
949
+ ```js
950
+ {
951
+ type: "media",
952
+ links: [
953
+ {
954
+ url: "https://example.com/spoiler.png",
955
+ description: "โš ๏ธ Spoiler Alert!",
956
+ spoiler: true,
957
+ },
958
+ ],
959
+ }
960
+ ```
961
+
962
+ ---
963
+
964
+ ### ๐Ÿ“Œ Multiple Images (Simple Strings):
965
+
966
+ ```js
967
+ {
968
+ type: "media",
969
+ links: [
970
+ "https://example.com/image1.png",
971
+ "https://example.com/image2.png",
972
+ "https://example.com/image3.png",
973
+ "https://example.com/image4.png",
974
+ ],
975
+ }
976
+ ```
977
+ **Result:** A 2x2 gallery grid of images.
978
+
979
+ ---
980
+
981
+ ### ๐Ÿ“Œ Mixed Format (Strings + Objects):
982
+
983
+ You can mix simple strings with detailed objects in the same array:
984
+
985
+ ```js
986
+ {
987
+ type: "media",
988
+ links: [
989
+ // Simple string - just the URL
990
+ "https://example.com/public-image.png",
991
+
992
+ // Object with description
993
+ {
994
+ url: "https://example.com/special-image.png",
995
+ description: "Limited Edition Art",
996
+ },
997
+
998
+ // Object with spoiler
999
+ {
1000
+ url: "https://example.com/secret-image.png",
1001
+ description: "Secret Content",
1002
+ spoiler: true,
1003
+ },
1004
+
1005
+ // Another simple string
1006
+ "https://example.com/another-image.png",
1007
+ ],
1008
+ }
1009
+ ```
1010
+
1011
+ ---
1012
+
1013
+ ### ๐Ÿ“Œ Meme/Artwork Gallery with Spoilers:
1014
+
1015
+ ```js
1016
+ {
1017
+ type: "media",
1018
+ links: [
1019
+ {
1020
+ url: "https://example.com/meme1.png",
1021
+ description: "Funny meme #1",
1022
+ spoiler: false,
1023
+ },
1024
+ {
1025
+ url: "https://example.com/meme2.png",
1026
+ description: "Funny meme #2",
1027
+ spoiler: false,
1028
+ },
1029
+ {
1030
+ url: "https://example.com/nsfw-meme.png",
1031
+ description: "โš ๏ธ Slightly inappropriate",
1032
+ spoiler: true, // Hidden behind blur
1033
+ },
1034
+ ],
1035
+ }
1036
+ ```
1037
+
1038
+ ---
1039
+
1040
+ ### ๐Ÿ’ก Tips for Media Galleries:
1041
+
1042
+ | Images Count | Display Layout |
1043
+ | ------------ | ---------------------- |
1044
+ | 1 image | Full width single image |
1045
+ | 2 images | Side by side |
1046
+ | 3 images | 1 large + 2 small |
1047
+ | 4+ images | Grid layout |
1048
+
1049
+ - Use `description` for accessibility and context
1050
+ - Use `spoiler: true` for sensitive/spoiler content
1051
+ - Mix formats freely - strings for quick images, objects for detailed ones
1052
+ - Images are displayed in the order provided
1053
+
1054
+ </details>
1055
+
1056
+ ---
1057
+
1058
+ <details>
1059
+ <summary>๐Ÿ“Ž File Component Examples</summary>
1060
+
1061
+ #### ๐Ÿ“Œ Simple File Attachment:
1062
+
1063
+ ```js
1064
+ {
1065
+ type: "file",
1066
+ url: "attachment://document.pdf",
1067
+ }
1068
+ ```
1069
+
1070
+
1071
+
1072
+ #### ๐Ÿ“Œ Full Example with File:
1073
+
1074
+ ```js
1075
+ const { CreateComponents } = require("djs-builder");
1076
+ const { AttachmentBuilder } = require("discord.js");
1077
+
1078
+ const file = new AttachmentBuilder("./myfile.txt", { name: "myfile.txt" });
1079
+
1080
+ const components = await CreateComponents("container", [
1081
+ {
1082
+ type: "text",
1083
+ content: "๐Ÿ“„ **Here is your requested file:**",
1084
+ },
1085
+ {
1086
+ type: "file",
1087
+ url: "attachment://myfile.txt",
1088
+ },
1089
+ ]);
1090
+
1091
+ await channel.send({ components, files: [file], flags: 32768 });
1092
+ ```
1093
+
1094
+ </details>
1095
+
1096
+ ---
1097
+
1098
+ <details>
1099
+ <summary>๐Ÿ”˜ Button Component Examples</summary>
1100
+
1101
+ #### ๐Ÿ“Œ Button with Emoji:
1102
+
1103
+ ```js
1104
+ {
1105
+ type: "button",
1106
+ components: [
1107
+ {
1108
+ id: "like_btn",
1109
+ style: 3, // Success (Green)
1110
+ label: "Like",
1111
+ emoji: "๐Ÿ‘",
1112
+ },
1113
+ ],
1114
+ }
1115
+ ```
1116
+
1117
+ #### ๐Ÿ“Œ Multiple Buttons in Row:
1118
+
1119
+ ```js
1120
+ {
1121
+ type: "button",
1122
+ components: [
1123
+ { id: "btn_yes", style: 3, label: "Yes", emoji: "โœ…" },
1124
+ { id: "btn_no", style: 4, label: "No", emoji: "โŒ" },
1125
+ { id: "btn_maybe", style: 2, label: "Maybe", emoji: "๐Ÿค”" },
1126
+ ],
1127
+ }
1128
+ ```
1129
+
1130
+ #### ๐Ÿ“Œ All Button Styles:
1131
+
1132
+ ```js
1133
+ {
1134
+ type: "button",
1135
+ components: [
1136
+ { id: "primary", style: 1, label: "Primary", emoji: "๐Ÿ”ต" }, // Blue
1137
+ { id: "secondary", style: 2, label: "Secondary", emoji: "โšช" }, // Gray
1138
+ { id: "success", style: 3, label: "Success", emoji: "๐ŸŸข" }, // Green
1139
+ { id: "danger", style: 4, label: "Danger", emoji: "๐Ÿ”ด" }, // Red
1140
+ { style: 5, label: "Link", emoji: "๐Ÿ”—", url: "https://discord.com" }, // Link
1141
+ ],
1142
+ }
1143
+ ```
1144
+
1145
+
1146
+ </details>
1147
+
1148
+ ---
1149
+
1150
+ <details>
1151
+ <summary>๐ŸŽฏ Menu Component Examples</summary>
1152
+
1153
+ #### ๐Ÿ“Œ String Select Menu (Basic):
1154
+
1155
+ ```js
1156
+ {
1157
+ type: "menu",
1158
+ components: {
1159
+ type: "string",
1160
+ options: {
1161
+ id: "color_select",
1162
+ placeholder: "๐ŸŽจ Choose a color",
1163
+ data: [
1164
+ { name: "Red", id: "red", icon: "๐Ÿ”ด" },
1165
+ { name: "Blue", id: "blue", icon: "๐Ÿ”ต" },
1166
+ { name: "Green", id: "green", icon: "๐ŸŸข" },
1167
+ ],
1168
+ label: "name",
1169
+ value: "id",
1170
+ emoji: "icon",
1171
+ },
1172
+ },
1173
+ }
1174
+ ```
1175
+
1176
+ #### ๐Ÿ“Œ String Select with Description:
1177
+
1178
+ ```js
1179
+ {
1180
+ type: "menu",
1181
+ components: {
1182
+ type: "string",
1183
+ options: {
1184
+ id: "role_select",
1185
+ placeholder: "๐ŸŽญ Select your role",
1186
+ data: [
1187
+ { name: "Gamer", id: "gamer", desc: "For gaming enthusiasts", icon: "๐ŸŽฎ" },
1188
+ { name: "Artist", id: "artist", desc: "For creative people", icon: "๐ŸŽจ" },
1189
+ { name: "Developer", id: "dev", desc: "For coders & programmers", icon: "๐Ÿ’ป" },
1190
+ { name: "Music Lover", id: "music", desc: "For music fans", icon: "๐ŸŽต" },
1191
+ ],
1192
+ label: "name",
1193
+ value: "id",
1194
+ description: "desc",
1195
+ emoji: "icon",
1196
+ },
1197
+ },
1198
+ }
1199
+ ```
1200
+
1201
+ #### ๐Ÿ“Œ String Select with Min/Max:
1202
+
1203
+ ```js
1204
+ {
1205
+ type: "menu",
1206
+ components: {
1207
+ type: "string",
1208
+ options: {
1209
+ id: "games_select",
1210
+ placeholder: "๐ŸŽฎ Select your favorite games (2-4)",
1211
+ min: 2,
1212
+ max: 4,
1213
+ data: [
1214
+ { name: "Minecraft", id: "mc", icon: "โ›๏ธ" },
1215
+ { name: "Fortnite", id: "fn", icon: "๐Ÿ”ซ" },
1216
+ { name: "Valorant", id: "val", icon: "๐ŸŽฏ" },
1217
+ { name: "League of Legends", id: "lol", icon: "โš”๏ธ" },
1218
+ { name: "Rocket League", id: "rl", icon: "๐Ÿš—" },
1219
+ ],
1220
+ label: "name",
1221
+ value: "id",
1222
+ emoji: "icon",
1223
+ },
1224
+ },
1225
+ }
1226
+ ```
1227
+
1228
+
1229
+ #### ๐Ÿ“Œ User Select (Multiple):
1230
+
1231
+ ```js
1232
+ {
1233
+ type: "menu",
1234
+ components: {
1235
+ type: "user",
1236
+ options: {
1237
+ id: "users_select",
1238
+ placeholder: "๐Ÿ‘ฅ Select users to invite (1-5)",
1239
+ min: 1,
1240
+ max: 5,
1241
+ },
1242
+ },
1243
+ }
1244
+ ```
1245
+
1246
+ #### ๐Ÿ“Œ Role Select Menu:
1247
+
1248
+ ```js
1249
+ {
1250
+ type: "menu",
1251
+ components: {
1252
+ type: "role",
1253
+ options: {
1254
+ id: "role_select",
1255
+ placeholder: "๐ŸŽญ Select a role",
1256
+ min: 1,
1257
+ max: 1,
1258
+ },
1259
+ },
1260
+ }
1261
+ ```
1262
+
1263
+
1264
+ #### ๐Ÿ“Œ Channel Select Menu:
1265
+
1266
+ ```js
1267
+ {
1268
+ type: "menu",
1269
+ components: {
1270
+ type: "channel",
1271
+ options: {
1272
+ id: "channel_select",
1273
+ placeholder: "๐Ÿ“ข Select a channel",
1274
+ min: 1,
1275
+ max: 1,
1276
+ },
1277
+ },
1278
+ }
1279
+ ```
1280
+
1281
+ #### ๐Ÿ“Œ Channel Select with Type Filter:
1282
+
1283
+ ```js
1284
+ const { ChannelType } = require("discord.js");
1285
+
1286
+ {
1287
+ type: "menu",
1288
+ components: {
1289
+ type: "channel",
1290
+ options: {
1291
+ id: "text_channel_select",
1292
+ placeholder: "๐Ÿ’ฌ Select a text channel",
1293
+ channelTypes: [ChannelType.GuildText, ChannelType.GuildAnnouncement],
1294
+ },
1295
+ },
1296
+ }
1297
+ ```
1298
+
1299
+ #### ๐Ÿ“Œ Menu with Default Values (User/Role/Channel):
1300
+
1301
+ ```js
1302
+ {
1303
+ type: "menu",
1304
+ components: {
1305
+ type: "user",
1306
+ options: {
1307
+ id: "user_select_default",
1308
+ placeholder: "๐Ÿ‘ค Select users",
1309
+ min: 1,
1310
+ max: 3,
1311
+ defaultValues: [
1312
+ { id: "123456789012345678", type: "user" },
1313
+ { id: "987654321098765432", type: "user" },
1314
+ ],
1315
+ },
1316
+ },
1317
+ }
1318
+ ```
1319
+
1320
+ </details>
1321
+
1322
+ ---
1323
+
1324
+ <details>
1325
+ <summary>๐Ÿ“ฆ Section Component Examples</summary>
1326
+
1327
+
1328
+ #### ๐Ÿ“Œ Section with Thumbnail (Product):
1329
+
1330
+ ```js
1331
+ {
1332
+ type: "section",
1333
+ content: "๐Ÿ›’ **iPhone 15 Pro**\n๐Ÿ’ฐ Price: $999\nโญ Rating: 4.8/5\n๐Ÿ“ฆ In Stock: Yes",
1334
+ accessory: {
1335
+ type: "thumbnail",
1336
+ url: "https://example.com/iphone.png",
1337
+ description: "iPhone 15 Pro Image",
1338
+ },
1339
+ }
1340
+ ```
1341
+
1342
+ #### ๐Ÿ“Œ Section with Button :
1343
+
1344
+ ```js
1345
+ {
1346
+ type: "section",
1347
+ content: "๐ŸŽ **Daily Reward**\nClick to claim your daily reward!\n๐Ÿ’Ž **+100 Coins**",
1348
+ accessory: {
1349
+ type: "button",
1350
+ id: "claim_daily",
1351
+ style: 3,
1352
+ label: "Claim",
1353
+ emoji: "๐ŸŽ",
1354
+ },
1355
+ }
1356
+ ```
1357
+
1358
+
1359
+
1360
+
1361
+ </details>
1362
+
1363
+ ---
1364
+
1365
+
1366
+ ### ๐Ÿ“– Component Types Explanation
1367
+
1368
+ #### ๐Ÿ”น Text
1369
+
1370
+ - `type` โ†’ `"text"`
1371
+ - `content` โ†’ The text content to display (supports Markdown)
1372
+
1373
+ #### ๐Ÿ”น Separator
1374
+
1375
+ - `type` โ†’ `"separator"`
1376
+ - `divider` โ†’ Show a dividing line (true/false)
1377
+ - `spacing` โ†’ Spacing size (1: Small, 2: Large)
1378
+
1379
+ #### ๐Ÿ”น Media Gallery
1380
+
1381
+ - `type` โ†’ `"media"`
1382
+ - `links` โ†’ Array of image URLs or objects with:
1383
+ - `url` โ†’ Image URL
1384
+ - `description` โ†’ Alt text for the image
1385
+ - `spoiler` โ†’ Hide behind spoiler (true/false)
1386
+
1387
+ #### ๐Ÿ”น File
1388
+
1389
+ - `type` โ†’ `"file"`
1390
+ - `url` โ†’ File URL or attachment reference
1391
+ - `spoiler` โ†’ Hide behind spoiler (true/false)
1392
+
1393
+ #### ๐Ÿ”น Button
1394
+
1395
+ - `type` โ†’ `"button"`
1396
+ - `components` โ†’ Array of button objects:
1397
+ - `id` โ†’ customId (required for non-link buttons)
1398
+ - `style` โ†’ 1: Primary, 2: Secondary, 3: Success, 4: Danger, 5: Link
1399
+ - `label` โ†’ Button text
1400
+ - `emoji` โ†’ Button emoji
1401
+ - `disabled` โ†’ Disable button (true/false)
1402
+ - `url` โ†’ URL for link buttons (style: 5)
1403
+
1404
+ #### ๐Ÿ”น Menu
1405
+
1406
+ - `type` โ†’ `"menu"`
1407
+ - `components` โ†’ Object containing:
1408
+ - `type` โ†’ `"string" | "user" | "role" | "channel"`
1409
+ - `options` โ†’ Menu configuration:
1410
+ - `id` โ†’ customId
1411
+ - `placeholder` โ†’ Placeholder text
1412
+ - `min` / `max` โ†’ Min/Max selectable values
1413
+ - `data` โ†’ Options array (for string select)
1414
+ - `label` โ†’ Key in data for label
1415
+ - `value` โ†’ Key in data for value
1416
+ - `emoji` โ†’ Key in data for emoji
1417
+ - `description` โ†’ Key in data for description
1418
+ - `channelTypes` โ†’ Channel types filter (for channel menu)
1419
+ - `defaultValues` โ†’ Pre-selected values
1420
+
1421
+ #### ๐Ÿ”น Section
1422
+
1423
+ - `type` โ†’ `"section"`
1424
+ - `content` โ†’ Text content for the section
1425
+ - `accessory` โ†’ Side component:
1426
+ - **Button Accessory:**
1427
+ - `type` โ†’ `"button"`
1428
+ - `id` โ†’ customId
1429
+ - `style` โ†’ Button style
1430
+ - `label` โ†’ Button text
1431
+ - `emoji` โ†’ Button emoji
1432
+ - `url` โ†’ URL (for link buttons)
1433
+ - **Thumbnail Accessory:**
1434
+ - `type` โ†’ `"thumbnail"`
1435
+ - `url` โ†’ Image URL
1436
+ - `description` โ†’ Image description
1437
+
1438
+ ---
1439
+
1440
+ ### ๐Ÿ”น Mode Differences
1441
+
1442
+ | Feature | `"array"` Mode | `"container"` Mode |
1443
+ | ---------------- | ----------------------- | ------------------------- |
1444
+ | Return Type | Array of components | Single ContainerBuilder |
1445
+ | Usage | Standard messages | Components V2 messages |
1446
+ | Sections Support | โœ… | โœ… |
1447
+ | Grouping | Individual components | All grouped in container |
1448
+ | Flags Required | โŒ | โœ… (flags: 32768) |
1449
+
1450
+ ---
1451
+
1452
+ ### ๐Ÿ”น Notes
1453
+
1454
+ - Use `"container"` mode for Discord's **Components V2** (newer UI)
1455
+ - Use `"array"` mode for standard component arrays
1456
+ - Sections can have either a **button** or **thumbnail** as accessory, not both
1457
+ - Media galleries support multiple images in a single component
1458
+ - All components are fully customizable ๐ŸŽจ
1459
+
1460
+ </details>
1461
+
1462
+ ---
1463
+
1464
+ <details>
1465
+ <summary>Wait โฐ</summary>
1466
+
1467
+ **โฐ Wait โ€“ Await messages, buttons, select menus or modals easily โœจ**
1468
+
1469
+ `Wait` is a replacement for traditional collectors. It supports:
1470
+
1471
+ - Awaiting **messages** ๐Ÿ“
1472
+ - Awaiting **interactions** (buttons / select menus) ๐ŸŽ›๏ธ
1473
+ - Awaiting **modal submissions** ๐Ÿ“‹
1474
+ - Filtering by **user** and timeout
1475
+
1476
+ ---
1477
+
1478
+ ### ๐Ÿ“Œ Example Usage:
1479
+
1480
+ ```js
1481
+ const { Wait } = require("djs-builder");
1482
+
1483
+ const response = await Wait({
1484
+ context: message, // Message or Interaction object
1485
+ userId: message.author.id, // Optional: filter by user
1486
+ type: "both", // "message" | "interaction" | "both"
1487
+ time: 30000, // Time in ms
1488
+ message_Wait: message, // Required if waiting for buttons/selects
1489
+ });
1490
+
1491
+ if (!response) return console.log("โฑ๏ธ Timeout!");
1492
+ console.log("โœ… Collected:", response);
1493
+ ```
1494
+
1495
+ ---
1496
+
1497
+ ### ๐Ÿ”น Options
1498
+
1499
+ - `context` โ†’ The message or interaction context
1500
+ - `userId` โ†’ Only collect from this user (optional)
1501
+ - `type` โ†’ `"message" | "interaction" | "both"`
1502
+ - `time` โ†’ Timeout in milliseconds
1503
+ - `message_Wait` โ†’ Message containing buttons/select menus (for interaction/both type)
1504
+
1505
+ ---
1506
+
1507
+ ### ๐Ÿ”น Notes
1508
+
1509
+ - Supports **automatic cleanup** of collectors after completion
1510
+ - Can return **Message**, **Interaction**, or **ModalSubmitInteraction**
1511
+
1512
+ </details>
1513
+
1514
+ ---
1515
+
1516
+ <details>
1517
+ <summary>GetUser ๐Ÿ‘ค</summary>
1518
+
1519
+ **๐Ÿ‘ค GetUser โ€“ Fetch a GuildMember easily from a message โœจ**
1520
+
1521
+ `GetUser` helps to detect a **target member** in multiple ways:
1522
+
1523
+ 1. Mention (`@User`)
1524
+ 2. User ID (`123456789012345678`)
1525
+ 3. Reply to another message
1526
+
1527
+ ---
1528
+
1529
+ ### ๐Ÿ“Œ Example Usage:
1530
+
1531
+ ```js
1532
+ const { GetUser } = require("djs-builder");
1533
+
1534
+ const data = await GetUser(message);
1535
+
1536
+ if (!data) return message.reply("โŒ Could not find the user.");
1537
+
1538
+ const member = data.user; // GuildMember object
1539
+ const args = data.args; // Remaining arguments
1540
+ const reason = args.join(" ") || "No reason provided";
1541
+
1542
+ await member.ban({ reason });
1543
+ message.reply(`๐Ÿšซ ${member.user.tag} was banned for: ${reason}`);
1544
+ ```
1545
+
1546
+ ---
1547
+
1548
+ ### ๐Ÿ”น Returns
1549
+
1550
+ ```js
1551
+ {
1552
+ user: <GuildMember>, // Targeted member
1553
+ args: [ "arg1", "arg2" ] // Remaining message arguments
1554
+ }
1555
+ ```
1556
+
1557
+ ---
1558
+
1559
+ ### ๐Ÿ”น Detection Methods
1560
+
1561
+ - **Mention:** `!ban @Ahmed Spamming`
1562
+ - **User ID:** `!ban 123456789012345678 Spamming`
1563
+ - **Reply:** `Reply to user's message with !ban`
1564
+
1565
+ ---
1566
+
1567
+ ### ๐Ÿ”น Notes
1568
+
1569
+ - Automatically handles missing users
1570
+ - Returns `null` if user not found
1571
+ - Works in any text channel of the guild
1572
+
1573
+ </details>
1574
+
1575
+ ---
1576
+
1577
+ <details>
1578
+ <summary>Logging System ๐Ÿ›ก๏ธ</summary>
1579
+
1580
+ ## ๐Ÿ›ก๏ธ Logging System โ€“ Track Everything in Your Server
1581
+
1582
+ The **Logging System** is a powerful feature that keeps track of almost everything happening inside your Discord server ๐Ÿ”.
1583
+ From **messages** ๐Ÿ“ to **channels** ๐Ÿ“‚, **roles** ๐ŸŽญ, **invites** ๐Ÿ”—, and even **voice state changes** ๐ŸŽ™๏ธ โ€“ nothing goes unnoticed!
1584
+
1585
+ > **Note 1**: Using `database: true` requires a **MongoDB** connection. | **Note 2**: You can import the **Log** model for direct database access ๐Ÿ’พ.
1586
+
1587
+ ---
1588
+
1589
+ ### ๐Ÿ“ฆ Module Exports
1590
+
1591
+ ```js
1592
+ const { log, Log } = require("djs-builder");
1593
+ ```
1594
+
1595
+ - `log(client, options)` โ†’ Start the logging system with your configuration ๐Ÿš€.
1596
+ - `Log` โ†’ The Mongoose model for direct database access and custom modifications ๐Ÿ’พ.
1597
+
1598
+ ---
1599
+
1600
+ ### ๐Ÿ“‹ Simple Example
1601
+
1602
+ ```js
1603
+ const { log } = require("djs-builder");
1604
+
1605
+ module.exports = {
1606
+ name: "clientReady",
1607
+ async run(client) {
1608
+ const logData = [
1609
+ {
1610
+ guildId: "999888777666555444",
1611
+ channelId: "444555666777888999",
1612
+ },
1613
+
1614
+ {
1615
+ guildId: "999888777666555444",
1616
+ channelId: "444555666777888999",
1617
+ },
1618
+ ];
1619
+
1620
+ // Start logging with custom data
1621
+ await log(client, {
1622
+ Data: logData, // ๐Ÿ“Š Your configurations
1623
+ });
1624
+
1625
+ console.log("โœ… Logging system started with custom data!");
1626
+ },
1627
+ };
1628
+ ```
1629
+
1630
+ ---
1631
+
1632
+ ### โœจ Features
1633
+
1634
+ - ๐Ÿ“ **Messages** โ€“ Deleted & edited messages are logged with details.
1635
+ - ๐Ÿ“‚ **Channels** โ€“ Creation, deletion, and updates are tracked.
1636
+ - ๐ŸŽญ **Roles** โ€“ Created, deleted, and updated roles, including member role changes.
1637
+ - ๐ŸŽ™๏ธ **Voice State** โ€“ Joins, leaves, and moves between channels.
1638
+ - ๐Ÿ”— **Invites** โ€“ Created invites & usage tracking.
1639
+ - ๐Ÿ˜€ **Emojis & Stickers** โ€“ Added, removed, or updated.
1640
+ - ๐Ÿ‘ค **Members** โ€“ Join, leave, kick, ban, and unban events.
1641
+ - ๐Ÿšจ **Audit Log Integration** โ€“ Fetches the executor (who did what).
1642
+ - ๐ŸŽจ **Beautiful Embeds** โ€“ Every log is shown in a clean, styled embed with timestamps.
1643
+ - ๐Ÿ—„๏ธ **Caching System** โ€“ Fast performance with built-in data caching.
1644
+
1645
+ ---
1646
+
1647
+ ### ๐Ÿ“Š Database Schema
1648
+
1649
+ The logging system uses the following data structure:
1650
+
1651
+ ```js
1652
+ {
1653
+ guildId: String, // ๐Ÿ  Server ID (required)
1654
+ channelId: String, // ๐Ÿ“ข Default log channel ID
1655
+ channels: Object, // ๐Ÿ“‚ Custom channels per event type (optional)
1656
+ colors: Object, // ๐ŸŽจ Custom colors per event type (optional)
1657
+ disable: Array, // ๐Ÿšซ Array of disabled event types (optional)
1658
+ }
1659
+ ```
1660
+
1661
+ ---
1662
+
1663
+ <details>
1664
+ <summary>๐Ÿ“‹ Supported Event Types</summary>
1665
+
1666
+ ### ๐Ÿ“‹ Supported Event Types
1667
+
1668
+ | Event Type | Description |
1669
+ | ------------------- | ------------------------- |
1670
+ | `messageDelete` | Message deleted ๐Ÿ“ |
1671
+ | `messageUpdate` | Message edited โœ๏ธ |
1672
+ | `channelCreate` | Channel created ๐Ÿ“ |
1673
+ | `channelDelete` | Channel deleted ๐Ÿ—‘๏ธ |
1674
+ | `channelUpdate` | Channel updated โš™๏ธ |
1675
+ | `guildMemberAdd` | Member joined ๐ŸŽ‰ |
1676
+ | `guildMemberRemove` | Member left/kicked ๐Ÿšช |
1677
+ | `guildBanAdd` | Member banned ๐Ÿ”จ |
1678
+ | `guildBanRemove` | Member unbanned ๐Ÿค— |
1679
+ | `roleCreate` | Role created ๐Ÿ… |
1680
+ | `roleDelete` | Role deleted โŒ |
1681
+ | `roleUpdate` | Role updated ๐Ÿ”„ |
1682
+ | `guildMemberUpdate` | Member roles changed ๐Ÿ‘ค |
1683
+ | `voiceStateUpdate` | Voice channel activity ๐ŸŽค |
1684
+ | `inviteCreate` | Invite created ๐Ÿ”— |
1685
+ | `emojiCreate` | Emoji added ๐Ÿ˜€ |
1686
+ | `emojiDelete` | Emoji removed ๐Ÿšซ |
1687
+ | `emojiUpdate` | Emoji updated ๐Ÿ”„ |
1688
+ | `stickerCreate` | Sticker added โœจ |
1689
+ | `stickerDelete` | Sticker removed ๐Ÿ—‘๏ธ |
1690
+ | `stickerUpdate` | Sticker updated ๐ŸŒ€ |
1691
+
1692
+ </details>
1693
+
1694
+ ---
1695
+
1696
+ <details>
1697
+ <summary>โšก Method Using Database (Recommended) ๐Ÿ—„๏ธ</summary>
1698
+
1699
+ ### ๐Ÿ—„๏ธ Using MongoDB Database
1700
+
1701
+ This method stores log configuration in MongoDB, allowing dynamic management via commands.
1702
+
1703
+ **โšก Setup in `clientReady` Event:**
1704
+
1705
+ ```js
1706
+ const { log } = require("djs-builder");
1707
+
1708
+ module.exports = {
1709
+ name: "clientReady",
1710
+ async run(client) {
1711
+ // Start logging with database mode
1712
+ await log(client, {
1713
+ database: true, // ๐Ÿ—„๏ธ Uses MongoDB to store/fetch config
1714
+ });
1715
+
1716
+ console.log("โœ… Logging system started with database mode!");
1717
+ },
1718
+ };
1719
+ ```
1720
+
1721
+ ---
1722
+
1723
+ ### ๐Ÿ’ก How It Works
1724
+
1725
+ - โœ… The system automatically fetches log configuration for each guild from MongoDB.
1726
+ - ๐Ÿ› ๏ธ You can manage settings via slash commands (see management command below).
1727
+ - ๐ŸŽจ Supports per-guild customization for channels, colors, and disabled events.
1728
+ - ๐Ÿ“– **Important**: If you use database mode, see the [Log Management Command](#-slash-command-for-log-management-) below to edit data.
1729
+
1730
+ </details>
1731
+
1732
+ ---
1733
+
1734
+ <details>
1735
+ <summary>โšก Method Using Custom Data Array ๐Ÿ“‹</summary>
1736
+
1737
+ ### ๐Ÿ“‹ Using Custom Data Array
1738
+
1739
+ This method uses a predefined array of configurations โ€“ perfect for simple setups or testing.
1740
+
1741
+ **โšก Setup in `clientReady` Event:**
1742
+
1743
+
1744
+
1745
+
1746
+ ```js
1747
+ const { log } = require("djs-builder");
1748
+
1749
+ module.exports = {
1750
+ name: "clientReady",
1751
+ async run(client) {
1752
+ // Define your log configurations
1753
+ const logData = [
1754
+ {
1755
+ guildId: "123456789012345678", // ๐Ÿ  Server ID
1756
+ channelId: "987654321098765432", // ๐Ÿ“ข Default log channel
1757
+ channels: {
1758
+ // ๐Ÿ“‚ Custom channels (optional)
1759
+ messageDelete: "111111111111111111",
1760
+ voiceStateUpdate: "222222222222222222",
1761
+ },
1762
+ colors: {
1763
+ // ๐ŸŽจ Custom colors (optional)
1764
+ messageDelete: "DarkRed",
1765
+ channelCreate: "DarkGreen",
1766
+ },
1767
+ disable: ["inviteCreate"], // ๐Ÿšซ Disabled events (optional)
1768
+ },
1769
+ // Add more guild configurations...
1770
+ {
1771
+ guildId: "999888777666555444",
1772
+ channelId: "444555666777888999",
1773
+ },
1774
+ ];
1775
+
1776
+ // Start logging with custom data
1777
+ await log(client, {
1778
+ database: false, // ๐Ÿ“‹ Uses custom array
1779
+ Data: logData, // ๐Ÿ“Š Your configurations
1780
+ });
1781
+
1782
+ console.log("โœ… Logging system started with custom data!");
1783
+ },
1784
+ };
1785
+ ```
1786
+
1787
+ ---
1788
+
1789
+ ### ๐ŸŽจ Supported Colors
1790
+
1791
+ `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`.
1792
+
1793
+ ---
1794
+
1795
+ ### ๐ŸŒ Multi-Guild Support
1796
+
1797
+ > ๐Ÿ’ก **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!
1798
+
1799
+ </details>
1800
+
1801
+ ---
1802
+
1803
+ <details>
1804
+ <summary>๐Ÿ”ง Direct Database Access with Log Model ๐Ÿ’พ</summary>
1805
+
1806
+ ### ๐Ÿ’พ Using the Log Model Directly
1807
+
1808
+ You can import the `Log` Mongoose model to create, update, or delete log configurations programmatically.
1809
+
1810
+ **๐Ÿ“ฅ Import the Model:**
1811
+
1812
+ ```js
1813
+ const { Log } = require("djs-builder");
1814
+ ```
1815
+
1816
+ **โž• Create New Configuration:**
1817
+
1818
+ ```js
1819
+ const { Log } = require("djs-builder");
1820
+
1821
+ // Create a new log configuration for a guild
1822
+ const newConfig = await Log.create({
1823
+ guildId: "123456789012345678",
1824
+ channelId: "987654321098765432",
1825
+ channels: {
1826
+ messageDelete: "111111111111111111",
1827
+ },
1828
+ colors: {
1829
+ messageDelete: "Red",
1830
+ },
1831
+ disable: [],
1832
+ });
1833
+
1834
+ console.log("โœ… Log configuration created!", newConfig);
1835
+ ```
1836
+
1837
+ **โœ๏ธ Update Existing Configuration:**
354
1838
 
355
1839
  ```js
356
- console.log(
357
- CreateBar(6, 10, {
358
- length: 12,
359
- fill: "๐Ÿ”ฅ",
360
- empty: "โ„๏ธ",
361
- partialChar: "๐ŸŒŸ",
362
- showPercent: true,
363
- left: "ยซ",
364
- right: "ยป",
365
- })
1840
+ const { Log } = require("djs-builder");
1841
+
1842
+ // Update log channel
1843
+ await Log.findOneAndUpdate(
1844
+ { guildId: "123456789012345678" },
1845
+ { channelId: "NEW_CHANNEL_ID" },
1846
+ { upsert: true } // Create if doesn't exist
366
1847
  );
367
1848
 
368
- // Output: ยซ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐ŸŒŸโ„๏ธโ„๏ธโ„๏ธโ„๏ธยป 60%
369
- ```
1849
+ // Add event to disable list
1850
+ await Log.findOneAndUpdate(
1851
+ { guildId: "123456789012345678" },
1852
+ { $push: { disable: "voiceStateUpdate" } }
1853
+ );
370
1854
 
371
- ---
1855
+ // Remove event from disable list
1856
+ await Log.findOneAndUpdate(
1857
+ { guildId: "123456789012345678" },
1858
+ { $pull: { disable: "voiceStateUpdate" } }
1859
+ );
372
1860
 
373
- ### ๐Ÿ”น Options Summary
1861
+ // Update specific channel for an event
1862
+ await Log.findOneAndUpdate(
1863
+ { guildId: "123456789012345678" },
1864
+ { $set: { "channels.messageDelete": "NEW_CHANNEL_ID" } }
1865
+ );
374
1866
 
375
- - `length` โ†’ Total number of symbols
376
- - `fill` โ†’ Symbol for filled portion
377
- - `empty` โ†’ Symbol for empty portion
378
- - `partialChar` โ†’ Symbol for partial fill (e.g., half-filled)
379
- - `showPercent` โ†’ Show percentage at the end
380
- - `left` / `right` โ†’ Brackets or edges for the bar
1867
+ // Update specific color for an event
1868
+ await Log.findOneAndUpdate(
1869
+ { guildId: "123456789012345678" },
1870
+ { $set: { "colors.messageDelete": "DarkRed" } }
1871
+ );
1872
+ ```
381
1873
 
382
- ---
1874
+ **๐Ÿ—‘๏ธ Delete Configuration:**
383
1875
 
384
- ### ๐Ÿ”น Notes
1876
+ ```js
1877
+ const { Log } = require("djs-builder");
385
1878
 
386
- - Supports **fractional values** for partial fill
387
- - Fully **customizable with any emoji or character** ๐ŸŽจ
388
- - Great for **progress, stats, experience bars, or loading indicators**
1879
+ await Log.findOneAndDelete({ guildId: "123456789012345678" });
1880
+ console.log("๐Ÿ—‘๏ธ Log configuration deleted!");
1881
+ ```
389
1882
 
390
- ---
1883
+ **๐Ÿ“Š Fetch Configuration:**
1884
+
1885
+ ```js
1886
+ const { Log } = require("djs-builder");
1887
+
1888
+ const config = await Log.findOne({ guildId: "123456789012345678" });
1889
+ if (config) {
1890
+ console.log("๐Ÿ“ข Log Channel:", config.channelId);
1891
+ console.log("๐Ÿ“‚ Custom Channels:", config.channels);
1892
+ console.log("๐ŸŽจ Custom Colors:", config.colors);
1893
+ console.log("๐Ÿšซ Disabled Events:", config.disable);
1894
+ }
1895
+ ```
391
1896
 
392
1897
  </details>
393
1898
 
394
1899
  ---
395
1900
 
396
1901
  <details>
397
- <summary>Wait โฐ</summary>
1902
+ <summary>๐ŸŒ Dashboard Integration โ€“ Manage Logs from Web Panel ๐Ÿ–ฅ๏ธ</summary>
398
1903
 
399
- **โฐ Wait โ€“ Await messages, buttons, select menus or modals easily โœจ**
400
-
401
- `Wait` is a replacement for traditional collectors. It supports:
1904
+ ### ๐Ÿ–ฅ๏ธ Web Dashboard for Log Management
402
1905
 
403
- - Awaiting **messages** ๐Ÿ“
404
- - Awaiting **interactions** (buttons / select menus) ๐ŸŽ›๏ธ
405
- - Awaiting **modal submissions** ๐Ÿ“‹
406
- - Filtering by **user** and timeout
1906
+ When you use **database mode** (`database: true`), you can manage the logging system directly from the **djs-builder Dashboard**! ๐ŸŽ›๏ธ
407
1907
 
408
1908
  ---
409
1909
 
410
- ### ๐Ÿ“Œ Example Usage:
1910
+ #### โœจ Dashboard Features for Logs
411
1911
 
412
- ```js
413
- const { Wait } = require("djs-builder");
1912
+ | Feature | Description |
1913
+ | ---------------------- | -------------------------------------------- |
1914
+ | ๐Ÿ“ข **Default Channel** | Set the main channel for all logs |
1915
+ | ๐Ÿ“‚ **Custom Channels** | Assign specific channels for each event type |
1916
+ | ๐ŸŽจ **Custom Colors** | Choose embed colors for each event type |
1917
+ | ๐Ÿ”„ **Toggle Events** | Enable/Disable specific event types |
1918
+ | ๐Ÿ“Š **Statistics** | View enabled/disabled events count |
1919
+ | ๐Ÿ—‘๏ธ **Reset** | Clear all log settings with one click |
414
1920
 
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
- });
1921
+ ---
422
1922
 
423
- if (!response) return console.log("โฑ๏ธ Timeout!");
424
- console.log("โœ… Collected:", response);
425
- ```
1923
+ #### ๐Ÿš€ How to Access
1924
+
1925
+ 1. Navigate to your dashboard (e.g., `http://localhost:3000`)
1926
+ 2. Log in with Discord OAuth2
1927
+ 3. Select a server
1928
+ 4. Click on **"ุณุฌู„ุงุช ุงู„ู…ุฑุงู‚ุจุฉ"** (Logs) in the sidebar
426
1929
 
427
1930
  ---
428
1931
 
429
- ### ๐Ÿ”น Options
1932
+ #### โš ๏ธ Important Notes
430
1933
 
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)
1934
+ **When `database: true`:**
436
1935
 
437
- ---
1936
+ - โœ… Full editing capabilities from dashboard
1937
+ - โœ… Changes are saved automatically to MongoDB
1938
+ - โœ… Real-time updates
438
1939
 
439
- ### ๐Ÿ”น Notes
1940
+ **When `database: false` (Custom Data Array):**
440
1941
 
441
- - Supports **automatic cleanup** of collectors after completion
442
- - Can return **Message**, **Interaction**, or **ModalSubmitInteraction**
1942
+ - โš ๏ธ Dashboard shows **read-only** mode
1943
+ - โš ๏ธ A warning banner appears at the top
1944
+ - โš ๏ธ You must edit settings in your code
443
1945
 
444
1946
  </details>
445
1947
 
446
1948
  ---
447
1949
 
448
1950
  <details>
449
- <summary>GetUser ๐Ÿ‘ค</summary>
1951
+ <summary>๐ŸŽฎ Slash Command for Log Management ๐Ÿ› ๏ธ</summary>
450
1952
 
451
- **๐Ÿ‘ค GetUser โ€“ Fetch a GuildMember easily from a message โœจ**
1953
+ ### ๐Ÿ› ๏ธ Complete Log Management Slash Command
452
1954
 
453
- `GetUser` helps to detect a **target member** in multiple ways:
1955
+ This command allows server administrators to manage the logging system via Discord.
454
1956
 
455
- 1. Mention (`@User`)
456
- 2. User ID (`123456789012345678`)
457
- 3. Reply to another message
1957
+ > โš ๏ธ **Important**: This command requires `database: true` mode to work properly.
458
1958
 
459
- ---
1959
+ ```js
1960
+ const { Log, getLogConfigData } = require("djs-builder");
1961
+ const {
1962
+ SlashCommandBuilder,
1963
+ PermissionFlagsBits,
1964
+ EmbedBuilder,
1965
+ ChannelType,
1966
+ } = require("discord.js");
460
1967
 
461
- ### ๐Ÿ“Œ Example Usage:
1968
+ // All supported event types (21 events)
1969
+ const EVENT_TYPES = [
1970
+ { name: "Message Delete", value: "messageDelete" },
1971
+ { name: "Message Update", value: "messageUpdate" },
1972
+ { name: "Channel Create", value: "channelCreate" },
1973
+ { name: "Channel Delete", value: "channelDelete" },
1974
+ { name: "Channel Update", value: "channelUpdate" },
1975
+ { name: "Member Join", value: "guildMemberAdd" },
1976
+ { name: "Member Leave", value: "guildMemberRemove" },
1977
+ { name: "Member Ban", value: "guildBanAdd" },
1978
+ { name: "Member Unban", value: "guildBanRemove" },
1979
+ { name: "Role Create", value: "roleCreate" },
1980
+ { name: "Role Delete", value: "roleDelete" },
1981
+ { name: "Role Update", value: "roleUpdate" },
1982
+ { name: "Member Role Update", value: "guildMemberUpdate" },
1983
+ { name: "Voice State", value: "voiceStateUpdate" },
1984
+ { name: "Invite Create", value: "inviteCreate" },
1985
+ { name: "Emoji Create", value: "emojiCreate" },
1986
+ { name: "Emoji Delete", value: "emojiDelete" },
1987
+ { name: "Emoji Update", value: "emojiUpdate" },
1988
+ { name: "Sticker Create", value: "stickerCreate" },
1989
+ { name: "Sticker Delete", value: "stickerDelete" },
1990
+ { name: "Sticker Update", value: "stickerUpdate" },
1991
+ ];
1992
+
1993
+ // Helper function to clear cache after updates
1994
+ function clearLogCache(guildId) {
1995
+ const logData = getLogConfigData();
1996
+ if (logData.clearCache) logData.clearCache(guildId);
1997
+ }
462
1998
 
463
- ```js
464
- const { GetUser } = require("djs-builder");
1999
+ module.exports = {
2000
+ data: new SlashCommandBuilder()
2001
+ .setName("logs")
2002
+ .setDescription("๐Ÿ›ก๏ธ Manage the server logging system")
2003
+ .setDefaultMemberPermissions(PermissionFlagsBits.Administrator)
2004
+ .addSubcommand((sub) =>
2005
+ sub
2006
+ .setName("setup")
2007
+ .setDescription("๐Ÿ“ข Set up the default log channel")
2008
+ .addChannelOption((opt) =>
2009
+ opt
2010
+ .setName("channel")
2011
+ .setDescription("The channel to send logs to")
2012
+ .addChannelTypes(ChannelType.GuildText)
2013
+ .setRequired(true)
2014
+ )
2015
+ )
2016
+ .addSubcommand((sub) =>
2017
+ sub
2018
+ .setName("channel")
2019
+ .setDescription("๐Ÿ“‚ Set a specific channel for an event type")
2020
+ .addStringOption((opt) =>
2021
+ opt
2022
+ .setName("event")
2023
+ .setDescription("The event type")
2024
+ .setRequired(true)
2025
+ .addChoices(...EVENT_TYPES)
2026
+ )
2027
+ .addChannelOption((opt) =>
2028
+ opt
2029
+ .setName("channel")
2030
+ .setDescription("The channel for this event")
2031
+ .addChannelTypes(ChannelType.GuildText)
2032
+ .setRequired(true)
2033
+ )
2034
+ )
2035
+ .addSubcommand((sub) =>
2036
+ sub
2037
+ .setName("color")
2038
+ .setDescription("๐ŸŽจ Set a custom color for an event type")
2039
+ .addStringOption((opt) =>
2040
+ opt
2041
+ .setName("event")
2042
+ .setDescription("The event type")
2043
+ .setRequired(true)
2044
+ .addChoices(...EVENT_TYPES)
2045
+ )
2046
+ .addStringOption((opt) =>
2047
+ opt
2048
+ .setName("color")
2049
+ .setDescription("Color name or hex code (e.g., Red, #FF5733)")
2050
+ .setRequired(true)
2051
+ )
2052
+ )
2053
+ .addSubcommand((sub) =>
2054
+ sub
2055
+ .setName("toggle")
2056
+ .setDescription("๐Ÿ”„ Enable or disable an event type")
2057
+ .addStringOption((opt) =>
2058
+ opt
2059
+ .setName("event")
2060
+ .setDescription("The event type")
2061
+ .setRequired(true)
2062
+ .addChoices(...EVENT_TYPES)
2063
+ )
2064
+ .addStringOption((opt) =>
2065
+ opt
2066
+ .setName("action")
2067
+ .setDescription("Enable or disable")
2068
+ .setRequired(true)
2069
+ .addChoices(
2070
+ { name: "Enable", value: "enable" },
2071
+ { name: "Disable", value: "disable" }
2072
+ )
2073
+ )
2074
+ )
2075
+ .addSubcommand((sub) =>
2076
+ sub.setName("view").setDescription("๐Ÿ“Š View current log configuration")
2077
+ )
2078
+ .addSubcommand((sub) =>
2079
+ sub
2080
+ .setName("reset")
2081
+ .setDescription("๐Ÿ—‘๏ธ Reset all log settings for this server")
2082
+ ),
465
2083
 
466
- const data = await GetUser(message);
2084
+ async run(client, interaction) {
2085
+ await interaction.deferReply({ ephemeral: true });
467
2086
 
468
- if (!data) return message.reply("โŒ Could not find the user.");
2087
+ const subcommand = interaction.options.getSubcommand();
2088
+ const guildId = interaction.guild.id;
469
2089
 
470
- const member = data.user; // GuildMember object
471
- const args = data.args; // Remaining arguments
472
- const reason = args.join(" ") || "No reason provided";
2090
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
2091
+ // ๐Ÿ“ข SETUP - Set default log channel
2092
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
2093
+ if (subcommand === "setup") {
2094
+ const channel = interaction.options.getChannel("channel");
473
2095
 
474
- await member.ban({ reason });
475
- message.reply(`๐Ÿšซ ${member.user.tag} was banned for: ${reason}`);
476
- ```
2096
+ await Log.findOneAndUpdate(
2097
+ { guildId },
2098
+ { guildId, channelId: channel.id },
2099
+ { upsert: true, new: true }
2100
+ );
477
2101
 
478
- ---
2102
+ clearLogCache(guildId); // Clear cache to apply changes immediately
479
2103
 
480
- ### ๐Ÿ”น Returns
2104
+ const embed = new EmbedBuilder()
2105
+ .setTitle("โœ… Logging System Setup")
2106
+ .setDescription(`Logs will now be sent to ${channel}`)
2107
+ .setColor("Green")
2108
+ .setTimestamp();
481
2109
 
482
- ```js
483
- {
484
- user: <GuildMember>, // Targeted member
485
- args: [ "arg1", "arg2" ] // Remaining message arguments
486
- }
487
- ```
2110
+ return interaction.editReply({ embeds: [embed] });
2111
+ }
488
2112
 
489
- ---
2113
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
2114
+ // ๐Ÿ“‚ CHANNEL - Set specific channel for event
2115
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
2116
+ if (subcommand === "channel") {
2117
+ const event = interaction.options.getString("event");
2118
+ const channel = interaction.options.getChannel("channel");
2119
+
2120
+ await Log.findOneAndUpdate(
2121
+ { guildId },
2122
+ { $set: { [`channels.${event}`]: channel.id } },
2123
+ { upsert: true }
2124
+ );
490
2125
 
491
- ### ๐Ÿ”น Detection Methods
2126
+ clearLogCache(guildId);
492
2127
 
493
- - **Mention:** `!ban @Ahmed Spamming`
494
- - **User ID:** `!ban 123456789012345678 Spamming`
495
- - **Reply:** `Reply to user's message with !ban`
2128
+ const eventName =
2129
+ EVENT_TYPES.find((e) => e.value === event)?.name || event;
2130
+ const embed = new EmbedBuilder()
2131
+ .setTitle("๐Ÿ“‚ Event Channel Updated")
2132
+ .setDescription(`**${eventName}** logs will now be sent to ${channel}`)
2133
+ .setColor("Blue")
2134
+ .setTimestamp();
496
2135
 
497
- ---
2136
+ return interaction.editReply({ embeds: [embed] });
2137
+ }
498
2138
 
499
- ### ๐Ÿ”น Notes
2139
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
2140
+ // ๐ŸŽจ COLOR - Set custom color for event
2141
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
2142
+ if (subcommand === "color") {
2143
+ const event = interaction.options.getString("event");
2144
+ const color = interaction.options.getString("color");
2145
+
2146
+ await Log.findOneAndUpdate(
2147
+ { guildId },
2148
+ { $set: { [`colors.${event}`]: color } },
2149
+ { upsert: true }
2150
+ );
500
2151
 
501
- - Automatically handles missing users
502
- - Returns `null` if user not found
503
- - Works in any text channel of the guild
2152
+ clearLogCache(guildId);
2153
+
2154
+ const eventName =
2155
+ EVENT_TYPES.find((e) => e.value === event)?.name || event;
2156
+
2157
+ // Try to use the color, fallback to Blue if invalid
2158
+ let embedColor;
2159
+ try {
2160
+ embedColor = color;
2161
+ } catch {
2162
+ embedColor = "Blue";
2163
+ }
504
2164
 
505
- </details>
2165
+ const embed = new EmbedBuilder()
2166
+ .setTitle("๐ŸŽจ Event Color Updated")
2167
+ .setDescription(
2168
+ `**${eventName}** embeds will now use color: \`${color}\``
2169
+ )
2170
+ .setColor(embedColor)
2171
+ .setTimestamp();
506
2172
 
507
- ---
2173
+ return interaction.editReply({ embeds: [embed] });
2174
+ }
508
2175
 
509
- <details>
510
- <summary>Logging System ๐Ÿ›ก๏ธ</summary>
2176
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
2177
+ // ๐Ÿ”„ TOGGLE - Enable/Disable event
2178
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
2179
+ if (subcommand === "toggle") {
2180
+ const event = interaction.options.getString("event");
2181
+ const action = interaction.options.getString("action");
2182
+
2183
+ if (action === "disable") {
2184
+ await Log.findOneAndUpdate(
2185
+ { guildId },
2186
+ { $addToSet: { disable: event } },
2187
+ { upsert: true }
2188
+ );
2189
+ } else {
2190
+ await Log.findOneAndUpdate(
2191
+ { guildId },
2192
+ { $pull: { disable: event } },
2193
+ { upsert: true }
2194
+ );
2195
+ }
511
2196
 
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!
2197
+ clearLogCache(guildId);
514
2198
 
515
- ---
2199
+ const eventName =
2200
+ EVENT_TYPES.find((e) => e.value === event)?.name || event;
2201
+ const embed = new EmbedBuilder()
2202
+ .setTitle(
2203
+ action === "disable" ? "๐Ÿšซ Event Disabled" : "โœ… Event Enabled"
2204
+ )
2205
+ .setDescription(`**${eventName}** logging has been ${action}d`)
2206
+ .setColor(action === "disable" ? "Red" : "Green")
2207
+ .setTimestamp();
516
2208
 
517
- ### โœจ Features
2209
+ return interaction.editReply({ embeds: [embed] });
2210
+ }
518
2211
 
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.
2212
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
2213
+ // ๐Ÿ“Š VIEW - Show current configuration
2214
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
2215
+ if (subcommand === "view") {
2216
+ const config = await Log.findOne({ guildId });
527
2217
 
528
- ---
2218
+ if (!config) {
2219
+ return interaction.editReply({
2220
+ content:
2221
+ "โŒ No logging configuration found for this server. Use `/logs setup` first!",
2222
+ });
2223
+ }
529
2224
 
530
- ### โš™๏ธ Setup Example
2225
+ const channelsList = config.channels
2226
+ ? Object.entries(config.channels)
2227
+ .map(([k, v]) => {
2228
+ const eventName = EVENT_TYPES.find((e) => e.value === k)?.name || k;
2229
+ return `โ€ข **${eventName}**: <#${v}>`;
2230
+ })
2231
+ .join("\n") || "None"
2232
+ : "None";
2233
+
2234
+ const colorsList = config.colors
2235
+ ? Object.entries(config.colors)
2236
+ .map(([k, v]) => {
2237
+ const eventName = EVENT_TYPES.find((e) => e.value === k)?.name || k;
2238
+ return `โ€ข **${eventName}**: \`${v}\``;
2239
+ })
2240
+ .join("\n") || "None"
2241
+ : "None";
2242
+
2243
+ const disabledList =
2244
+ config.disable?.length > 0
2245
+ ? config.disable.map((e) => {
2246
+ const eventName = EVENT_TYPES.find((ev) => ev.value === e)?.name || e;
2247
+ return `โ€ข ${eventName}`;
2248
+ }).join("\n")
2249
+ : "None";
2250
+
2251
+ const enabledCount = EVENT_TYPES.length - (config.disable?.length || 0);
2252
+
2253
+ const embed = new EmbedBuilder()
2254
+ .setTitle("๐Ÿ“Š Log Configuration")
2255
+ .setDescription(`**${enabledCount}/${EVENT_TYPES.length}** events are enabled`)
2256
+ .setColor("Blue")
2257
+ .addFields(
2258
+ {
2259
+ name: "๐Ÿ“ข Default Channel",
2260
+ value: config.channelId ? `<#${config.channelId}>` : "Not set",
2261
+ inline: true,
2262
+ },
2263
+ {
2264
+ name: "๐Ÿ“‚ Custom Channels",
2265
+ value: channelsList.slice(0, 1024) || "None",
2266
+ inline: false,
2267
+ },
2268
+ {
2269
+ name: "๐ŸŽจ Custom Colors",
2270
+ value: colorsList.slice(0, 1024) || "None",
2271
+ inline: false,
2272
+ },
2273
+ {
2274
+ name: "๐Ÿšซ Disabled Events",
2275
+ value: disabledList.slice(0, 1024) || "None",
2276
+ inline: false,
2277
+ }
2278
+ )
2279
+ .setFooter({ text: `Guild ID: ${guildId}` })
2280
+ .setTimestamp();
531
2281
 
532
- Using the `log` function is very simple โšก.
533
- Just place this code inside an event (like `clientReady`) to start logging:
2282
+ return interaction.editReply({ embeds: [embed] });
2283
+ }
534
2284
 
535
- ```js
536
- const { log } = require("djs-builder");
2285
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
2286
+ // ๐Ÿ—‘๏ธ RESET - Delete all configuration
2287
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
2288
+ if (subcommand === "reset") {
2289
+ await Log.findOneAndDelete({ guildId });
2290
+
2291
+ clearLogCache(guildId);
537
2292
 
538
- 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
- );
2293
+ const embed = new EmbedBuilder()
2294
+ .setTitle("๐Ÿ—‘๏ธ Configuration Reset")
2295
+ .setDescription(
2296
+ "All logging settings have been deleted for this server."
2297
+ )
2298
+ .setColor("Red")
2299
+ .setTimestamp();
2300
+
2301
+ return interaction.editReply({ embeds: [embed] });
2302
+ }
546
2303
  },
547
2304
  };
548
2305
  ```
549
2306
 
2307
+ </details>
2308
+
550
2309
  ---
551
2310
 
552
- ### ๐Ÿ’ก How It Works
2311
+ ### ๐Ÿ’ก Tips & Notes
553
2312
 
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!
2313
+ - ๐Ÿ”„ **Caching**: The system caches guild configurations for better performance.
2314
+ - ๐Ÿ” **Permissions**: Make sure your bot has `View Audit Log` permission for full functionality.
2315
+ - ๐Ÿ“ข **Invite Tracking**: Uses `discord-inviter` package for accurate invite tracking.
2316
+ - ๐ŸŽจ **Default Colors**: Each event type has sensible default colors if not customized.
2317
+ - ๐Ÿšซ **Disabled Events**: Events in the `disable` array will be completely ignored.
2318
+ - ๐Ÿ“‚ **Channel Fallback**: If no specific channel is set for an event, it uses `channelId`.
2319
+ - ๐Ÿ’พ **Database Mode**: Recommended for multi-server bots with dynamic configuration needs.
2320
+ - ๐ŸŒ **Dashboard Integration**: When using database mode, you can manage logs via the web dashboard!
2321
+
2322
+ ---
557
2323
 
558
2324
  </details>
559
2325
 
@@ -809,55 +2575,54 @@ const { Gstart } = require("djs-builder");
809
2575
  const { EmbedBuilder } = require("discord.js");
810
2576
 
811
2577
  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,
2578
+ name: "gstart",
2579
+ description: "Starts a new highly-customized giveaway.",
2580
+ run: async (client, message, args) => {
2581
+ // โฐ Giveaway ends in 48 hours
2582
+ const twoDays = Date.now() + 48 * 60 * 60 * 1000;
2583
+ const channelId = "YOUR_GIVEAWAY_CHANNEL_ID"; // ๐Ÿ“ข Target Channel
824
2584
 
825
- // ๐ŸŽจ Customization for the STARTING EMBED
826
- ย  ย  ย  embed: {
2585
+ await Gstart({
2586
+ context: message,
2587
+ endTime: twoDays,
2588
+ winers: 5, // 5 lucky winners! ๐Ÿ†
2589
+ channelId: channelId,
827
2590
 
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
- ย  ย  ย  },
2591
+ // ๐ŸŽจ Customization for the STARTING EMBED
2592
+ embed: {
2593
+ custom: new EmbedBuilder().setTitle("Raw Embed"), // ๐Ÿ’ก You can use 'custom' to pass a raw Discord.js EmbedBuilder JSON
2594
+ title: "๐ŸŽ‰ **HUGE SERVER BOOST GIVEAWAY!**",
2595
+ description:
2596
+ "Click the button below to enter for a chance to win a free server boost!",
2597
+ color: "Blue", // Any valid Discord color
2598
+ image: "https://yourimage.com/banner.png", // image URL
2599
+ thumbnail: message.guild.iconURL(),
2600
+ },
835
2601
 
836
2602
  // ๐Ÿ›‘ 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
- ย  ย  ย  },
2603
+ endEmbed: {
2604
+ custom: new EmbedBuilder().setTitle("Raw Embed"), // ๐Ÿ’ก You can use 'custom' to pass a raw Discord.js EmbedBuilder JSON
2605
+ title: "๐Ÿ›‘ Giveaway Has Concluded!",
2606
+ description: "Congratulations to the winners! Check the message below.",
2607
+ color: "Green", // Eimage and Ethumbnail can also be set here
2608
+ },
844
2609
 
845
2610
  // ๐Ÿ–ฑ๏ธ 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
- ย  ย  ย  },
2611
+ reaction: {
2612
+ type: "button", // Use 'reaction' for an emoji reaction
2613
+ emoji: "โœ…", // The emoji displayed on the button
2614
+ label: "Enter Giveaway!", // The text label
2615
+ style: 3, // Button style: Primary(1), Secondary(2), Success(3), Danger(4)
2616
+ id: "djs-builder-giveaway", // Custom ID for the button
2617
+ },
853
2618
 
854
2619
  // ๐Ÿ”’ Requirements (Optional)
855
2620
  requirements: {
856
2621
  requiredRoles: ["123456789012345678"], // ๐Ÿ›ก๏ธ User MUST have this role to join (Button Only)
857
2622
  },
858
- ย  ย  });
859
- ย  ย  message.reply("๐ŸŽ‰ Giveaway started successfully!");
860
- ย  },
2623
+ });
2624
+ message.reply("๐ŸŽ‰ Giveaway started successfully!");
2625
+ },
861
2626
  };
862
2627
  ```
863
2628
 
@@ -1103,14 +2868,14 @@ module.exports = {
1103
2868
  const result = await GaddUser(
1104
2869
  interaction.message.id,
1105
2870
  interaction.user.id,
1106
- interaction.guild
2871
+ interaction.guild
1107
2872
  );
1108
2873
 
1109
2874
  if (result?.error) {
1110
2875
  // Handles both "User Already Joined" and "Missing Roles" errors
1111
2876
  if (result.error === "โŒ User Already Joined") {
1112
- // ... (Leave button logic)
1113
- const row = await CreateRow([
2877
+ // ... (Leave button logic)
2878
+ const row = await CreateRow([
1114
2879
  [
1115
2880
  {
1116
2881
  label: "Leave Giveaway",
@@ -1120,16 +2885,17 @@ module.exports = {
1120
2885
  ],
1121
2886
  ]);
1122
2887
  return interaction.reply({
1123
- content: "โš ๏ธ You have **already joined** this giveaway! You can **leave** by clicking the button below.",
2888
+ content:
2889
+ "โš ๏ธ You have **already joined** this giveaway! You can **leave** by clicking the button below.",
1124
2890
  components: row,
1125
- flags: 64,
2891
+ flags: 64,
1126
2892
  });
1127
2893
  }
1128
-
2894
+
1129
2895
  // Show error (e.g. Missing Role)
1130
2896
  return interaction.reply({
1131
- content: result.error,
1132
- flags: 64
2897
+ content: result.error,
2898
+ flags: 64,
1133
2899
  });
1134
2900
  }
1135
2901
 
@@ -1139,7 +2905,6 @@ module.exports = {
1139
2905
  });
1140
2906
  }
1141
2907
 
1142
-
1143
2908
  // 2. Handle Leave Button Click (Dynamically Generated ID)
1144
2909
  if (
1145
2910
  interaction.customId &&
@@ -1534,7 +3299,7 @@ module.exports = {
1534
3299
  channelId: channel.id,
1535
3300
  winers: winnerCount,
1536
3301
  endTime: endTimeMs,
1537
- prize : prize,
3302
+ prize: prize,
1538
3303
  embed: {
1539
3304
  title: `๐ŸŽ‰ ${prize} Giveaway!`,
1540
3305
  image: image,
@@ -1810,7 +3575,6 @@ module.exports = {
1810
3575
 
1811
3576
  ---
1812
3577
 
1813
-
1814
3578
  <details>
1815
3579
  <summary>Blacklist System ๐Ÿšซ</summary>
1816
3580
 
@@ -1882,10 +3646,12 @@ console.log("Role unblacklisted! ๐Ÿ”“");
1882
3646
  Returns an array of blacklisted items for a guild. You can optionally filter by type (`user`, `role`, `channel`).
1883
3647
 
1884
3648
  **Parameters:**
3649
+
1885
3650
  - `guildId` (String): The ID of the guild.
1886
3651
  - `type` (String, optional): The type to filter by (`user`, `role`, `channel`).
1887
3652
 
1888
3653
  **Example:**
3654
+
1889
3655
  ```js
1890
3656
  // Get all blacklisted items
1891
3657
  const allBlacklisted = await getBlacklist("GUILD_ID");
@@ -1910,35 +3676,80 @@ Output:
1910
3676
  You can create a slash command to manage the blacklist easily.
1911
3677
 
1912
3678
  ```js
1913
- const { addToBlacklist, removeFromBlacklist, isBlacklisted, getBlacklist } = require("djs-builder");
1914
- const { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder } = require("discord.js");
3679
+ const {
3680
+ addToBlacklist,
3681
+ removeFromBlacklist,
3682
+ isBlacklisted,
3683
+ getBlacklist,
3684
+ } = require("djs-builder");
3685
+ const {
3686
+ SlashCommandBuilder,
3687
+ PermissionFlagsBits,
3688
+ EmbedBuilder,
3689
+ } = require("discord.js");
1915
3690
 
1916
3691
  module.exports = {
1917
3692
  data: new SlashCommandBuilder()
1918
3693
  .setName("blacklist")
1919
3694
  .setDescription("Manage the blacklist")
1920
3695
  .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"))
3696
+ .addSubcommand((sub) =>
3697
+ sub
3698
+ .setName("add")
3699
+ .setDescription("Add to blacklist")
3700
+ .addUserOption((opt) =>
3701
+ opt.setName("user").setDescription("User to blacklist")
3702
+ )
3703
+ .addRoleOption((opt) =>
3704
+ opt.setName("role").setDescription("Role to blacklist")
3705
+ )
3706
+ .addChannelOption((opt) =>
3707
+ opt.setName("channel").setDescription("Channel to blacklist")
3708
+ )
1926
3709
  )
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"))
3710
+ .addSubcommand((sub) =>
3711
+ sub
3712
+ .setName("remove")
3713
+ .setDescription("Remove from blacklist")
3714
+ .addUserOption((opt) =>
3715
+ opt.setName("user").setDescription("User to remove")
3716
+ )
3717
+ .addRoleOption((opt) =>
3718
+ opt.setName("role").setDescription("Role to remove")
3719
+ )
3720
+ .addChannelOption((opt) =>
3721
+ opt.setName("channel").setDescription("Channel to remove")
3722
+ )
1932
3723
  )
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"))
3724
+ .addSubcommand((sub) =>
3725
+ sub
3726
+ .setName("check")
3727
+ .setDescription("Check if a target is blacklisted")
3728
+ .addUserOption((opt) =>
3729
+ opt.setName("user").setDescription("User to check")
3730
+ )
3731
+ .addRoleOption((opt) =>
3732
+ opt.setName("role").setDescription("Role to check")
3733
+ )
3734
+ .addChannelOption((opt) =>
3735
+ opt.setName("channel").setDescription("Channel to check")
3736
+ )
1938
3737
  )
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" }))
3738
+ .addSubcommand((sub) =>
3739
+ sub
3740
+ .setName("list")
3741
+ .setDescription("List all blacklisted items")
3742
+ .addStringOption((opt) =>
3743
+ opt
3744
+ .setName("type")
3745
+ .setDescription("Filter by type")
3746
+ .addChoices(
3747
+ { name: "User", value: "user" },
3748
+ { name: "Role", value: "role" },
3749
+ { name: "Channel", value: "channel" },
3750
+ { name: "All", value: "all" }
3751
+ )
3752
+ )
1942
3753
  ),
1943
3754
  async run(interaction) {
1944
3755
  const sub = interaction.options.getSubcommand();
@@ -1948,54 +3759,95 @@ module.exports = {
1948
3759
  const guildId = interaction.guild.id;
1949
3760
 
1950
3761
  if (sub === "list") {
1951
- const type = interaction.options.getString("type");
1952
- if (type !== "all") {
3762
+ const type = interaction.options.getString("type");
3763
+ if (type !== "all") {
1953
3764
  const list = await getBlacklist(guildId, type);
1954
3765
 
1955
- if (!list.length) return interaction.reply({ content: "โœ… No blacklisted items found.", flags : 64 });
3766
+ if (!list.length)
3767
+ return interaction.reply({
3768
+ content: "โœ… No blacklisted items found.",
3769
+ flags: 64,
3770
+ });
1956
3771
 
1957
3772
  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 {
3773
+ .setTitle("๐Ÿšซ Blacklist")
3774
+ .setColor("Red")
3775
+ .setDescription(
3776
+ list
3777
+ .map(
3778
+ (item) =>
3779
+ `โ€ข **${item.type.toUpperCase()}**: <${
3780
+ item.type === "channel"
3781
+ ? "#"
3782
+ : item.type === "role"
3783
+ ? "@&"
3784
+ : "@"
3785
+ }${item.id}> (\`${item.id}\`)`
3786
+ )
3787
+ .join("\n")
3788
+ .slice(0, 4000)
3789
+ );
3790
+
3791
+ return interaction.reply({ embeds: [embed], flags: 64 });
3792
+ } else {
1964
3793
  const list = await getBlacklist(guildId);
1965
- if (!list.length) return interaction.reply({ content: "โœ… No blacklisted items found.", flags : 64 });
3794
+ if (!list.length)
3795
+ return interaction.reply({
3796
+ content: "โœ… No blacklisted items found.",
3797
+ flags: 64,
3798
+ });
1966
3799
 
1967
3800
  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");
3801
+ const roles = list.filter((i) => i.type === "role");
3802
+ const users = list.filter((i) => i.type === "user");
3803
+ const channels = list.filter((i) => i.type === "channel");
1971
3804
 
1972
3805
  if (users.length) {
1973
- const userEmbed = new EmbedBuilder()
3806
+ const userEmbed = new EmbedBuilder()
1974
3807
  .setTitle("๐Ÿšซ Blacklisted Users")
1975
3808
  .setColor("Red")
1976
- .setDescription(users.map(item => `โ€ข <@${item.id}> (\`${item.id}\`)`).join("\n").slice(0, 4000));
1977
- embeds.push(userEmbed);
3809
+ .setDescription(
3810
+ users
3811
+ .map((item) => `โ€ข <@${item.id}> (\`${item.id}\`)`)
3812
+ .join("\n")
3813
+ .slice(0, 4000)
3814
+ );
3815
+ embeds.push(userEmbed);
1978
3816
  }
1979
- if( roles.length) {
1980
- const roleEmbed = new EmbedBuilder()
3817
+ if (roles.length) {
3818
+ const roleEmbed = new EmbedBuilder()
1981
3819
  .setTitle("๐Ÿšซ Blacklisted Roles")
1982
3820
  .setColor("Red")
1983
- .setDescription(roles.map(item => `โ€ข <@&${item.id}> (\`${item.id}\`)`).join("\n").slice(0, 4000));
1984
- embeds.push(roleEmbed);
3821
+ .setDescription(
3822
+ roles
3823
+ .map((item) => `โ€ข <@&${item.id}> (\`${item.id}\`)`)
3824
+ .join("\n")
3825
+ .slice(0, 4000)
3826
+ );
3827
+ embeds.push(roleEmbed);
1985
3828
  }
1986
- if( channels.length) {
1987
- const channelEmbed = new EmbedBuilder()
3829
+ if (channels.length) {
3830
+ const channelEmbed = new EmbedBuilder()
1988
3831
  .setTitle("๐Ÿšซ Blacklisted Channels")
1989
3832
  .setColor("Red")
1990
- .setDescription(channels.map(item => `โ€ข <#${item.id}> (\`${item.id}\`)`).join("\n").slice(0, 4000));
1991
- embeds.push(channelEmbed);
3833
+ .setDescription(
3834
+ channels
3835
+ .map((item) => `โ€ข <#${item.id}> (\`${item.id}\`)`)
3836
+ .join("\n")
3837
+ .slice(0, 4000)
3838
+ );
3839
+ embeds.push(channelEmbed);
1992
3840
  }
1993
- return interaction.reply({ embeds, flags : 64 });
3841
+ return interaction.reply({ embeds, flags: 64 });
3842
+ }
1994
3843
  }
1995
- }
1996
-
3844
+
1997
3845
  if (!user && !role && !channel) {
1998
- return interaction.reply({ content: "โš ๏ธ You must provide at least one option (User, Role, or Channel).", flags : 64 });
3846
+ return interaction.reply({
3847
+ content:
3848
+ "โš ๏ธ You must provide at least one option (User, Role, or Channel).",
3849
+ flags: 64,
3850
+ });
1999
3851
  }
2000
3852
  const target = user || role || channel;
2001
3853
  const type = user ? "user" : role ? "role" : "channel";
@@ -2003,18 +3855,25 @@ module.exports = {
2003
3855
 
2004
3856
  if (sub === "add") {
2005
3857
  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.`);
3858
+ if (success)
3859
+ interaction.reply(`โœ… Added **${type}** ${target} to blacklist.`);
3860
+ else
3861
+ interaction.reply(`โš ๏ธ **${type}** ${target} is already blacklisted.`);
2008
3862
  } else if (sub === "remove") {
2009
3863
  const success = await removeFromBlacklist(guildId, type, id);
2010
- if (success) interaction.reply(`โœ… Removed **${type}** ${target} from blacklist.`);
3864
+ if (success)
3865
+ interaction.reply(`โœ… Removed **${type}** ${target} from blacklist.`);
2011
3866
  else interaction.reply(`โš ๏ธ **${type}** ${target} is not blacklisted.`);
2012
3867
  } else if (sub === "check") {
2013
3868
  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.`);
3869
+ if (isBlocked)
3870
+ interaction.reply(
3871
+ `๐Ÿšซ **${type}** ${target} is currently **blacklisted**.`
3872
+ );
3873
+ else
3874
+ interaction.reply(`โœ… **${type}** ${target} is **not** blacklisted.`);
2016
3875
  }
2017
- }
3876
+ },
2018
3877
  };
2019
3878
  ```
2020
3879
 
@@ -2160,6 +4019,7 @@ The **Dashboard System** is a modern, lightweight web-based control panel for yo
2160
4019
  - ๐Ÿ“œ **Commands Viewer** โ€“ Browse all slash and prefix commands.
2161
4020
  - ๐Ÿ† **Level System Management** โ€“ View leaderboards, manage user XP and levels.
2162
4021
  - ๐ŸŽ‰ **Giveaway Control** โ€“ Pause, resume, end, reroll, or delete giveaways.
4022
+ - ๐Ÿฆพ **Logging System Control** โ€“ Manage log channels, colors, and event toggles.
2163
4023
  - ๐Ÿšซ **Blacklist Management** โ€“ Add/remove users, roles, or channels from blacklist.
2164
4024
  - ๐ŸŽจ **Modern UI** โ€“ Beautiful, responsive design with dark mode support.
2165
4025
 
@@ -2191,11 +4051,10 @@ const starterOptions = {
2191
4051
 
2192
4052
  // ๐ŸŒ Dashboard Configuration
2193
4053
  dashboard: {
2194
- clientID: "YOUR_DISCORD_CLIENT_ID", // ๐Ÿ”‘ Discord Application Client ID
2195
4054
  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)
4055
+ callbackURL: "http://localhost:3000/auth/discord/callback", // ๐Ÿ”— OAuth2 Callback URL (OPTINAL)
4056
+ sessionSecret: "your-super-secret-key", // ๐Ÿ”’ Session encryption secret
4057
+ port: 3000, // ๐ŸŒ Dashboard port (OPTINAL / default: 3000)
2199
4058
  },
2200
4059
 
2201
4060
  // ... other options (Status, database, anticrash, etc.)
@@ -2229,11 +4088,10 @@ client.once("ready", () => {
2229
4088
 
2230
4089
  // ๐ŸŒ Start the Dashboard
2231
4090
  dashboard(client, {
2232
- clientID: "YOUR_DISCORD_CLIENT_ID", // ๐Ÿ”‘ Discord Application Client ID
2233
4091
  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)
4092
+ callbackURL: "http://localhost:3000/auth/discord/callback", // ๐Ÿ”— OAuth2 Callback URL (OPTINAL)
4093
+ sessionSecret: "your-super-secret-key", // ๐Ÿ”’ Session encryption secret
4094
+ port: 3000, // ๐ŸŒ Dashboard port (OPTINAL / default: 3000)
2237
4095
  });
2238
4096
  });
2239
4097
  ```
@@ -2249,15 +4107,16 @@ client.once("ready", () => {
2249
4107
 
2250
4108
  ### ๐Ÿ“Œ Dashboard Routes
2251
4109
 
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 |
4110
+ | Route | Description |
4111
+ | ------------------------------- | ---------------------------- |
4112
+ | `/` | ๐Ÿ  Homepage with bot stats |
4113
+ | `/login` | ๐Ÿ” Login page |
4114
+ | `/dashboard` | ๐Ÿ“Š Server selection |
4115
+ | `/dashboard/:guildId` | ๐Ÿ  Server overview |
4116
+ | `/dashboard/:guildId/commands` | ๐Ÿ“œ Commands list |
4117
+ | `/dashboard/:guildId/levels` | ๐Ÿ† Level leaderboard |
4118
+ | `/dashboard/:guildId/giveaways` | ๐ŸŽ‰ Giveaway management |
4119
+ | `/dashboard/:guildId/logs` | ๐Ÿ›ก๏ธ Logging system management |
2261
4120
 
2262
4121
  ---
2263
4122
 
@@ -2290,7 +4149,13 @@ POST /api/:guildId/giveaway/end
2290
4149
  POST /api/:guildId/giveaway/reroll
2291
4150
  POST /api/:guildId/giveaway/delete
2292
4151
 
2293
- // ๐Ÿšซ Blacklist management
4152
+ // ๏ฟฝ๏ธ Logging system management
4153
+ POST /api/:guildId/logs/channel // Set default log channel
4154
+ POST /api/:guildId/logs/toggle // Enable/disable event type
4155
+ POST /api/:guildId/logs/event // Update event settings (channel, color)
4156
+ POST /api/:guildId/logs/reset // Reset all log settings
4157
+
4158
+ // ๏ฟฝ๐Ÿšซ Blacklist management
2294
4159
  POST /api/guild/:guildId/blacklist // Add to blacklist
2295
4160
  DELETE /api/guild/:guildId/blacklist // Remove from blacklist
2296
4161
  ```
@@ -2304,13 +4169,12 @@ DELETE /api/guild/:guildId/blacklist // Remove from blacklist
2304
4169
 
2305
4170
  ### ๐Ÿ”ง Configuration Options
2306
4171
 
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) |
4172
+ | Option | Type | Required | Description |
4173
+ | --------------- | -------- | -------- | ---------------------------------------------------- |
4174
+ | `clientSecret` | `string` | โœ… | ๐Ÿ” Your Discord Application Client Secret |
4175
+ | `callbackURL` | `string` | โœ… | ๐Ÿ”— OAuth2 redirect URL (must match Discord settings) |
4176
+ | `sessionSecret` | `string` | โœ… | ๐Ÿ”’ Secret key for session encryption |
4177
+ | `port` | `number` | โŒ | ๐ŸŒ Port to run the dashboard (default: 3000) |
2314
4178
 
2315
4179
  ---
2316
4180
 
@@ -2318,16 +4182,17 @@ DELETE /api/guild/:guildId/blacklist // Remove from blacklist
2318
4182
 
2319
4183
  The dashboard uses **EJS** templates located in the `views` folder:
2320
4184
 
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 |
4185
+ | File | Description |
4186
+ | --------------- | ---------------------------- |
4187
+ | `index.ejs` | ๐Ÿ  Homepage |
4188
+ | `login.ejs` | ๐Ÿ” Login page |
4189
+ | `dashboard.ejs` | ๐Ÿ“Š Server selection |
4190
+ | `guild.ejs` | ๐Ÿ  Server overview |
4191
+ | `commands.ejs` | ๐Ÿ“œ Commands list |
4192
+ | `levels.ejs` | ๐Ÿ† Level management |
4193
+ | `giveaways.ejs` | ๐ŸŽ‰ Giveaway management |
4194
+ | `logs.ejs` | ๐Ÿ›ก๏ธ Logging system management |
4195
+ | `404.ejs` | โŒ Not found page |
2331
4196
 
2332
4197
  </details>
2333
4198
 
@@ -2368,4 +4233,4 @@ We welcome contributions! If you have any suggestions, bug reports, or feature r
2368
4233
 
2369
4234
  ๐ŸŒ **Join our Discord:**
2370
4235
 
2371
- [![Discord Banner](https://api.weblutions.com/discord/invite/CS2NRSPyze/)](https://discord.gg/CS2NRSPyze)
4236
+ [![Discord Banner](https://api.weblutions.com/discord/invite/uYcKCZk3/)](https://discord.gg/uYcKCZk3)