djs-builder 0.6.401 → 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 +2335 -221
- package/function/dash.js +1133 -0
- package/function/function.js +255 -8
- package/function/giveaway.js +47 -10
- package/function/level.js +337 -10
- package/function/log.js +407 -332
- package/function/security.js +0 -0
- package/handler/helper.js +46 -25
- package/handler/starter.js +115 -46
- package/package.json +25 -6
- package/views/404.ejs +40 -0
- package/views/dashboard.ejs +928 -0
- package/views/giveaways.ejs +307 -0
- package/views/guild.ejs +580 -0
- package/views/index.ejs +419 -0
- package/views/levels.ejs +966 -0
- package/views/login.ejs +437 -0
- package/views/logs.ejs +624 -0
package/README.md
CHANGED
|
@@ -5,13 +5,16 @@
|
|
|
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
|
+
[](https://discord.gg/uYcKCZk3)
|
|
9
|
+
|
|
8
10
|
---
|
|
9
11
|
|
|
10
12
|
## 📑 Table of Contents
|
|
11
13
|
|
|
12
|
-
1. 🎯 [Starter](
|
|
13
|
-
2. ⚙️ [Functions](
|
|
14
|
-
3. ⚡ [Commands & Events](
|
|
14
|
+
1. 🎯 [Starter](#-starter) – Initialize your bot with commands, events, presence, and more.
|
|
15
|
+
2. ⚙️ [Functions](#%EF%B8%8F-functions) – Utilities like CreateRow, CreateBar, Wait, and GetUser.
|
|
16
|
+
3. ⚡ [Commands & Events](#-commands--events) – Easy setup with cooldowns, permissions, logging, and anti-crash.
|
|
17
|
+
4. 🌐 [Dashboard](#-dashboard) – Web-based control panel for managing your bot.
|
|
15
18
|
|
|
16
19
|
---
|
|
17
20
|
|
|
@@ -63,12 +66,21 @@ const starterOptions = {
|
|
|
63
66
|
|
|
64
67
|
database: {
|
|
65
68
|
url: "mongodb://localhost:27017", // 💾 MongoDB connection
|
|
69
|
+
dbName: "yourDatabaseName", // 📁 Optional: Specify database name (default: "test")
|
|
66
70
|
},
|
|
67
71
|
|
|
68
72
|
anticrash: {
|
|
69
73
|
url: "https://your.crash.webhook.url", // 🚨 Webhook for crash reports
|
|
70
74
|
mention_id: "YOUR_USER_ID", // 📣 Optional: mention user on crash
|
|
71
75
|
},
|
|
76
|
+
|
|
77
|
+
// 🌐 Dashboard Configuration (Full docs at the end of this page)
|
|
78
|
+
dashboard: {
|
|
79
|
+
clientSecret: "YOUR_DISCORD_CLIENT_SECRET", // 🔐 Discord Application Client Secret
|
|
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)
|
|
83
|
+
},
|
|
72
84
|
};
|
|
73
85
|
|
|
74
86
|
// Start the bot
|
|
@@ -90,6 +102,7 @@ await starter(client, starterOptions);
|
|
|
90
102
|
|
|
91
103
|
- Connects automatically to MongoDB 💾.
|
|
92
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.
|
|
93
106
|
|
|
94
107
|
#### 3️⃣ Anticrash System
|
|
95
108
|
|
|
@@ -130,6 +143,14 @@ await starter(client, starterOptions);
|
|
|
130
143
|
|
|
131
144
|
- Available via `client.files`, useful for debugging or terminal display 🛠️.
|
|
132
145
|
|
|
146
|
+
#### 7️⃣ Dashboard (Web Control Panel)
|
|
147
|
+
|
|
148
|
+
- Launches a **modern web-based control panel** for your bot 🌐.
|
|
149
|
+
- Supports Discord OAuth2 authentication 🔐.
|
|
150
|
+
- Manage servers, levels, giveaways, and blacklists from the browser 🎛️.
|
|
151
|
+
|
|
152
|
+
> 📖 **Full Dashboard documentation available at the end of this page** → [🌐 DASHBOARD](#-dashboard)
|
|
153
|
+
|
|
133
154
|
---
|
|
134
155
|
|
|
135
156
|
### 💡 Tips
|
|
@@ -190,6 +211,12 @@ const actionRow = new CreateRow([
|
|
|
190
211
|
emoji: "🚀",
|
|
191
212
|
disabled: true, // Button is disabled
|
|
192
213
|
},
|
|
214
|
+
{
|
|
215
|
+
style: 5,
|
|
216
|
+
label: "link",
|
|
217
|
+
emoji: "🔗"
|
|
218
|
+
url : "https://discord.gg/z9GpYsYF" // for url button
|
|
219
|
+
}
|
|
193
220
|
],
|
|
194
221
|
|
|
195
222
|
// 🔹 Row #2: Select Menu
|
|
@@ -224,7 +251,7 @@ const actionRow = new CreateRow([
|
|
|
224
251
|
disabled: false, // Disable the entire menu
|
|
225
252
|
defaultValues: [
|
|
226
253
|
// For role/user/channel menus
|
|
227
|
-
{ id: "123456789012345678"
|
|
254
|
+
{ id: "123456789012345678" }, // Pre-selected
|
|
228
255
|
],
|
|
229
256
|
channelTypes: [0, 2], // Only for ChannelSelectMenu (0 = Text, 2 = Voice)
|
|
230
257
|
},
|
|
@@ -243,6 +270,7 @@ const actionRow = new CreateRow([
|
|
|
243
270
|
- `label` → Button text
|
|
244
271
|
- `emoji` → Displayed emoji
|
|
245
272
|
- `disabled` → true = button is unclickable
|
|
273
|
+
- `url` → requiier for like button (style : 5)
|
|
246
274
|
|
|
247
275
|
#### 🔹 Select Menus
|
|
248
276
|
|
|
@@ -376,166 +404,1922 @@ console.log(
|
|
|
376
404
|
---
|
|
377
405
|
|
|
378
406
|
<details>
|
|
379
|
-
<summary>
|
|
407
|
+
<summary>CreateModal 🔳</summary>
|
|
380
408
|
|
|
381
|
-
|
|
409
|
+
**🔳 CreateModal – Easily create Discord Modals with Text Inputs, Menus, Files, and Labels ✨**
|
|
382
410
|
|
|
383
|
-
`
|
|
411
|
+
`CreateModal` is a powerful utility to build Discord **Modals**. It supports:
|
|
384
412
|
|
|
385
|
-
-
|
|
386
|
-
-
|
|
387
|
-
-
|
|
388
|
-
-
|
|
413
|
+
- **Text Inputs** 📝
|
|
414
|
+
- **Select Menus** 🎯 (`string`, `role`, `user`, `channel`)
|
|
415
|
+
- **File Uploads** 📎
|
|
416
|
+
- **Text Displays** 🏷️
|
|
389
417
|
|
|
390
418
|
---
|
|
391
419
|
|
|
392
420
|
### 📌 Example Usage:
|
|
393
421
|
|
|
394
422
|
```js
|
|
395
|
-
const {
|
|
423
|
+
const { CreateModal } = require("djs-builder");
|
|
396
424
|
|
|
397
|
-
const
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
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
|
+
],
|
|
403
490
|
});
|
|
404
491
|
|
|
405
|
-
|
|
406
|
-
|
|
492
|
+
// Show the modal
|
|
493
|
+
await interaction.showModal(modal);
|
|
407
494
|
```
|
|
408
495
|
|
|
409
496
|
---
|
|
410
497
|
|
|
411
|
-
###
|
|
498
|
+
### 📔 Examples for Each Component Type:
|
|
412
499
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
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
|
|
418
632
|
|
|
419
633
|
---
|
|
420
634
|
|
|
421
635
|
### 🔹 Notes
|
|
422
636
|
|
|
423
|
-
- Supports
|
|
424
|
-
-
|
|
637
|
+
- Supports multiple components in one modal
|
|
638
|
+
- Fully customizable with Discord.js ModalBuilder
|
|
425
639
|
|
|
426
640
|
</details>
|
|
427
641
|
|
|
428
642
|
---
|
|
429
643
|
|
|
430
644
|
<details>
|
|
431
|
-
<summary>
|
|
645
|
+
<summary>CreateComponents 🧩</summary>
|
|
432
646
|
|
|
433
|
-
|
|
647
|
+
**🧩 CreateComponents – Build Advanced Discord UI Components with Containers, Sections & Media ✨**
|
|
434
648
|
|
|
435
|
-
`
|
|
649
|
+
`CreateComponents` is a powerful utility to build Discord's **new UI components**. It supports:
|
|
436
650
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
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)
|
|
440
659
|
|
|
441
660
|
---
|
|
442
661
|
|
|
443
|
-
### 📌 Example Usage:
|
|
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:**
|
|
1838
|
+
|
|
1839
|
+
```js
|
|
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
|
|
1847
|
+
);
|
|
1848
|
+
|
|
1849
|
+
// Add event to disable list
|
|
1850
|
+
await Log.findOneAndUpdate(
|
|
1851
|
+
{ guildId: "123456789012345678" },
|
|
1852
|
+
{ $push: { disable: "voiceStateUpdate" } }
|
|
1853
|
+
);
|
|
1854
|
+
|
|
1855
|
+
// Remove event from disable list
|
|
1856
|
+
await Log.findOneAndUpdate(
|
|
1857
|
+
{ guildId: "123456789012345678" },
|
|
1858
|
+
{ $pull: { disable: "voiceStateUpdate" } }
|
|
1859
|
+
);
|
|
1860
|
+
|
|
1861
|
+
// Update specific channel for an event
|
|
1862
|
+
await Log.findOneAndUpdate(
|
|
1863
|
+
{ guildId: "123456789012345678" },
|
|
1864
|
+
{ $set: { "channels.messageDelete": "NEW_CHANNEL_ID" } }
|
|
1865
|
+
);
|
|
1866
|
+
|
|
1867
|
+
// Update specific color for an event
|
|
1868
|
+
await Log.findOneAndUpdate(
|
|
1869
|
+
{ guildId: "123456789012345678" },
|
|
1870
|
+
{ $set: { "colors.messageDelete": "DarkRed" } }
|
|
1871
|
+
);
|
|
1872
|
+
```
|
|
1873
|
+
|
|
1874
|
+
**🗑️ Delete Configuration:**
|
|
1875
|
+
|
|
1876
|
+
```js
|
|
1877
|
+
const { Log } = require("djs-builder");
|
|
1878
|
+
|
|
1879
|
+
await Log.findOneAndDelete({ guildId: "123456789012345678" });
|
|
1880
|
+
console.log("🗑️ Log configuration deleted!");
|
|
1881
|
+
```
|
|
1882
|
+
|
|
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
|
+
```
|
|
1896
|
+
|
|
1897
|
+
</details>
|
|
1898
|
+
|
|
1899
|
+
---
|
|
1900
|
+
|
|
1901
|
+
<details>
|
|
1902
|
+
<summary>🌐 Dashboard Integration – Manage Logs from Web Panel 🖥️</summary>
|
|
1903
|
+
|
|
1904
|
+
### 🖥️ Web Dashboard for Log Management
|
|
1905
|
+
|
|
1906
|
+
When you use **database mode** (`database: true`), you can manage the logging system directly from the **djs-builder Dashboard**! 🎛️
|
|
1907
|
+
|
|
1908
|
+
---
|
|
1909
|
+
|
|
1910
|
+
#### ✨ Dashboard Features for Logs
|
|
1911
|
+
|
|
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 |
|
|
1920
|
+
|
|
1921
|
+
---
|
|
1922
|
+
|
|
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
|
|
1929
|
+
|
|
1930
|
+
---
|
|
1931
|
+
|
|
1932
|
+
#### ⚠️ Important Notes
|
|
1933
|
+
|
|
1934
|
+
**When `database: true`:**
|
|
1935
|
+
|
|
1936
|
+
- ✅ Full editing capabilities from dashboard
|
|
1937
|
+
- ✅ Changes are saved automatically to MongoDB
|
|
1938
|
+
- ✅ Real-time updates
|
|
1939
|
+
|
|
1940
|
+
**When `database: false` (Custom Data Array):**
|
|
1941
|
+
|
|
1942
|
+
- ⚠️ Dashboard shows **read-only** mode
|
|
1943
|
+
- ⚠️ A warning banner appears at the top
|
|
1944
|
+
- ⚠️ You must edit settings in your code
|
|
1945
|
+
|
|
1946
|
+
</details>
|
|
1947
|
+
|
|
1948
|
+
---
|
|
1949
|
+
|
|
1950
|
+
<details>
|
|
1951
|
+
<summary>🎮 Slash Command for Log Management 🛠️</summary>
|
|
1952
|
+
|
|
1953
|
+
### 🛠️ Complete Log Management Slash Command
|
|
1954
|
+
|
|
1955
|
+
This command allows server administrators to manage the logging system via Discord.
|
|
1956
|
+
|
|
1957
|
+
> ⚠️ **Important**: This command requires `database: true` mode to work properly.
|
|
1958
|
+
|
|
1959
|
+
```js
|
|
1960
|
+
const { Log, getLogConfigData } = require("djs-builder");
|
|
1961
|
+
const {
|
|
1962
|
+
SlashCommandBuilder,
|
|
1963
|
+
PermissionFlagsBits,
|
|
1964
|
+
EmbedBuilder,
|
|
1965
|
+
ChannelType,
|
|
1966
|
+
} = require("discord.js");
|
|
1967
|
+
|
|
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
|
+
}
|
|
1998
|
+
|
|
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
|
+
),
|
|
444
2083
|
|
|
445
|
-
|
|
446
|
-
|
|
2084
|
+
async run(client, interaction) {
|
|
2085
|
+
await interaction.deferReply({ ephemeral: true });
|
|
447
2086
|
|
|
448
|
-
const
|
|
2087
|
+
const subcommand = interaction.options.getSubcommand();
|
|
2088
|
+
const guildId = interaction.guild.id;
|
|
449
2089
|
|
|
450
|
-
|
|
2090
|
+
// ═══════════════════════════════════════════════════════
|
|
2091
|
+
// 📢 SETUP - Set default log channel
|
|
2092
|
+
// ═══════════════════════════════════════════════════════
|
|
2093
|
+
if (subcommand === "setup") {
|
|
2094
|
+
const channel = interaction.options.getChannel("channel");
|
|
451
2095
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
2096
|
+
await Log.findOneAndUpdate(
|
|
2097
|
+
{ guildId },
|
|
2098
|
+
{ guildId, channelId: channel.id },
|
|
2099
|
+
{ upsert: true, new: true }
|
|
2100
|
+
);
|
|
455
2101
|
|
|
456
|
-
|
|
457
|
-
message.reply(`🚫 ${member.user.tag} was banned for: ${reason}`);
|
|
458
|
-
```
|
|
2102
|
+
clearLogCache(guildId); // Clear cache to apply changes immediately
|
|
459
2103
|
|
|
460
|
-
|
|
2104
|
+
const embed = new EmbedBuilder()
|
|
2105
|
+
.setTitle("✅ Logging System Setup")
|
|
2106
|
+
.setDescription(`Logs will now be sent to ${channel}`)
|
|
2107
|
+
.setColor("Green")
|
|
2108
|
+
.setTimestamp();
|
|
461
2109
|
|
|
462
|
-
|
|
2110
|
+
return interaction.editReply({ embeds: [embed] });
|
|
2111
|
+
}
|
|
463
2112
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
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
|
+
);
|
|
470
2125
|
|
|
471
|
-
|
|
2126
|
+
clearLogCache(guildId);
|
|
472
2127
|
|
|
473
|
-
|
|
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();
|
|
474
2135
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
- **Reply:** `Reply to user's message with !ban`
|
|
2136
|
+
return interaction.editReply({ embeds: [embed] });
|
|
2137
|
+
}
|
|
478
2138
|
|
|
479
|
-
|
|
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
|
+
);
|
|
480
2151
|
|
|
481
|
-
|
|
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
|
+
}
|
|
482
2164
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
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();
|
|
486
2172
|
|
|
487
|
-
|
|
2173
|
+
return interaction.editReply({ embeds: [embed] });
|
|
2174
|
+
}
|
|
488
2175
|
|
|
489
|
-
|
|
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
|
+
}
|
|
490
2196
|
|
|
491
|
-
|
|
492
|
-
<summary>Logging System 🛡️</summary>
|
|
2197
|
+
clearLogCache(guildId);
|
|
493
2198
|
|
|
494
|
-
|
|
495
|
-
|
|
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();
|
|
496
2208
|
|
|
497
|
-
|
|
2209
|
+
return interaction.editReply({ embeds: [embed] });
|
|
2210
|
+
}
|
|
498
2211
|
|
|
499
|
-
|
|
2212
|
+
// ═══════════════════════════════════════════════════════
|
|
2213
|
+
// 📊 VIEW - Show current configuration
|
|
2214
|
+
// ═══════════════════════════════════════════════════════
|
|
2215
|
+
if (subcommand === "view") {
|
|
2216
|
+
const config = await Log.findOne({ guildId });
|
|
500
2217
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
- 🚨 **Audit Log Integration** – Fetches the executor (who did what).
|
|
508
|
-
- 🎨 **Beautiful Embeds** – Every log is shown in a clean, styled embed with timestamps.
|
|
2218
|
+
if (!config) {
|
|
2219
|
+
return interaction.editReply({
|
|
2220
|
+
content:
|
|
2221
|
+
"❌ No logging configuration found for this server. Use `/logs setup` first!",
|
|
2222
|
+
});
|
|
2223
|
+
}
|
|
509
2224
|
|
|
510
|
-
|
|
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();
|
|
511
2281
|
|
|
512
|
-
|
|
2282
|
+
return interaction.editReply({ embeds: [embed] });
|
|
2283
|
+
}
|
|
513
2284
|
|
|
514
|
-
|
|
515
|
-
|
|
2285
|
+
// ═══════════════════════════════════════════════════════
|
|
2286
|
+
// 🗑️ RESET - Delete all configuration
|
|
2287
|
+
// ═══════════════════════════════════════════════════════
|
|
2288
|
+
if (subcommand === "reset") {
|
|
2289
|
+
await Log.findOneAndDelete({ guildId });
|
|
2290
|
+
|
|
2291
|
+
clearLogCache(guildId);
|
|
516
2292
|
|
|
517
|
-
|
|
518
|
-
|
|
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();
|
|
519
2300
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
async run(client) {
|
|
523
|
-
await log(
|
|
524
|
-
client,
|
|
525
|
-
"GUILD_ID", // 🏠 Guild ID (server)
|
|
526
|
-
"CHANNEL_ID" // 📢 Channel ID for logs
|
|
527
|
-
);
|
|
2301
|
+
return interaction.editReply({ embeds: [embed] });
|
|
2302
|
+
}
|
|
528
2303
|
},
|
|
529
2304
|
};
|
|
530
2305
|
```
|
|
531
2306
|
|
|
2307
|
+
</details>
|
|
2308
|
+
|
|
532
2309
|
---
|
|
533
2310
|
|
|
534
|
-
### 💡
|
|
2311
|
+
### 💡 Tips & Notes
|
|
2312
|
+
|
|
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!
|
|
535
2321
|
|
|
536
|
-
|
|
537
|
-
- 🔔 Instantly starts tracking events and sending them to the log channel.
|
|
538
|
-
- 🧰 No extra setup required – plug and play!
|
|
2322
|
+
---
|
|
539
2323
|
|
|
540
2324
|
</details>
|
|
541
2325
|
|
|
@@ -552,9 +2336,7 @@ module.exports = {
|
|
|
552
2336
|
The **Level System** module lets you track user experience points (XP) in **text** 💬 and **voice** 🎙️, handle **level-ups** ⬆️, and display **leaderboards** 🏅.
|
|
553
2337
|
Perfect for gamifying your Discord server! 🎮✨
|
|
554
2338
|
|
|
555
|
-
> **Note**: To use this module, you **MUST** have **DATABASE** conection.
|
|
556
|
-
|
|
557
|
-
> **Note**: You can get all data by requiring the **Level** module.
|
|
2339
|
+
> **Note**: To use this module, you **MUST** have **DATABASE** conection. | **Note 2**: You can get all data by requiring the **Level** module.
|
|
558
2340
|
|
|
559
2341
|
---
|
|
560
2342
|
|
|
@@ -708,9 +2490,7 @@ module.exports = {
|
|
|
708
2490
|
|
|
709
2491
|
This module provides a robust and feature-rich suite of functions to effortlessly launch, monitor, manage, and conclude **Giveaways** on your Discord server. It fully supports both **Reactions** and **Buttons** for entry, featuring advanced controls like pausing, resuming, and rerolling winners. **It is highly recommended to read the Important Notes section below.** 🚨
|
|
710
2492
|
|
|
711
|
-
> **Note**: To use this module, you **MUST** have **DATABASE** conection.
|
|
712
|
-
|
|
713
|
-
> **Note**: You can get all data by requiring the **giveaway** module.
|
|
2493
|
+
> **Note**: To use this module, you **MUST** have **DATABASE** conection. | **Note 2**: You can get all data by requiring the **giveaway** module.
|
|
714
2494
|
|
|
715
2495
|
---
|
|
716
2496
|
|
|
@@ -795,51 +2575,54 @@ const { Gstart } = require("djs-builder");
|
|
|
795
2575
|
const { EmbedBuilder } = require("discord.js");
|
|
796
2576
|
|
|
797
2577
|
module.exports = {
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
const channelId =
|
|
804
|
-
|
|
805
|
-
await Gstart({
|
|
806
|
-
context: message,
|
|
807
|
-
endTime: twoDays,
|
|
808
|
-
winers: 5, // 5 lucky winners! 🏆
|
|
809
|
-
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
|
|
810
2584
|
|
|
811
|
-
|
|
812
|
-
|
|
2585
|
+
await Gstart({
|
|
2586
|
+
context: message,
|
|
2587
|
+
endTime: twoDays,
|
|
2588
|
+
winers: 5, // 5 lucky winners! 🏆
|
|
2589
|
+
channelId: channelId,
|
|
813
2590
|
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
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
|
+
},
|
|
821
2601
|
|
|
822
2602
|
// 🛑 Customization for the ENDED EMBED
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
},
|
|
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
|
+
},
|
|
830
2609
|
|
|
831
2610
|
// 🖱️ Button Entry Method
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
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
|
+
},
|
|
2618
|
+
|
|
2619
|
+
// 🔒 Requirements (Optional)
|
|
2620
|
+
requirements: {
|
|
2621
|
+
requiredRoles: ["123456789012345678"], // 🛡️ User MUST have this role to join (Button Only)
|
|
2622
|
+
},
|
|
2623
|
+
});
|
|
2624
|
+
message.reply("🎉 Giveaway started successfully!");
|
|
2625
|
+
},
|
|
843
2626
|
};
|
|
844
2627
|
```
|
|
845
2628
|
|
|
@@ -867,6 +2650,11 @@ This module requires specific setup steps to function correctly. Pay attention t
|
|
|
867
2650
|
- You **MUST** manually implement a listener for the **`interactionCreate`** event and use the **`GaddUser`** function to register the user entry when the button is clicked. 🖱️
|
|
868
2651
|
- _See the `GaddUser` section for a detailed code example._
|
|
869
2652
|
|
|
2653
|
+
- **3. Requirements (Roles):**
|
|
2654
|
+
|
|
2655
|
+
- The `requiredRoles` feature currently works **ONLY** with the **Button** entry method (`reaction.type: "button"`).
|
|
2656
|
+
- When using `GaddUser`, you must pass the `guild` object as the third argument for the role check to work.
|
|
2657
|
+
|
|
870
2658
|
</details>
|
|
871
2659
|
|
|
872
2660
|
---
|
|
@@ -1076,27 +2864,38 @@ module.exports = {
|
|
|
1076
2864
|
run: async (interaction) => {
|
|
1077
2865
|
// 1. Handle Join/Entry Button Click
|
|
1078
2866
|
if (interaction.customId === "djs-builder-giveaway") {
|
|
2867
|
+
// ⚠️ Note: Pass 'interaction.guild' as the 3rd argument to enable Role Requirements check!
|
|
1079
2868
|
const result = await GaddUser(
|
|
1080
2869
|
interaction.message.id,
|
|
1081
|
-
interaction.user.id
|
|
2870
|
+
interaction.user.id,
|
|
2871
|
+
interaction.guild
|
|
1082
2872
|
);
|
|
1083
2873
|
|
|
1084
|
-
if (result?.error
|
|
1085
|
-
// User
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
2874
|
+
if (result?.error) {
|
|
2875
|
+
// Handles both "User Already Joined" and "Missing Roles" errors
|
|
2876
|
+
if (result.error === "❌ User Already Joined") {
|
|
2877
|
+
// ... (Leave button logic)
|
|
2878
|
+
const row = await CreateRow([
|
|
2879
|
+
[
|
|
2880
|
+
{
|
|
2881
|
+
label: "Leave Giveaway",
|
|
2882
|
+
id: "djs-builder-giveaway-leave-" + interaction.message.id, // Dynamic ID
|
|
2883
|
+
style: 4, // Danger Red
|
|
2884
|
+
},
|
|
2885
|
+
],
|
|
2886
|
+
]);
|
|
2887
|
+
return interaction.reply({
|
|
2888
|
+
content:
|
|
2889
|
+
"⚠️ You have **already joined** this giveaway! You can **leave** by clicking the button below.",
|
|
2890
|
+
components: row,
|
|
2891
|
+
flags: 64,
|
|
2892
|
+
});
|
|
2893
|
+
}
|
|
2894
|
+
|
|
2895
|
+
// Show error (e.g. Missing Role)
|
|
1095
2896
|
return interaction.reply({
|
|
1096
|
-
content:
|
|
1097
|
-
|
|
1098
|
-
components: row,
|
|
1099
|
-
flags: 64, // Ephemeral reply
|
|
2897
|
+
content: result.error,
|
|
2898
|
+
flags: 64,
|
|
1100
2899
|
});
|
|
1101
2900
|
}
|
|
1102
2901
|
|
|
@@ -1208,8 +3007,9 @@ if (giveawayData) {
|
|
|
1208
3007
|
"channelId": "876543210987654321", // 📢 Channel ID
|
|
1209
3008
|
"messageId": "987654321098765432", // 💬 Message ID of the giveaway post
|
|
1210
3009
|
"hoster": "112233445566778899", // 👤 User ID of the giveaway host
|
|
1211
|
-
|
|
1212
|
-
"
|
|
3010
|
+
"prize" : "code" // 🎁 prize
|
|
3011
|
+
"winnerCount": 1, // 🔢 Number of winners set
|
|
3012
|
+
"winners": [], // 🏆 Array of user IDs who won (empty if not ended)
|
|
1213
3013
|
"paused": false, // ⏸️ True if the giveaway is paused
|
|
1214
3014
|
"pausedTime": [], // ⏱️ Array of saved remaining times (used for resume)
|
|
1215
3015
|
"endTime": "1730995200000", // 📅 Timestamp (MS) of when the giveaway should end
|
|
@@ -1223,7 +3023,7 @@ if (giveawayData) {
|
|
|
1223
3023
|
"fields": [
|
|
1224
3024
|
{
|
|
1225
3025
|
"name": "🎉 Giveaway",
|
|
1226
|
-
"value": "-
|
|
3026
|
+
"value": "- Winner(s): 1\n- Time : <t:1730995200:R>\n- Hosted By : <@112233445566778899>",
|
|
1227
3027
|
"inline": true
|
|
1228
3028
|
}
|
|
1229
3029
|
]
|
|
@@ -1499,6 +3299,7 @@ module.exports = {
|
|
|
1499
3299
|
channelId: channel.id,
|
|
1500
3300
|
winers: winnerCount,
|
|
1501
3301
|
endTime: endTimeMs,
|
|
3302
|
+
prize: prize,
|
|
1502
3303
|
embed: {
|
|
1503
3304
|
title: `🎉 ${prize} Giveaway!`,
|
|
1504
3305
|
image: image,
|
|
@@ -1550,7 +3351,7 @@ module.exports = {
|
|
|
1550
3351
|
content: `${title}\n\n${listContent}`,
|
|
1551
3352
|
});
|
|
1552
3353
|
} else if (listContent.length <= MAX_EMBED_LENGTH) {
|
|
1553
|
-
// Output as an Embed (Over 2000, under
|
|
3354
|
+
// Output as an Embed (Over 2000, under 4000)
|
|
1554
3355
|
const embed = new EmbedBuilder()
|
|
1555
3356
|
.setTitle(title.replace(/\*\*/g, ""))
|
|
1556
3357
|
.setDescription(listContent)
|
|
@@ -1561,7 +3362,7 @@ module.exports = {
|
|
|
1561
3362
|
embeds: [embed],
|
|
1562
3363
|
});
|
|
1563
3364
|
} else {
|
|
1564
|
-
// Output as an attachment/JSON file (Over
|
|
3365
|
+
// Output as an attachment/JSON file (Over 4000 chars)
|
|
1565
3366
|
const jsonFile = new AttachmentBuilder(
|
|
1566
3367
|
Buffer.from(JSON.stringify(giveaways, null, 2)),
|
|
1567
3368
|
{ name: `${type}_giveaways_list.json` }
|
|
@@ -1768,6 +3569,8 @@ module.exports = {
|
|
|
1768
3569
|
|
|
1769
3570
|
</details>
|
|
1770
3571
|
|
|
3572
|
+
---
|
|
3573
|
+
|
|
1771
3574
|
</details>
|
|
1772
3575
|
|
|
1773
3576
|
---
|
|
@@ -1779,9 +3582,7 @@ module.exports = {
|
|
|
1779
3582
|
|
|
1780
3583
|
The **Blacklist System** allows you to block specific **users**, **roles**, or **channels** from using your bot's commands. This is useful for moderation and preventing abuse.
|
|
1781
3584
|
|
|
1782
|
-
> **Note**: To use this module, you **MUST** have **DATABASE** connection.
|
|
1783
|
-
|
|
1784
|
-
> **Note**: You can get all data by requiring the **Blacklist** module.
|
|
3585
|
+
> **Note 1**: To use this module, you **MUST** have **DATABASE** connection. | **Note 2**: You can get all data by requiring the **Blacklist** module.
|
|
1785
3586
|
|
|
1786
3587
|
---
|
|
1787
3588
|
|
|
@@ -1845,10 +3646,12 @@ console.log("Role unblacklisted! 🔓");
|
|
|
1845
3646
|
Returns an array of blacklisted items for a guild. You can optionally filter by type (`user`, `role`, `channel`).
|
|
1846
3647
|
|
|
1847
3648
|
**Parameters:**
|
|
3649
|
+
|
|
1848
3650
|
- `guildId` (String): The ID of the guild.
|
|
1849
3651
|
- `type` (String, optional): The type to filter by (`user`, `role`, `channel`).
|
|
1850
3652
|
|
|
1851
3653
|
**Example:**
|
|
3654
|
+
|
|
1852
3655
|
```js
|
|
1853
3656
|
// Get all blacklisted items
|
|
1854
3657
|
const allBlacklisted = await getBlacklist("GUILD_ID");
|
|
@@ -1873,35 +3676,80 @@ Output:
|
|
|
1873
3676
|
You can create a slash command to manage the blacklist easily.
|
|
1874
3677
|
|
|
1875
3678
|
```js
|
|
1876
|
-
const {
|
|
1877
|
-
|
|
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");
|
|
1878
3690
|
|
|
1879
3691
|
module.exports = {
|
|
1880
3692
|
data: new SlashCommandBuilder()
|
|
1881
3693
|
.setName("blacklist")
|
|
1882
3694
|
.setDescription("Manage the blacklist")
|
|
1883
3695
|
.setDefaultMemberPermissions(PermissionFlagsBits.Administrator)
|
|
1884
|
-
.addSubcommand(sub =>
|
|
1885
|
-
sub
|
|
1886
|
-
.
|
|
1887
|
-
.
|
|
1888
|
-
.
|
|
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
|
+
)
|
|
1889
3709
|
)
|
|
1890
|
-
.addSubcommand(sub =>
|
|
1891
|
-
sub
|
|
1892
|
-
.
|
|
1893
|
-
.
|
|
1894
|
-
.
|
|
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
|
+
)
|
|
1895
3723
|
)
|
|
1896
|
-
.addSubcommand(sub =>
|
|
1897
|
-
sub
|
|
1898
|
-
.
|
|
1899
|
-
.
|
|
1900
|
-
.
|
|
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
|
+
)
|
|
1901
3737
|
)
|
|
1902
|
-
.addSubcommand(sub =>
|
|
1903
|
-
sub
|
|
1904
|
-
.
|
|
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
|
+
)
|
|
1905
3753
|
),
|
|
1906
3754
|
async run(interaction) {
|
|
1907
3755
|
const sub = interaction.options.getSubcommand();
|
|
@@ -1911,54 +3759,95 @@ module.exports = {
|
|
|
1911
3759
|
const guildId = interaction.guild.id;
|
|
1912
3760
|
|
|
1913
3761
|
if (sub === "list") {
|
|
1914
|
-
|
|
1915
|
-
|
|
3762
|
+
const type = interaction.options.getString("type");
|
|
3763
|
+
if (type !== "all") {
|
|
1916
3764
|
const list = await getBlacklist(guildId, type);
|
|
1917
3765
|
|
|
1918
|
-
if (!list.length)
|
|
3766
|
+
if (!list.length)
|
|
3767
|
+
return interaction.reply({
|
|
3768
|
+
content: "✅ No blacklisted items found.",
|
|
3769
|
+
flags: 64,
|
|
3770
|
+
});
|
|
1919
3771
|
|
|
1920
3772
|
const embed = new EmbedBuilder()
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
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 {
|
|
1927
3793
|
const list = await getBlacklist(guildId);
|
|
1928
|
-
if (!list.length)
|
|
3794
|
+
if (!list.length)
|
|
3795
|
+
return interaction.reply({
|
|
3796
|
+
content: "✅ No blacklisted items found.",
|
|
3797
|
+
flags: 64,
|
|
3798
|
+
});
|
|
1929
3799
|
|
|
1930
3800
|
const embeds = [];
|
|
1931
|
-
const roles = list.filter(i => i.type === "role");
|
|
1932
|
-
const users = list.filter(i => i.type === "user");
|
|
1933
|
-
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");
|
|
1934
3804
|
|
|
1935
3805
|
if (users.length) {
|
|
1936
|
-
|
|
3806
|
+
const userEmbed = new EmbedBuilder()
|
|
1937
3807
|
.setTitle("🚫 Blacklisted Users")
|
|
1938
3808
|
.setColor("Red")
|
|
1939
|
-
.setDescription(
|
|
1940
|
-
|
|
3809
|
+
.setDescription(
|
|
3810
|
+
users
|
|
3811
|
+
.map((item) => `• <@${item.id}> (\`${item.id}\`)`)
|
|
3812
|
+
.join("\n")
|
|
3813
|
+
.slice(0, 4000)
|
|
3814
|
+
);
|
|
3815
|
+
embeds.push(userEmbed);
|
|
1941
3816
|
}
|
|
1942
|
-
if(
|
|
1943
|
-
|
|
3817
|
+
if (roles.length) {
|
|
3818
|
+
const roleEmbed = new EmbedBuilder()
|
|
1944
3819
|
.setTitle("🚫 Blacklisted Roles")
|
|
1945
3820
|
.setColor("Red")
|
|
1946
|
-
.setDescription(
|
|
1947
|
-
|
|
3821
|
+
.setDescription(
|
|
3822
|
+
roles
|
|
3823
|
+
.map((item) => `• <@&${item.id}> (\`${item.id}\`)`)
|
|
3824
|
+
.join("\n")
|
|
3825
|
+
.slice(0, 4000)
|
|
3826
|
+
);
|
|
3827
|
+
embeds.push(roleEmbed);
|
|
1948
3828
|
}
|
|
1949
|
-
if(
|
|
1950
|
-
|
|
3829
|
+
if (channels.length) {
|
|
3830
|
+
const channelEmbed = new EmbedBuilder()
|
|
1951
3831
|
.setTitle("🚫 Blacklisted Channels")
|
|
1952
3832
|
.setColor("Red")
|
|
1953
|
-
.setDescription(
|
|
1954
|
-
|
|
3833
|
+
.setDescription(
|
|
3834
|
+
channels
|
|
3835
|
+
.map((item) => `• <#${item.id}> (\`${item.id}\`)`)
|
|
3836
|
+
.join("\n")
|
|
3837
|
+
.slice(0, 4000)
|
|
3838
|
+
);
|
|
3839
|
+
embeds.push(channelEmbed);
|
|
1955
3840
|
}
|
|
1956
|
-
return interaction.reply({ embeds, flags
|
|
3841
|
+
return interaction.reply({ embeds, flags: 64 });
|
|
3842
|
+
}
|
|
1957
3843
|
}
|
|
1958
|
-
|
|
1959
|
-
|
|
3844
|
+
|
|
1960
3845
|
if (!user && !role && !channel) {
|
|
1961
|
-
return interaction.reply({
|
|
3846
|
+
return interaction.reply({
|
|
3847
|
+
content:
|
|
3848
|
+
"⚠️ You must provide at least one option (User, Role, or Channel).",
|
|
3849
|
+
flags: 64,
|
|
3850
|
+
});
|
|
1962
3851
|
}
|
|
1963
3852
|
const target = user || role || channel;
|
|
1964
3853
|
const type = user ? "user" : role ? "role" : "channel";
|
|
@@ -1966,18 +3855,25 @@ module.exports = {
|
|
|
1966
3855
|
|
|
1967
3856
|
if (sub === "add") {
|
|
1968
3857
|
const success = await addToBlacklist(guildId, type, id);
|
|
1969
|
-
if (success)
|
|
1970
|
-
|
|
3858
|
+
if (success)
|
|
3859
|
+
interaction.reply(`✅ Added **${type}** ${target} to blacklist.`);
|
|
3860
|
+
else
|
|
3861
|
+
interaction.reply(`⚠️ **${type}** ${target} is already blacklisted.`);
|
|
1971
3862
|
} else if (sub === "remove") {
|
|
1972
3863
|
const success = await removeFromBlacklist(guildId, type, id);
|
|
1973
|
-
if (success)
|
|
3864
|
+
if (success)
|
|
3865
|
+
interaction.reply(`✅ Removed **${type}** ${target} from blacklist.`);
|
|
1974
3866
|
else interaction.reply(`⚠️ **${type}** ${target} is not blacklisted.`);
|
|
1975
3867
|
} else if (sub === "check") {
|
|
1976
3868
|
const isBlocked = await isBlacklisted(guildId, type, id);
|
|
1977
|
-
if (isBlocked)
|
|
1978
|
-
|
|
3869
|
+
if (isBlocked)
|
|
3870
|
+
interaction.reply(
|
|
3871
|
+
`🚫 **${type}** ${target} is currently **blacklisted**.`
|
|
3872
|
+
);
|
|
3873
|
+
else
|
|
3874
|
+
interaction.reply(`✅ **${type}** ${target} is **not** blacklisted.`);
|
|
1979
3875
|
}
|
|
1980
|
-
}
|
|
3876
|
+
},
|
|
1981
3877
|
};
|
|
1982
3878
|
```
|
|
1983
3879
|
|
|
@@ -2111,6 +4007,224 @@ execute: Function // 🏃♂️ Alternative function to run the
|
|
|
2111
4007
|
|
|
2112
4008
|
---
|
|
2113
4009
|
|
|
4010
|
+
## 🌐 DASHBOARD
|
|
4011
|
+
|
|
4012
|
+
The **Dashboard System** is a modern, lightweight web-based control panel for your Discord bot. It provides a beautiful interface to manage your bot, servers, levels, giveaways, and more! 🎛️🚀
|
|
4013
|
+
|
|
4014
|
+
**Features:**
|
|
4015
|
+
|
|
4016
|
+
- 🔐 **Discord OAuth2 Login** – Secure authentication with Discord.
|
|
4017
|
+
- 📊 **Bot Statistics** – View real-time bot stats (servers, users, commands, uptime).
|
|
4018
|
+
- 🏠 **Server Management** – Manage servers where you have admin permissions.
|
|
4019
|
+
- 📜 **Commands Viewer** – Browse all slash and prefix commands.
|
|
4020
|
+
- 🏆 **Level System Management** – View leaderboards, manage user XP and levels.
|
|
4021
|
+
- 🎉 **Giveaway Control** – Pause, resume, end, reroll, or delete giveaways.
|
|
4022
|
+
- 🦾 **Logging System Control** – Manage log channels, colors, and event toggles.
|
|
4023
|
+
- 🚫 **Blacklist Management** – Add/remove users, roles, or channels from blacklist.
|
|
4024
|
+
- 🎨 **Modern UI** – Beautiful, responsive design with dark mode support.
|
|
4025
|
+
|
|
4026
|
+
> **Note**: This module requires **express**, **express-session**, **passport**, and **passport-discord** packages. | **Note 2**: You must have a **DATABASE** connection for full functionality.
|
|
4027
|
+
|
|
4028
|
+
> 💡 **Tip:** You can use Dashboard with the starter function (see [Starter](#starter)) or as a standalone function!
|
|
4029
|
+
|
|
4030
|
+
---
|
|
4031
|
+
|
|
4032
|
+
<details>
|
|
4033
|
+
<summary>Dashboard with Starter ⚙️</summary>
|
|
4034
|
+
|
|
4035
|
+
When using with starter, simply add the `dashboard` option to your starter configuration:
|
|
4036
|
+
|
|
4037
|
+
```js
|
|
4038
|
+
const { starter } = require("djs-builder");
|
|
4039
|
+
const { Client, GatewayIntentBits } = require("discord.js");
|
|
4040
|
+
|
|
4041
|
+
const client = new Client({
|
|
4042
|
+
intents: Object.keys(GatewayIntentBits).map((a) => GatewayIntentBits[a]),
|
|
4043
|
+
});
|
|
4044
|
+
|
|
4045
|
+
const starterOptions = {
|
|
4046
|
+
bot: {
|
|
4047
|
+
token: "YOUR_BOT_TOKEN",
|
|
4048
|
+
ownerId: "YOUR_USER_ID",
|
|
4049
|
+
},
|
|
4050
|
+
terminal: true,
|
|
4051
|
+
|
|
4052
|
+
// 🌐 Dashboard Configuration
|
|
4053
|
+
dashboard: {
|
|
4054
|
+
clientSecret: "YOUR_DISCORD_CLIENT_SECRET", // 🔐 Discord Application Client Secret
|
|
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)
|
|
4058
|
+
},
|
|
4059
|
+
|
|
4060
|
+
// ... other options (Status, database, anticrash, etc.)
|
|
4061
|
+
};
|
|
4062
|
+
|
|
4063
|
+
await starter(client, starterOptions);
|
|
4064
|
+
```
|
|
4065
|
+
|
|
4066
|
+
</details>
|
|
4067
|
+
|
|
4068
|
+
---
|
|
4069
|
+
|
|
4070
|
+
<details>
|
|
4071
|
+
<summary>Dashboard Standalone Usage 🔧</summary>
|
|
4072
|
+
|
|
4073
|
+
You can use the Dashboard as a **standalone function** without the starter! This is useful if you already have your own bot setup or want more control.
|
|
4074
|
+
|
|
4075
|
+
```js
|
|
4076
|
+
const { dashboard } = require("djs-builder");
|
|
4077
|
+
const { Client, GatewayIntentBits } = require("discord.js");
|
|
4078
|
+
|
|
4079
|
+
const client = new Client({
|
|
4080
|
+
intents: Object.keys(GatewayIntentBits).map((a) => GatewayIntentBits[a]),
|
|
4081
|
+
});
|
|
4082
|
+
|
|
4083
|
+
// 🔑 Login your bot first
|
|
4084
|
+
client.login("YOUR_BOT_TOKEN");
|
|
4085
|
+
|
|
4086
|
+
client.once("ready", () => {
|
|
4087
|
+
console.log(`✅ Logged in as ${client.user.tag}`);
|
|
4088
|
+
|
|
4089
|
+
// 🌐 Start the Dashboard
|
|
4090
|
+
dashboard(client, {
|
|
4091
|
+
clientSecret: "YOUR_DISCORD_CLIENT_SECRET", // 🔐 Discord Application Client Secret
|
|
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)
|
|
4095
|
+
});
|
|
4096
|
+
});
|
|
4097
|
+
```
|
|
4098
|
+
|
|
4099
|
+
> 💡 **Tip:** When using standalone, make sure your bot is logged in before starting the dashboard!
|
|
4100
|
+
|
|
4101
|
+
</details>
|
|
4102
|
+
|
|
4103
|
+
---
|
|
4104
|
+
|
|
4105
|
+
<details>
|
|
4106
|
+
<summary>Dashboard Routes & API 📡</summary>
|
|
4107
|
+
|
|
4108
|
+
### 📌 Dashboard Routes
|
|
4109
|
+
|
|
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 |
|
|
4120
|
+
|
|
4121
|
+
---
|
|
4122
|
+
|
|
4123
|
+
### 📡 API Endpoints
|
|
4124
|
+
|
|
4125
|
+
The dashboard exposes several API endpoints for dynamic data:
|
|
4126
|
+
|
|
4127
|
+
```js
|
|
4128
|
+
// 📊 Get bot statistics
|
|
4129
|
+
GET /api/stats
|
|
4130
|
+
|
|
4131
|
+
// 🏠 Get server statistics
|
|
4132
|
+
GET /api/:guildId/stats
|
|
4133
|
+
|
|
4134
|
+
// 👤 Get user level data
|
|
4135
|
+
GET /api/:guildId/user/:userId
|
|
4136
|
+
|
|
4137
|
+
// 🔍 Search members
|
|
4138
|
+
GET /api/:guildId/members/search?q=query
|
|
4139
|
+
|
|
4140
|
+
// 🏆 Level management
|
|
4141
|
+
POST /api/:guildId/level/update // Update user level
|
|
4142
|
+
POST /api/:guildId/level/add // Add XP to user
|
|
4143
|
+
POST /api/:guildId/level/reset // Reset user level
|
|
4144
|
+
|
|
4145
|
+
// 🎉 Giveaway actions
|
|
4146
|
+
POST /api/:guildId/giveaway/pause
|
|
4147
|
+
POST /api/:guildId/giveaway/resume
|
|
4148
|
+
POST /api/:guildId/giveaway/end
|
|
4149
|
+
POST /api/:guildId/giveaway/reroll
|
|
4150
|
+
POST /api/:guildId/giveaway/delete
|
|
4151
|
+
|
|
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
|
|
4159
|
+
POST /api/guild/:guildId/blacklist // Add to blacklist
|
|
4160
|
+
DELETE /api/guild/:guildId/blacklist // Remove from blacklist
|
|
4161
|
+
```
|
|
4162
|
+
|
|
4163
|
+
</details>
|
|
4164
|
+
|
|
4165
|
+
---
|
|
4166
|
+
|
|
4167
|
+
<details>
|
|
4168
|
+
<summary>Dashboard Options 🔧</summary>
|
|
4169
|
+
|
|
4170
|
+
### 🔧 Configuration Options
|
|
4171
|
+
|
|
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) |
|
|
4178
|
+
|
|
4179
|
+
---
|
|
4180
|
+
|
|
4181
|
+
### 📁 View Templates
|
|
4182
|
+
|
|
4183
|
+
The dashboard uses **EJS** templates located in the `views` folder:
|
|
4184
|
+
|
|
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 |
|
|
4196
|
+
|
|
4197
|
+
</details>
|
|
4198
|
+
|
|
4199
|
+
---
|
|
4200
|
+
|
|
4201
|
+
<details>
|
|
4202
|
+
<summary>Discord Developer Portal Setup 🛠️</summary>
|
|
4203
|
+
|
|
4204
|
+
### 🛠️ How to Get Client ID & Secret
|
|
4205
|
+
|
|
4206
|
+
1. Go to [Discord Developer Portal](https://discord.com/developers/applications) 🌐
|
|
4207
|
+
2. Create a new application or select existing one 📱
|
|
4208
|
+
3. Go to **OAuth2** → **General** 🔐
|
|
4209
|
+
4. Copy the **Client ID** and **Client Secret** 📋
|
|
4210
|
+
5. Add your **Redirect URL** (e.g., `http://localhost:3000/auth/discord/callback`) ✅
|
|
4211
|
+
6. Make sure to add the URL to **Redirects** list 📝
|
|
4212
|
+
|
|
4213
|
+
---
|
|
4214
|
+
|
|
4215
|
+
### 💡 Tips & Notes
|
|
4216
|
+
|
|
4217
|
+
- 🔒 **Keep secrets safe** – Never expose `clientSecret` or `sessionSecret` publicly.
|
|
4218
|
+
- 🌐 **Production URL** – Update `callbackURL` when deploying to production.
|
|
4219
|
+
- 🗄️ **Database Required** – Level and Giveaway features require MongoDB connection.
|
|
4220
|
+
- 🎨 **Customizable** – Edit EJS templates to customize the look and feel.
|
|
4221
|
+
- 🔄 **Real-time Stats** – Bot statistics update automatically.
|
|
4222
|
+
- 🛡️ **Secure** – Only admins can manage their servers.
|
|
4223
|
+
|
|
4224
|
+
</details>
|
|
4225
|
+
|
|
4226
|
+
---
|
|
4227
|
+
|
|
2114
4228
|
## 💌 Support
|
|
2115
4229
|
|
|
2116
4230
|
We welcome contributions! If you have any suggestions, bug reports, or feature requests, feel free to reach out to us on Discord.
|
|
@@ -2119,4 +4233,4 @@ We welcome contributions! If you have any suggestions, bug reports, or feature r
|
|
|
2119
4233
|
|
|
2120
4234
|
🌐 **Join our Discord:**
|
|
2121
4235
|
|
|
2122
|
-
[](https://discord.gg/uYcKCZk3)
|