npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

Iโ€™ve always been into building performant and accessible sites, but lately Iโ€™ve been taking it extremely seriously. So much so that Iโ€™ve been building a tool to help me optimize and monitor the sites that I build to make sure that Iโ€™m making an attempt to offer the best experience to those who visit them. If youโ€™re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, ๐Ÿ‘‹, Iโ€™m Ryan Hefnerย  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If youโ€™re interested in other things Iโ€™m working on, follow me on Twitter or check out the open source projects Iโ€™ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soonโ€“ish.

Open Software & Tools

This site wouldnโ€™t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you ๐Ÿ™

ยฉ 2026 โ€“ย Pkg Stats / Ryan Hefner

djs-builder

v0.7.9

Published

๐ŸŽ‰ Full-featured Discord.js utilities: CreateComponents, CreateModal, Dashboard, Logging & more! ๐Ÿฅ

Readme

Example Image

Typing SVG

Welcome to the ultimate Discord Bot Utilities package! ๐Ÿฅ Boost your Discord bot development with ease, speed, and all-in-one features.

Discord Banner


๐Ÿ“‘ Table of Contents

  1. ๐ŸŽฏ Starter โ€“ Initialize your bot with commands, events, presence, and more.
  2. โš™๏ธ Functions โ€“ Utilities like CreateRow, CreateBar, Wait, and GetUser.
  3. โšก Commands & Events โ€“ Easy setup with cooldowns, permissions, logging, and anti-crash.
  4. ๐ŸŒ Dashboard โ€“ Web-based control panel for managing your bot.

๐ŸŽฏ STARTER

The starter function is the ultimate initializer for your Discord bot ๐Ÿค–. It handles everything from logging in, loading commands/events, setting the bot presence, anti-crash protection, logging commands usage, and even checking for library updates.

Features:

  • ๐Ÿ› ๏ธ One-line loader for both Slash & Prefix commands ๐Ÿ”ฉ
  • ๐Ÿ“œ Comprehensive terminal info display (commands, events, bot stats) ๐Ÿ“Š
  • ๐Ÿงฐ Event handler loader in one line ๐ŸŽ‰
  • โš ๏ธ Anti-crash system with automatic webhook reporting ๐Ÿ“ƒ
  • ๐Ÿ”‹ MongoDB connection support ๐Ÿ“ฅ
  • ๐Ÿ“‘ Command logger for both Slash and Prefix commands ๐Ÿงญ
  • ๐Ÿ’ก Supports custom prefixes per guild and cooldowns โณ
  • ๐Ÿ”ผ Automatic update checker for djs-builder ๐Ÿ“ฆ

๐Ÿ’ก Tip: Any option you donโ€™t want, just remove it ๐Ÿ—‘๏ธ.


const { starter } = require("djs-builder");
const { Client, GatewayIntentBits } = require("discord.js");

const client = new Client({
  intents: Object.keys(GatewayIntentBits).map((a) => GatewayIntentBits[a]),
});

// Define starter options
const starterOptions = {
  bot: {
    token: "YOUR_BOT_TOKEN", // ๐Ÿ”‘ Discord bot token
    ownerId: "YOUR_USER_ID", // ๐Ÿ‘ค Bot owner ID
  },
  terminal: true, // ๐Ÿ–ฅ๏ธ Show bot info in terminal

  Status: {
    status: "online", // โœ… Presence state: online, dnd, idle, offline
    activities: ["Game 1", "Game 2"], // ๐ŸŽฎ Multiple activities
    type: 0, // ๐ŸŽญ Activity type: (0=PLAYING, 1=STREAMING, 2=LISTENING, 3=WATCHING)
    time: 60000, // โฑ๏ธ Rotate activities every X ms
    url: "https://twitch.tv/example", // ๐ŸŒ Twitch URL (only required for streaming)
  },

  database: {
    url: "mongodb://localhost:27017", // ๐Ÿ’พ MongoDB connection
    dbName: "yourDatabaseName", // ๐Ÿ“ Optional: Specify database name (default: "test")
  },

  anticrash: {
    url: "https://your.crash.webhook.url", // ๐Ÿšจ Webhook for crash reports
    mention_id: "YOUR_USER_ID", // ๐Ÿ“ฃ Optional: mention user on crash
  },

  // ๐ŸŒ Dashboard Configuration (Full docs at the end of this page)
  dashboard: {
    clientSecret: "YOUR_DISCORD_CLIENT_SECRET", // ๐Ÿ” Discord Application Client Secret
    callbackURL: "http://localhost:3000/auth/discord/callback", // ๐Ÿ”— OAuth2 Callback URL (OPTINAL)
    sessionSecret: "your-super-secret-key", // ๐Ÿ”’ Session encryption secret
    port: 3000, // ๐ŸŒ Dashboard port (OPTINAL / default: 3000)
  },
};

// Start the bot
await starter(client, starterOptions);

๐Ÿ“Œ How Starter Works

1๏ธโƒฃ Bot Login & Status

  • Authenticates the bot using your token ๐Ÿ”‘.
  • Supports multiple rotating activities (e.g., Game 1 โ†’ Game 2 โ†’ โ€ฆ) โฑ๏ธ.
  • Works with all Discord activity types: PLAYING, STREAMING, LISTENING, WATCHING ๐ŸŽญ.
  • Twitch URL is supported for streaming mode ๐ŸŒ.

2๏ธโƒฃ Database Connection

  • Connects automatically to MongoDB ๐Ÿ’พ.
  • Useful for bots with persistent data storage.
  • Specify the database name using the dbName option. If not specified, MongoDB uses "test" as the default database name.

3๏ธโƒฃ Anticrash System

  • Catches and logs:

    • unhandledRejection
    • uncaughtException
    • uncaughtExceptionMonitor
    • unhandledRejectionMonitor
    • warning โš ๏ธ
  • Sends error reports to a webhook ๐Ÿšจ.

  • Optionally pings the owner ๐Ÿ“ฃ.

4๏ธโƒฃ Terminal Info

  • Displays colorful and structured information ๐Ÿ–ฅ๏ธ:

    • Bot name, user, guild, and channel counts ๐Ÿ“Š.
    • Owner ID ๐Ÿ‘ค.
    • Database connection status ๐Ÿ’พ.
    • Uptime โณ.
  • Powered by cli-table3 + chalk for a professional CLI look ๐ŸŽจ.

5๏ธโƒฃ Auto Update Checker

  • Monitors new versions of djs-builder automatically ๐Ÿ”„.
  • Sends update notifications to the webhook ๐ŸŽ‰.

6๏ธโƒฃ Bot Files Information

  • Access detailed stats about loaded files directly from the client:

    • Number of prefix commands โšก.
    • Number of slash commands โš”๏ธ.
    • Number of events ๐ŸŽ‰.
  • Available via client.files, useful for debugging or terminal display ๐Ÿ› ๏ธ.

7๏ธโƒฃ Dashboard (Web Control Panel)

  • Launches a modern web-based control panel for your bot ๐ŸŒ.
  • Supports Discord OAuth2 authentication ๐Ÿ”.
  • Manage servers, levels, giveaways, and blacklists from the browser ๐ŸŽ›๏ธ.

๐Ÿ“– Full Dashboard documentation available at the end of this page โ†’ ๐ŸŒ DASHBOARD


๐Ÿ’ก Tips

  • Flexible: Delete any section you donโ€™t need (anticrash, database, etc.) ๐Ÿ—‘๏ธ.
  • Multi-Status: Add as many activities as you want and let them rotate ๐ŸŽฎ.
  • Safe by Default: Anticrash system ensures your bot wonโ€™t go down easily ๐Ÿ›ก๏ธ.
  • Always Up-to-Date: Automatic update checker keeps your bot running on the latest version โฌ†๏ธ.
  • Transparent: Quickly check how many files your bot has loaded anytime ๐Ÿ“Š.


โš™๏ธ functions

  • Easiest โœจ / Fastest โšก /Clear ๐Ÿงต

Than the discord.js


๐Ÿ”ต CreateRow โ€“ Easily create Discord Action Rows with Buttons & Select Menus โœจ

CreateRow is a powerful utility to build Discord Action Rows. It supports:

  • Buttons โœ…
  • Select Menus ๐ŸŽฏ (string, role, user, channel)
  • Advanced options like defaultValues and channelTypes.

๐Ÿ“Œ Example Usage:

const { CreateRow } = require("djs-builder");

const actionRow = new CreateRow([
  //// For each new row, use [] for buttons or {} for a select menu

  // ๐Ÿ”น Row #1: Buttons
  [
    {
      id: "button1", // customId for the button
      style: 1, // Button styles: Primary(1), Secondary(2), Success(3), Danger(4), Link(5)
      label: "Primary Button", // Text shown on button
      emoji: "๐Ÿ˜ƒ", // Emoji displayed
      disabled: false, // true = disabled
    },
    {
      id: "button2",
      style: 2,
      emoji: "๐Ÿš€",
      disabled: true, // Button is disabled
    },
    {           
      style: 5,
      label: "link",
      emoji: "๐Ÿ”—" 
      url : "https://discord.gg/z9GpYsYF" // for url button
    }
  ],

  // ๐Ÿ”น Row #2: Select Menu
  {
    type: "string", // Options: "string" | "role" | "user" | "channel"
    options: {
      id: "menu1", // customId for the select menu
      placeholder: "Select an option",
      min: 1, // Minimum selection
      max: 2, // Maximum selection

      // ๐Ÿ”ธ Data for string select only
      data: [
        {
          name: "Option 1",
          id: "opt1",
          about: "First option",
          icon: "๐ŸŒŸ",
          default: true,
        },
        { name: "Option 2", id: "opt2", about: "Second option", icon: "๐Ÿš€" },
        { name: "Option 3", id: "opt3", about: "Third option", icon: "๐Ÿ”—" },
      ],

      // ๐Ÿ”ธ Map keys
      label: "name", // Which field is the label
      value: "id", // Which field is the value
      description: "about", // Description for each option
      emoji: "icon", // Emoji for each option

      // ๐Ÿ”ธ Extra options
      disabled: false, // Disable the entire menu
      defaultValues: [
        // For role/user/channel menus
        { id: "123456789012345678" }, // Pre-selected
      ],
      channelTypes: [0, 2], // Only for ChannelSelectMenu (0 = Text, 2 = Voice)
    },
  },
]);

๐Ÿ“– Explanation

๐Ÿ”น Buttons

  • id โ†’ customId for the button
  • style โ†’ 1: Primary, 2: Secondary, 3: Success, 4: Danger, 5: Link
  • label โ†’ Button text
  • emoji โ†’ Displayed emoji
  • disabled โ†’ true = button is unclickable
  • url โ†’ requiier for like button (style : 5)

๐Ÿ”น Select Menus

  • type โ†’ "string" | "user" | "role" | "channel"

  • id โ†’ customId for menu

  • placeholder โ†’ Text shown before selection

  • min / max โ†’ Min/Max selectable values

  • data โ†’ Options array (for string select only)

    • label โ†’ Visible text
    • value โ†’ Internal value
    • description โ†’ Short description
    • emoji โ†’ Option emoji
    • default โ†’ Pre-selected option
  • disabled โ†’ Disable menu completely

  • defaultValues โ†’ Pre-selected user/role/channel options

  • channelTypes โ†’ Restrict selectable channel types


๐Ÿงพ CreateBar โ€“ Text-based Progress Bar for Discord โœจ

CreateBar allows you to display a customizable progress bar with optional percentages and partial symbols. Perfect for showing progress, loading, or stats in messages.


๐Ÿ“Œ Basic Example:

const { CreateBar } = require("djs-builder");

const bar = new CreateBar(7, 10, {
  length: 20, // Total length of the bar
  fill: "๐Ÿ’š", // Filled portion
  empty: "๐Ÿ–ค", // Empty portion
  partialChar: "๐Ÿ’›", // Partial fill
  showPercent: true, // Show percentage
  left: "โฐ", // Left bracket
  right: "โฑ", // Right bracket
});

console.log(bar);
// Output: โฐ๐Ÿ’š๐Ÿ’š๐Ÿ’š๐Ÿ’š๐Ÿ’š๐Ÿ’š๐Ÿ’š๐Ÿ’›๐Ÿ–ค๐Ÿ–ค๐Ÿ–ค๐Ÿ–ค๐Ÿ–ค๐Ÿ–ค๐Ÿ–ค๐Ÿ–ค๐Ÿ–ค๐Ÿ–คโฑ 70%

๐Ÿ“Œ Another Example with different symbols:

console.log(
  CreateBar(3.7, 5, {
    fill: "๐ŸŸฆ",
    empty: "โฌ›",
    partialChar: "๐ŸŸจ",
    length: 10,
    left: "โฐ",
    right: "โฑ",
    showPercent: true,
  })
);

// Output: โฐ๐ŸŸฆ๐ŸŸฆ๐ŸŸฆ๐ŸŸจโฌ›โฌ›โฌ›โฌ›โฌ›โฌ›โฑ 74%

๐Ÿ“Œ Minimalist example without percentage:

console.log(
  CreateBar(4, 8, {
    fill: "๐Ÿ”ต",
    empty: "โšช",
    showPercent: false,
  })
);

// Output: ๐Ÿ”ต๐Ÿ”ต๐Ÿ”ต๐Ÿ”ตโšชโšชโšชโšช

๐Ÿ“Œ Fun Emoji example:

console.log(
  CreateBar(6, 10, {
    length: 12,
    fill: "๐Ÿ”ฅ",
    empty: "โ„๏ธ",
    partialChar: "๐ŸŒŸ",
    showPercent: true,
    left: "ยซ",
    right: "ยป",
  })
);

// Output: ยซ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐ŸŒŸโ„๏ธโ„๏ธโ„๏ธโ„๏ธยป 60%

๐Ÿ”น Options Summary

  • length โ†’ Total number of symbols
  • fill โ†’ Symbol for filled portion
  • empty โ†’ Symbol for empty portion
  • partialChar โ†’ Symbol for partial fill (e.g., half-filled)
  • showPercent โ†’ Show percentage at the end
  • left / right โ†’ Brackets or edges for the bar

๐Ÿ”น Notes

  • Supports fractional values for partial fill
  • Fully customizable with any emoji or character ๐ŸŽจ
  • Great for progress, stats, experience bars, or loading indicators


๐Ÿ”ณ CreateModal โ€“ Easily create Discord Modals with Text Inputs, Menus, Files, and Labels โœจ

CreateModal is a powerful utility to build Discord Modals. It supports:

  • Text Inputs ๐Ÿ“
  • Select Menus ๐ŸŽฏ (string, role, user, channel)
  • File Uploads ๐Ÿ“Ž
  • Text Displays ๐Ÿท๏ธ

๐Ÿ“Œ Example Usage:

const { CreateModal } = require("djs-builder");

const modal = CreateModal({
  id: "myModal",
  title: "User Information",
  components: [
    {
      type: "textInput",
      components: [
        {
          label: "Your Name",
          id: "name",
          style: 1, // 1: Short, 2: Paragraph
          placeholder: "Enter your name",
          required: true,
          minLength: 2,
          maxLength: 50,
        },
      ],
    },
    {
      type: "menu",
      components: {
        type: "string",
        options: {
          id: "favoriteColor",
          placeholder: "Choose your favorite color",
          min: 1,
          max: 1,
          data: [
            {
              label: "Red",
              value: "red",
              description: "A bold color",
              emoji: "๐Ÿ”ด",
              default: false,
            },
            {
              label: "Blue",
              value: "blue",
              description: "A calm color",
              emoji: "๐Ÿ”ต",
            },
          ],
          label: "label",
          value: "value",
          description: "description",
          emoji: "emoji",
          disabled: false,
        },
      },
    },
    {
      type: "file",
      components: {
        id: "avatar",
        label: "Upload Avatar",
        description: "Optional avatar image",
      },
    },
    {
      type: "label",
      components: {
        label: "Thank you for your input!",
      },
    },
  ],
});

// Show the modal
await interaction.showModal(modal);

๐Ÿ“” Examples for Each Component Type:

๐Ÿ”น Text Input Example:

{
  type: "textInput",
  components: [
    {
      label: "Your Age",
      id: "age",
      style: 1, // Short input
      placeholder: "Enter your age",
      required: true,
      minLength: 1,
      maxLength: 3,
      value: "18", // Pre-filled
    },
  ],
},

๐Ÿ”น Menu Example:

{
  type: "menu",
  components: {
    type: "string",
    options: {
      id: "country",
      placeholder: "Select your country",
      min: 1,
      max: 1,
      data: [
        {
          name: "USA",
          id: "usa",
          desc: "United States",
          icon: "๐Ÿ‡บ๐Ÿ‡ธ",
          default: true, // This option is pre-selected
        },
        {
          name: "Canada",
          id: "canada",
          desc: "Canada",
          icon: "๐Ÿ‡จ๐Ÿ‡ฆ",
        },
      ],
      label: "name", // Maps to 'name' field in data
      value: "id",   // Maps to 'id' field in data
      description: "desc", // Maps to 'desc' field
      emoji: "icon", // Maps to 'icon' field
      disabled: false,
    },
  },
},

๐Ÿ”น File Example:

{
  type: "file",
  components: {
    id: "document",
    label: "Upload Document",
    description: "Upload a PDF or image",
  },
},

๐Ÿ”น Label Example:

{
  type: "label",
  components: {
    label: "Please fill out the form above.",
  },
},

๏ฟฝ๐Ÿ“– Explanation

๐Ÿ”น Text Input

  • label โ†’ Label for the input field
  • id โ†’ customId for the input
  • style โ†’ 1: Short, 2: Paragraph
  • placeholder โ†’ Placeholder text
  • required โ†’ true/false
  • minLength / maxLength โ†’ Min/Max characters
  • value โ†’ Pre-filled value

๐Ÿ”น Menu

Same as CreateRow select menus.

  • type โ†’ "string" | "user" | "role" | "channel"

  • id โ†’ customId for menu

  • placeholder โ†’ Text shown before selection

  • min / max โ†’ Min/Max selectable values

  • data โ†’ Options array (for string select only)

    • label โ†’ Visible text (maps to the field specified in label key)
    • value โ†’ Internal value (maps to the field specified in value key)
    • description โ†’ Short description (maps to the field specified in description key)
    • emoji โ†’ Option emoji (maps to the field specified in emoji key)
    • default โ†’ Pre-selected option (true/false in data array)
  • label โ†’ Key in data to use as label (e.g., "name")

  • value โ†’ Key in data to use as value (e.g., "id")

  • description โ†’ Key in data to use as description (e.g., "desc")

  • emoji โ†’ Key in data to use as emoji (e.g., "icon")

  • disabled โ†’ Disable menu completely

  • defaultValues โ†’ Pre-selected user/role/channel options (for non-string menus)

  • channelTypes โ†’ Restrict selectable channel types (for channel menu)

๐Ÿ”น File

  • id โ†’ customId for the file upload
  • label โ†’ Label
  • description โ†’ Description

๐Ÿ”น Label

  • label โ†’ Text to display

๐Ÿ”น Notes

  • Supports multiple components in one modal
  • Fully customizable with Discord.js ModalBuilder

๐Ÿงฉ CreateComponents โ€“ Build Advanced Discord UI Components with Containers, Sections & Media โœจ

CreateComponents is a powerful utility to build Discord's new UI components. It supports:

  • Text Displays ๐Ÿ“
  • Separators โž–
  • Media Galleries ๐Ÿ–ผ๏ธ
  • File Attachments ๐Ÿ“Ž
  • Buttons ๐Ÿ”˜
  • Select Menus ๐ŸŽฏ (string, role, user, channel)
  • Sections with Accessories ๐Ÿ“ฆ (Thumbnails & Buttons)
  • Containers ๐Ÿ“ฆ (Group all components together)

๐Ÿ“Œ Example Usage (Array Mode):

const { CreateComponents } = require("djs-builder");

const components = await CreateComponents("array", [
  {
    type: "text",
    content: "Welcome to our server! ๐ŸŽ‰",
  },
  {
    type: "separator",
    divider: true,
    spacing: 1, // 1: Small, 2: Large
  },
  {
    type: "media",
    links: [
      "https://example.com/image1.png",
      {
        url: "https://example.com/image2.png",
        description: "A cool image",
        spoiler: true,
      },
    ],
  },
  {
    type: "button",
    components: [
      {
        id: "btn_1",
        style: 1, // 1: Primary, 2: Secondary, 3: Success, 4: Danger, 5: Link
        label: "Click Me!",
        emoji: "๐Ÿš€",
      },
      {
        id: "btn_2",
        style: 3,
        label: "Confirm",
      },
    ],
  },
]);

// Send the components
await channel.send({ components });

๐Ÿ“Œ Example Usage (Container Mode):

const { CreateComponents } = require("djs-builder");

const components = await CreateComponents("container", [
  {
    type: "text",
    content: "# ๐Ÿ“ข Server Announcement\nWelcome everyone!",
  },
  {
    type: "separator",
    divider: true,
  },
  {
    type: "section",
    content: "Check out our latest updates and news!",
    accessory: {
      type: "thumbnail",
      url: "https://example.com/thumbnail.png",
      description: "News Image",
    },
  },
  {
    type: "section",
    content: "**Click below to get your roles!**",
    accessory: {
      type: "button",
      id: "get_roles",
      style: 1,
      label: "Get Roles",
      emoji: "๐ŸŽญ",
    },
  },
  {
    type: "media",
    links: ["https://example.com/banner.png"],
  },
  {
    type: "button",
    components: [
      { id: "rules", style: 2, label: "๐Ÿ“œ Rules", emoji: "๐Ÿ“œ" },
      { id: "help", style: 2, label: "โ“ Help", emoji: "โ“" },
      { style: 5, label: "๐ŸŒ Website", url: "https://example.com" },
    ],
  },
]);

// Send with container
await channel.send({ components, flags: 32768 }); // flags for components v2

๐Ÿ“œ Examples for Each Component Type:


๐Ÿ“Œ Simple Text:

{
  type: "text",
  content: "Hello World! ๐Ÿ‘‹",
}

๐Ÿ“Œ Text with Markdown:

{
  type: "text",
  content: "# ๐Ÿ“ข Announcement\n**Important:** Server maintenance tonight!",
}

๐Ÿ“Œ Text with Multiple Lines:

{
  type: "text",
  content: `## ๐ŸŽฎ Game Stats
  
**Player:** Ahmed
**Level:** 50
**XP:** 12,500 / 15,000
**Rank:** Diamond ๐Ÿ’Ž`,
}

๐Ÿ“Œ Text with Emojis & Formatting:

{
  type: "text",
  content: ">>> ๐Ÿ’ก **Tip:** Use `/help` to see all commands!\n\n*This message will auto-delete in 30 seconds*",
}

โž– Separator โ€“ Add spacing and dividers between components

The separator component allows you to add visual breaks between other components with customizable spacing and divider lines.


๐Ÿ“– Separator Options

| Option | Type | Default | Description | | --------- | --------- | ------- | -------------------------------------------------- | | type | string | โ€” | Must be "separator" | | divider | boolean | false | Show a horizontal dividing line | | spacing | number | 1 | Spacing size: 1 (Small) or 2 (Large) |


๐Ÿ“Œ Simple Divider Line:

{
  type: "separator",
  divider: true,
}

Result: A thin horizontal line appears between components.


๐Ÿ“Œ Separator without Line (Spacing Only):

{
  type: "separator",
  divider: false,
  spacing: 2, // Large spacing
}

Result: Empty space without any visible line - useful for visual grouping.


๐Ÿ“Œ Small Spacing with Divider:

{
  type: "separator",
  divider: true,
  spacing: 1, // Small spacing (default)
}

Result: A divider line with minimal padding above and below.


๐Ÿ“Œ Large Spacing with Divider:

{
  type: "separator",
  divider: true,
  spacing: 2, // Large spacing
}

Result: A divider line with more padding - creates stronger visual separation.


๐Ÿ’ก When to Use Each Option:

| Scenario | divider | spacing | | ------------------------------------- | --------- | --------- | | Separate major sections | true | 2 | | Separate sub-sections | true | 1 | | Group related items visually | false | 1 | | Create breathing room between content | false | 2 | | Minimal separation | false | 1 |


๐Ÿ–ผ๏ธ Media Gallery โ€“ Display images in a beautiful gallery format

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.


๐Ÿ“Œ Format 1: Simple String URLs

The simplest way - just pass image URLs as strings:

{
  type: "media",
  links: ["https://example.com/image.png"],
}

๐Ÿ“Œ Format 2: Object with Full Options

For more control, use objects with url, description, and spoiler:

{
  type: "media",
  links: [
    {
      url: "https://example.com/image.png",
      description: "A beautiful sunset",
      spoiler: false,
    },
  ],
}

๐Ÿ“Œ Single Image with Spoiler:

{
  type: "media",
  links: [
    {
      url: "https://example.com/spoiler.png",
      description: "โš ๏ธ Spoiler Alert!",
      spoiler: true,
    },
  ],
}

๐Ÿ“Œ Multiple Images (Simple Strings):

{
  type: "media",
  links: [
    "https://example.com/image1.png",
    "https://example.com/image2.png",
    "https://example.com/image3.png",
    "https://example.com/image4.png",
  ],
}

Result: A 2x2 gallery grid of images.


๐Ÿ“Œ Mixed Format (Strings + Objects):

You can mix simple strings with detailed objects in the same array:

{
  type: "media",
  links: [
    // Simple string - just the URL
    "https://example.com/public-image.png",
    
    // Object with description
    {
      url: "https://example.com/special-image.png",
      description: "Limited Edition Art",
    },
    
    // Object with spoiler
    {
      url: "https://example.com/secret-image.png",
      description: "Secret Content",
      spoiler: true,
    },
    
    // Another simple string
    "https://example.com/another-image.png",
  ],
}

๐Ÿ“Œ Meme/Artwork Gallery with Spoilers:

{
  type: "media",
  links: [
    {
      url: "https://example.com/meme1.png",
      description: "Funny meme #1",
      spoiler: false,
    },
    {
      url: "https://example.com/meme2.png",
      description: "Funny meme #2",
      spoiler: false,
    },
    {
      url: "https://example.com/nsfw-meme.png",
      description: "โš ๏ธ Slightly inappropriate",
      spoiler: true, // Hidden behind blur
    },
  ],
}

๐Ÿ’ก Tips for Media Galleries:

| Images Count | Display Layout | | ------------ | ---------------------- | | 1 image | Full width single image | | 2 images | Side by side | | 3 images | 1 large + 2 small | | 4+ images | Grid layout |

  • Use description for accessibility and context
  • Use spoiler: true for sensitive/spoiler content
  • Mix formats freely - strings for quick images, objects for detailed ones
  • Images are displayed in the order provided

๐Ÿ“Œ Simple File Attachment:

{
  type: "file",
  url: "attachment://document.pdf",
}

๐Ÿ“Œ Full Example with File:

const { CreateComponents } = require("djs-builder");
const { AttachmentBuilder } = require("discord.js");

const file = new AttachmentBuilder("./myfile.txt", { name: "myfile.txt" });

const components = await CreateComponents("container", [
  {
    type: "text",
    content: "๐Ÿ“„ **Here is your requested file:**",
  },
  {
    type: "file",
    url: "attachment://myfile.txt",
  },
]);

await channel.send({ components, files: [file], flags: 32768 });

๐Ÿ“Œ Button with Emoji:

{
  type: "button",
  components: [
    {
      id: "like_btn",
      style: 3, // Success (Green)
      label: "Like",
      emoji: "๐Ÿ‘",
    },
  ],
}

๐Ÿ“Œ Multiple Buttons in Row:

{
  type: "button",
  components: [
    { id: "btn_yes", style: 3, label: "Yes", emoji: "โœ…" },
    { id: "btn_no", style: 4, label: "No", emoji: "โŒ" },
    { id: "btn_maybe", style: 2, label: "Maybe", emoji: "๐Ÿค”" },
  ],
}

๐Ÿ“Œ All Button Styles:

{
  type: "button",
  components: [
    { id: "primary", style: 1, label: "Primary", emoji: "๐Ÿ”ต" },    // Blue
    { id: "secondary", style: 2, label: "Secondary", emoji: "โšช" }, // Gray
    { id: "success", style: 3, label: "Success", emoji: "๐ŸŸข" },    // Green
    { id: "danger", style: 4, label: "Danger", emoji: "๐Ÿ”ด" },      // Red
    { style: 5, label: "Link", emoji: "๐Ÿ”—", url: "https://discord.com" }, // Link
  ],
}

๐Ÿ“Œ String Select Menu (Basic):

{
  type: "menu",
  components: {
    type: "string",
    options: {
      id: "color_select",
      placeholder: "๐ŸŽจ Choose a color",
      data: [
        { name: "Red", id: "red", icon: "๐Ÿ”ด" },
        { name: "Blue", id: "blue", icon: "๐Ÿ”ต" },
        { name: "Green", id: "green", icon: "๐ŸŸข" },
      ],
      label: "name",
      value: "id",
      emoji: "icon",
    },
  },
}

๐Ÿ“Œ String Select with Description:

{
  type: "menu",
  components: {
    type: "string",
    options: {
      id: "role_select",
      placeholder: "๐ŸŽญ Select your role",
      data: [
        { name: "Gamer", id: "gamer", desc: "For gaming enthusiasts", icon: "๐ŸŽฎ" },
        { name: "Artist", id: "artist", desc: "For creative people", icon: "๐ŸŽจ" },
        { name: "Developer", id: "dev", desc: "For coders & programmers", icon: "๐Ÿ’ป" },
        { name: "Music Lover", id: "music", desc: "For music fans", icon: "๐ŸŽต" },
      ],
      label: "name",
      value: "id",
      description: "desc",
      emoji: "icon",
    },
  },
}

๐Ÿ“Œ String Select with Min/Max:

{
  type: "menu",
  components: {
    type: "string",
    options: {
      id: "games_select",
      placeholder: "๐ŸŽฎ Select your favorite games (2-4)",
      min: 2,
      max: 4,
      data: [
        { name: "Minecraft", id: "mc", icon: "โ›๏ธ" },
        { name: "Fortnite", id: "fn", icon: "๐Ÿ”ซ" },
        { name: "Valorant", id: "val", icon: "๐ŸŽฏ" },
        { name: "League of Legends", id: "lol", icon: "โš”๏ธ" },
        { name: "Rocket League", id: "rl", icon: "๐Ÿš—" },
      ],
      label: "name",
      value: "id",
      emoji: "icon",
    },
  },
}

๐Ÿ“Œ User Select (Multiple):

{
  type: "menu",
  components: {
    type: "user",
    options: {
      id: "users_select",
      placeholder: "๐Ÿ‘ฅ Select users to invite (1-5)",
      min: 1,
      max: 5,
    },
  },
}

๐Ÿ“Œ Role Select Menu:

{
  type: "menu",
  components: {
    type: "role",
    options: {
      id: "role_select",
      placeholder: "๐ŸŽญ Select a role",
      min: 1,
      max: 1,
    },
  },
}

๐Ÿ“Œ Channel Select Menu:

{
  type: "menu",
  components: {
    type: "channel",
    options: {
      id: "channel_select",
      placeholder: "๐Ÿ“ข Select a channel",
      min: 1,
      max: 1,
    },
  },
}

๐Ÿ“Œ Channel Select with Type Filter:

const { ChannelType } = require("discord.js");

{
  type: "menu",
  components: {
    type: "channel",
    options: {
      id: "text_channel_select",
      placeholder: "๐Ÿ’ฌ Select a text channel",
      channelTypes: [ChannelType.GuildText, ChannelType.GuildAnnouncement],
    },
  },
}

๐Ÿ“Œ Menu with Default Values (User/Role/Channel):

{
  type: "menu",
  components: {
    type: "user",
    options: {
      id: "user_select_default",
      placeholder: "๐Ÿ‘ค Select users",
      min: 1,
      max: 3,
      defaultValues: [
        { id: "123456789012345678", type: "user" },
        { id: "987654321098765432", type: "user" },
      ],
    },
  },
}

๐Ÿ“Œ Section with Thumbnail (Product):

{
  type: "section",
  content: "๐Ÿ›’ **iPhone 15 Pro**\n๐Ÿ’ฐ Price: $999\nโญ Rating: 4.8/5\n๐Ÿ“ฆ In Stock: Yes",
  accessory: {
    type: "thumbnail",
    url: "https://example.com/iphone.png",
    description: "iPhone 15 Pro Image",
  },
}

๐Ÿ“Œ Section with Button :

{
  type: "section",
  content: "๐ŸŽ **Daily Reward**\nClick to claim your daily reward!\n๐Ÿ’Ž **+100 Coins**",
  accessory: {
    type: "button",
    id: "claim_daily",
    style: 3, 
    label: "Claim",
    emoji: "๐ŸŽ",
  },
}

๐Ÿ“– Component Types Explanation

๐Ÿ”น Text

  • type โ†’ "text"
  • content โ†’ The text content to display (supports Markdown)

๐Ÿ”น Separator

  • type โ†’ "separator"
  • divider โ†’ Show a dividing line (true/false)
  • spacing โ†’ Spacing size (1: Small, 2: Large)

๐Ÿ”น Media Gallery

  • type โ†’ "media"
  • links โ†’ Array of image URLs or objects with:
    • url โ†’ Image URL
    • description โ†’ Alt text for the image
    • spoiler โ†’ Hide behind spoiler (true/false)

๐Ÿ”น File

  • type โ†’ "file"
  • url โ†’ File URL or attachment reference
  • spoiler โ†’ Hide behind spoiler (true/false)

๐Ÿ”น Button

  • type โ†’ "button"
  • components โ†’ Array of button objects:
    • id โ†’ customId (required for non-link buttons)
    • style โ†’ 1: Primary, 2: Secondary, 3: Success, 4: Danger, 5: Link
    • label โ†’ Button text
    • emoji โ†’ Button emoji
    • disabled โ†’ Disable button (true/false)
    • url โ†’ URL for link buttons (style: 5)

๐Ÿ”น Menu

  • type โ†’ "menu"
  • components โ†’ Object containing:
    • type โ†’ "string" | "user" | "role" | "channel"
    • options โ†’ Menu configuration:
      • id โ†’ customId
      • placeholder โ†’ Placeholder text
      • min / max โ†’ Min/Max selectable values
      • data โ†’ Options array (for string select)
      • label โ†’ Key in data for label
      • value โ†’ Key in data for value
      • emoji โ†’ Key in data for emoji
      • description โ†’ Key in data for description
      • channelTypes โ†’ Channel types filter (for channel menu)
      • defaultValues โ†’ Pre-selected values

๐Ÿ”น Section

  • type โ†’ "section"
  • content โ†’ Text content for the section
  • accessory โ†’ Side component:
    • Button Accessory:
      • type โ†’ "button"
      • id โ†’ customId
      • style โ†’ Button style
      • label โ†’ Button text
      • emoji โ†’ Button emoji
      • url โ†’ URL (for link buttons)
    • Thumbnail Accessory:
      • type โ†’ "thumbnail"
      • url โ†’ Image URL
      • description โ†’ Image description

๐Ÿ”น Mode Differences

| Feature | "array" Mode | "container" Mode | | ---------------- | ----------------------- | ------------------------- | | Return Type | Array of components | Single ContainerBuilder | | Usage | Standard messages | Components V2 messages | | Sections Support | โœ… | โœ… | | Grouping | Individual components | All grouped in container | | Flags Required | โŒ | โœ… (flags: 32768) |


๐Ÿ”น Notes

  • Use "container" mode for Discord's Components V2 (newer UI)
  • Use "array" mode for standard component arrays
  • Sections can have either a button or thumbnail as accessory, not both
  • Media galleries support multiple images in a single component
  • All components are fully customizable ๐ŸŽจ

โฐ Wait โ€“ Await messages, buttons, select menus or modals easily โœจ

Wait is a replacement for traditional collectors. It supports:

  • Awaiting messages ๐Ÿ“
  • Awaiting interactions (buttons / select menus) ๐ŸŽ›๏ธ
  • Awaiting modal submissions ๐Ÿ“‹
  • Filtering by user and timeout

๐Ÿ“Œ Example Usage:

const { Wait } = require("djs-builder");

const response = await Wait({
  context: message, // Message or Interaction object
  userId: message.author.id, // Optional: filter by user
  type: "both", // "message" | "interaction" | "both"
  time: 30000, // Time in ms
  message_Wait: message, // Required if waiting for buttons/selects
});

if (!response) return console.log("โฑ๏ธ Timeout!");
console.log("โœ… Collected:", response);

๐Ÿ”น Options

  • context โ†’ The message or interaction context
  • userId โ†’ Only collect from this user (optional)
  • type โ†’ "message" | "interaction" | "both"
  • time โ†’ Timeout in milliseconds
  • message_Wait โ†’ Message containing buttons/select menus (for interaction/both type)

๐Ÿ”น Notes

  • Supports automatic cleanup of collectors after completion
  • Can return Message, Interaction, or ModalSubmitInteraction

๐Ÿ‘ค GetUser โ€“ Fetch a GuildMember easily from a message โœจ

GetUser helps to detect a target member in multiple ways:

  1. Mention (@User)
  2. User ID (123456789012345678)
  3. Reply to another message

๐Ÿ“Œ Example Usage:

const { GetUser } = require("djs-builder");

const data = await GetUser(message);

if (!data) return message.reply("โŒ Could not find the user.");

const member = data.user; // GuildMember object
const args = data.args; // Remaining arguments
const reason = args.join(" ") || "No reason provided";

await member.ban({ reason });
message.reply(`๐Ÿšซ ${member.user.tag} was banned for: ${reason}`);

๐Ÿ”น Returns

{
  user: <GuildMember>,  // Targeted member
  args: [ "arg1", "arg2" ] // Remaining message arguments
}

๐Ÿ”น Detection Methods

  • Mention: !ban @Ahmed Spamming
  • User ID: !ban 123456789012345678 Spamming
  • Reply: Reply to user's message with !ban

๐Ÿ”น Notes

  • Automatically handles missing users
  • Returns null if user not found
  • Works in any text channel of the guild

๐Ÿ›ก๏ธ Logging System โ€“ Track Everything in Your Server

The Logging System is a powerful feature that keeps track of almost everything happening inside your Discord server ๐Ÿ”.
From messages ๐Ÿ“ to channels ๐Ÿ“‚, roles ๐ŸŽญ, invites ๐Ÿ”—, and even voice state changes ๐ŸŽ™๏ธ โ€“ nothing goes unnoticed!

Note 1: Using database: true requires a MongoDB connection. | Note 2: You can import the Log model for direct database access ๐Ÿ’พ.


๐Ÿ“ฆ Module Exports

const { log, Log } = require("djs-builder");
  • log(client, options) โ†’ Start the logging system with your configuration ๐Ÿš€.
  • Log โ†’ The Mongoose model for direct database access and custom modifications ๐Ÿ’พ.

๐Ÿ“‹ Simple Example

const { log } = require("djs-builder");

module.exports = {
  name: "clientReady",
  async run(client) {
    const logData = [
      {
        guildId: "999888777666555444",
        channelId: "444555666777888999",
      },

          {
        guildId: "999888777666555444",
        channelId: "444555666777888999",
      },
    ];

    // Start logging with custom data
    await log(client, {
      Data: logData, // ๐Ÿ“Š Your configurations
    });

    console.log("โœ… Logging system started with custom data!");
  },
};

โœจ Features

  • ๐Ÿ“ Messages โ€“ Deleted & edited messages are logged with details.
  • ๐Ÿ“‚ Channels โ€“ Creation, deletion, and updates are tracked.
  • ๐ŸŽญ Roles โ€“ Created, deleted, and updated roles, including member role changes.
  • ๐ŸŽ™๏ธ Voice State โ€“ Joins, leaves, and moves between channels.
  • ๐Ÿ”— Invites โ€“ Created invites & usage tracking.
  • ๐Ÿ˜€ Emojis & Stickers โ€“ Added, removed, or updated.
  • ๐Ÿ‘ค Members โ€“ Join, leave, kick, ban, and unban events.
  • ๐Ÿšจ Audit Log Integration โ€“ Fetches the executor (who did what).
  • ๐ŸŽจ Beautiful Embeds โ€“ Every log is shown in a clean, styled embed with timestamps.
  • ๐Ÿ—„๏ธ Caching System โ€“ Fast performance with built-in data caching.

๐Ÿ“Š Database Schema

The logging system uses the following data structure:

{
  guildId: String,      // ๐Ÿ  Server ID (required)
  channelId: String,    // ๐Ÿ“ข Default log channel ID
  channels: Object,     // ๐Ÿ“‚ Custom channels per event type (optional)
  colors: Object,       // ๐ŸŽจ Custom colors per event type (optional)
  disable: Array,       // ๐Ÿšซ Array of disabled event types (optional)
}

๐Ÿ“‹ Supported Event Types

| Event Type | Description | | ------------------- | ------------------------- | | messageDelete | Message deleted ๐Ÿ“ | | messageUpdate | Message edited โœ๏ธ | | channelCreate | Channel created ๐Ÿ“ | | channelDelete | Channel deleted ๐Ÿ—‘๏ธ | | channelUpdate | Channel updated โš™๏ธ | | guildMemberAdd | Member joined ๐ŸŽ‰ | | guildMemberRemove | Member left/kicked ๐Ÿšช | | guildBanAdd | Member banned ๐Ÿ”จ | | guildBanRemove | Member unbanned ๐Ÿค— | | roleCreate | Role created ๐Ÿ… | | roleDelete | Role deleted โŒ | | roleUpdate | Role updated ๐Ÿ”„ | | guildMemberUpdate | Member roles changed ๐Ÿ‘ค | | voiceStateUpdate | Voice channel activity ๐ŸŽค | | inviteCreate | Invite created ๐Ÿ”— | | emojiCreate | Emoji added ๐Ÿ˜€ | | emojiDelete | Emoji removed ๐Ÿšซ | | emojiUpdate | Emoji updated ๐Ÿ”„ | | stickerCreate | Sticker added โœจ | | stickerDelete | Sticker removed ๐Ÿ—‘๏ธ | | stickerUpdate | Sticker updated ๐ŸŒ€ |


๐Ÿ—„๏ธ Using MongoDB Database

This method stores log configuration in MongoDB, allowing dynamic management via commands.

โšก Setup in clientReady Event:

const { log } = require("djs-builder");

module.exports = {
  name: "clientReady",
  async run(client) {
    // Start logging with database mode
    await log(client, {
      database: true, // ๐Ÿ—„๏ธ Uses MongoDB to store/fetch config
    });

    console.log("โœ… Logging system started with database mode!");
  },
};

๐Ÿ’ก How It Works

  • โœ… The system automatically fetches log configuration for each guild from MongoDB.
  • ๐Ÿ› ๏ธ You can manage settings via slash commands (see management command below).
  • ๐ŸŽจ Supports per-guild customization for channels, colors, and disabled events.
  • ๐Ÿ“– Important: If you use database mode, see the Log Management Command below to edit data.

๐Ÿ“‹ Using Custom Data Array

This method uses a predefined array of configurations โ€“ perfect for simple setups or testing.

โšก Setup in clientReady Event:

const { log } = require("djs-builder");

module.exports = {
  name: "clientReady",
  async run(client) {
    // Define your log configurations
    const logData = [
      {
        guildId: "123456789012345678", // ๐Ÿ  Server ID
        channelId: "987654321098765432", // ๐Ÿ“ข Default log channel
        channels: {
          // ๐Ÿ“‚ Custom channels (optional)
          messageDelete: "111111111111111111",
          voiceStateUpdate: "222222222222222222",
        },
        colors: {
          // ๐ŸŽจ Custom colors (optional)
          messageDelete: "DarkRed",
          channelCreate: "DarkGreen",
        },
        disable: ["inviteCreate"], // ๐Ÿšซ Disabled events (optional)
      },
      // Add more guild configurations...
      {
        guildId: "999888777666555444",
        channelId: "444555666777888999",
      },
    ];

    // Start logging with custom data
    await log(client, {
      database: false, // ๐Ÿ“‹ Uses custom array
      Data: logData, // ๐Ÿ“Š Your configurations
    });

    console.log("โœ… Logging system started with custom data!");
  },
};

๐ŸŽจ Supported Colors

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.


๐ŸŒ Multi-Guild Support

๐Ÿ’ก 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!


๐Ÿ’พ Using the Log Model Directly

You can import the Log Mongoose model to create, update, or delete log configurations programmatically.

๐Ÿ“ฅ Import the Model:

const { Log } = require("djs-builder");

โž• Create New Configuration:

const { Log } = require("djs-builder");

// Create a new log configuration for a guild
const newConfig = await Log.create({
  guildId: "123456789012345678",
  channelId: "987654321098765432",
  channels: {
    messageDelete: "111111111111111111",
  },
  colors: {
    messageDelete: "Red",
  },
  disable: [],
});

console.log("โœ… Log configuration created!", newConfig);

โœ๏ธ Update Existing Configuration:

const { Log } = require("djs-builder");

// Update log channel
await Log.findOneAndUpdate(
  { guildId: "123456789012345678" },
  { channelId: "NEW_CHANNEL_ID" },
  { upsert: true } // Create if doesn't exist
);

// Add event to disable list
await Log.findOneAndUpdate(
  { guildId: "123456789012345678" },
  { $push: { disable: "voiceStateUpdate" } }
);

// Remove event from disable list
await Log.findOneAndUpdate(
  { guildId: "123456789012345678" },
  { $pull: { disable: "voiceStateUpdate" } }
);

// Update specific channel for an event
await Log.findOneAndUpdate(
  { guildId: "123456789012345678" },
  { $set: { "channels.messageDelete": "NEW_CHANNEL_ID" } }
);

// Update specific color for an event
await Log.findOneAndUpdate(
  { guildId: "123456789012345678" },
  { $set: { "colors.messageDelete": "DarkRed" } }
);

๐Ÿ—‘๏ธ Delete Configuration:

const { Log } = require("djs-builder");

await Log.findOneAndDelete({ guildId: "123456789012345678" });
console.log("๐Ÿ—‘๏ธ Log configuration deleted!");

๐Ÿ“Š Fetch Configuration:

const { Log } = require("djs-builder");

const config = await Log.findOne({ guildId: "123456789012345678" });
if (config) {
  console.log("๐Ÿ“ข Log Channel:", config.channelId);
  console.log("๐Ÿ“‚ Custom Channels:", config.channels);
  console.log("๐ŸŽจ Custom Colors:", config.colors);
  console.log("๐Ÿšซ Disabled Events:", config.disable);
}

๐Ÿ–ฅ๏ธ Web Dashboard for Log Management

When you use database mode (database: true), you can manage the logging system directly from the djs-builder Dashboard! ๐ŸŽ›๏ธ


โœจ Dashboard Features for Logs

| Feature | Description | | ---------------------- | -------------------------------------------- | | ๐Ÿ“ข Default Channel | Set the main channel for all logs | | ๐Ÿ“‚ Custom Channels | Assign specific channels for each event type | | ๐ŸŽจ Custom Colors | Choose embed colors for each event type | | ๐Ÿ”„ Toggle Events | Enable/Disable specific event types | | ๐Ÿ“Š Statistics | View enabled/disabled events count | | ๐Ÿ—‘๏ธ Reset | Clear all log settings with one click |


๐Ÿš€ How to Access

  1. Navigate to your dashboard (e.g., http://localhost:3000)
  2. Log in with Discord OAuth2
  3. Select a server
  4. Click on "ุณุฌู„ุงุช ุงู„ู…ุฑุงู‚ุจุฉ" (Logs) in the sidebar

โš ๏ธ Important Notes

When database: true:

  • โœ… Full editing capabilities from dashboard
  • โœ… Changes are saved automatically to MongoDB
  • โœ… Real-time updates

When database: false (Custom Data Array):

  • โš ๏ธ Dashboard shows read-only mode
  • โš ๏ธ A warning banner appears at the top
  • โš ๏ธ You must edit settings in your code

๐Ÿ› ๏ธ Complete Log Management Slash Command

This command allows server administrators to manage the logging system via Discord.

โš ๏ธ Important: This command requires database: true mode to work properly.

const { Log, getLogConfigData } = require("djs-builder");
const {
  SlashCommandBuilder,
  PermissionFlagsBits,
  EmbedBuilder,
  ChannelType,
} = require("discord.js");

// All supported event types (21 events)
const EVENT_TYPES = [
  { name: "Message Delete", value: "messageDelete" },
  { name: "Message Update", value: "messageUpdate" },
  { name: "Channel Create", value: "channelCreate" },
  { name: "Channel Delete", value: "channelDelete" },
  { name: "Channel Update", value: "channelUpdate" },
  { name: "Member Join", value: "guildMemberAdd" },
  { name: "Member Leave", value: "guildMemberRemove" },
  { name: "Member Ban", value: "guildBanAdd" },
  { name: "Member Unban", value: "guildBanRemove" },
  { name: "Role Create", value: "roleCreate" },
  { name: "Role Delete", value: "roleDelete" },
  { name: "Role Update", value: "roleUpdate" },
  { name: "Member Role Update", value: "guildMemberUpdate" },
  { name: "Voice State", value: "voiceStateUpdate" },
  { name: "Invite Create", value: "inviteCreate" },
  { name: "Emoji Create", value: "emojiCreate" },
  { name: "Emoji Delete", value: "emojiDelete" },
  { name: "Emoji Update", value: "emojiUpdate" },
  { name: "Sticker Create", value: "stickerCreate" },
  { name: "Sticker Delete", value: "stickerDelete" },
  { name: "Sticker Update", value: "stickerUpdate" },
];

// Helper function to clear cache after updates
function clearLogCache(guildId) {
  const logData = getLogConfigData();
  if (logData.clearCache) logData.clearCache(guildId);
}

module.exports = {
  data: new SlashCommandBuilder()
    .setName("logs")
    .setDescription("๐Ÿ›ก๏ธ Manage the server logging system")
    .setDefaultMemberPermissions(PermissionFlagsBits.Administrator)
    .addSubcommand((sub) =>
      sub
        .setName("setup")
        .setDescription("๐Ÿ“ข Set up the default log channel")
        .addChannelOption((opt) =>
          opt
            .setName("channel")
            .setDescription("The channel to send logs to")
            .addChannelTypes(ChannelType.GuildText)
            .setRequired(true)
        )
    )
    .addSubcommand((sub) =>
      sub
        .setName("channel")
        .setDescription("๐Ÿ“‚ Set a specific channel for an event type")
        .addStringOption((opt) =>
          opt
            .setName("event")
            .setDescription("The event type")
            .setRequired(true)
            .addChoices(...EVENT_TYPES)
        )
        .addChannelOption((opt) =>
          opt
            .setName("channel")
            .setDescription("The channel for this event")
            .addChannelTypes(ChannelType.GuildText)
            .setRequired(true)
        )
    )
    .addSubcommand((sub) =>
      sub
        .setName("color")
        .setDescription("๐ŸŽจ Set a custom color for an event type")
        .addStringOption((opt) =>
          opt
            .setName("event")
            .setDescription("The event type")
            .setRequired(true)
            .addChoices(...EVENT_TYPES)
        )
        .addStringOption((opt) =>
          opt
            .setName("color")
            .setDescription("Color name or hex code (e.g., Red, #FF5733)")
            .setRequired(true)
        )
    )
    .addSubcommand((sub) =>
      sub
        .setName("toggle")
        .setDescription("๐Ÿ”„ Enable or disable an event type")
        .addStringOption((opt) =>
          opt
            .setName("event")
            .setDescription("The event type")
            .setRequired(true)
            .addChoices(...EVENT_TYPES)
        )
        .addStringOption((opt) =>
          opt
            .setName("action")
            .setDescription("Enable or disable")
            .setRequired(true)
            .addChoices(
              { name: "Enable", value: "enable" },
              { name: "Disable", value: "disable" }
            )
        )
    )
    .addSubcommand((sub) =>
      sub.setName("view").setDescription("๐Ÿ“Š View current log configuration")
    )
    .addSubcommand((sub) =>
      sub
        .setName("reset")
        .setDescription("๐Ÿ—‘๏ธ Reset all log settings for this server")
    ),

  async run(client, interaction) {
    await interaction.deferReply({ ephemeral: true });

    const subcommand = interaction.options.getSubcommand();
    const guildId = interaction.guild.id;

    // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    // ๐Ÿ“ข SETUP - Set default log channel
    // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    if (subcommand === "setup") {
      const channel = interaction.options.getChannel("channel");

      await Log.findOneAndUpdate(
        { guildId },
        { guildId, channelId: channel.id },
        { upsert: true, new: true }
      );

      clearLogCache(guildId); // Clear cache to apply changes immediately

      const embed = new EmbedBuilder()
        .setTitle("โœ… Logging System Setup")
        .setDescription(`Logs will now be sent to ${channel}`)
        .setColor("Green")
        .setTimestamp();

      return interaction.editReply({ embeds: [embed] });
    }

    // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    // ๐Ÿ“‚ CHANNEL - Set specific channel for event
    // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    if (subcommand === "channel") {
      const event = interaction.options.getString("event");
      const channel = interaction.options.getChannel("channel");

      await Log.findOneAndUpdate(
        { guildId },
        { $set: { [`channels.${event}`]: channel.id } },
        { upsert: true }
      );

      clearLogCache(guildId);

      const eventName =
        EVENT_TYPES.find((e) => e.value === event)?.name || event;
      const embed = new EmbedBuilder()
        .setTitle("๐Ÿ“‚ Event Channel Updated")
        .setDescription(`**${eventName}** logs will now be sent to ${channel}`)
        .setColor("Blue")
        .setTimestamp();

      return interaction.editReply({ embeds: [embed] });
    }

    // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    // ๐ŸŽจ COLOR - Set custom color for event
    // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    if (subcommand === "color") {
      const event = interaction.options.getString("event");
      const color = interaction.options.getString("color");

      await Log.findOneAndUpdate(
        { guildId },
        { $set: { [`colors.${event}`]: color } },
        { upsert: true }
      );

      clearLogCache(guildId);

      const eventName =
        EVENT_TYPES.find((e) => e.value === event)?.name || event;
      
      // Try to use the color, fallback to Blue if invalid
      let embedColor;
      try {
        embedColor = color;
      } catch {
        embedColor = "Blue";
      }

      const embed = new EmbedBuilder()
        .setTitle("๐ŸŽจ Event Color Updated")
        .setDescription(
          `**${eventName}** embeds will now use color: \`${color}\``
        )
        .setColor(embedColor)
        .setTimestamp();

      return interaction.editReply({ embeds: [embed] });
    }

    // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    // ๐Ÿ”„ TOGGLE - Enable/Disable event
    // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    if (subcommand === "toggle") {
      const event = interaction.options.getString("event");
      const action = interaction.options.getString("action");

      if (action === "disable") {
        await Log.findOneAndUpdate(
          { guildId },
          { $addToSet: { disable: event } },
          { upsert: true }
        );
      } else {
        await Log.findOneAndUpdate(
          { guildId },
          { $pull: { disable: event } },
          { upsert: true }
        );
      }

      clearLogCache(guildId);

      const eventName =
        EVENT_TYPES.find((e) => e.value === event)?.name || event;
      const embed = new EmbedBuilder()
        .setTitle(
          action === "disable" ? "๐Ÿšซ Event Disabled" : "โœ… Event Enabled"
        )
        .setDescription(`**${eventName}** logging has been ${action}d`)
        .setColor(action === "disable" ? "Red" : "Green")
        .setTimestamp();

      return interaction.editReply({ embeds: [embed] });
    }

    // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    // ๐Ÿ“Š VIEW - Show current configuration
    // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    if (subcommand === "view") {
      const config = await Log.findOne({ guildId });

      if (!config) {
        return interaction.editReply({
          content:
            "โŒ No logging configuration found for this server. Use `/logs setup` first!",
        });
      }

      const channelsList = config.channels
        ? Object.entries(config.channels)
            .map(([k, v]) => {
              const eventName = EVENT_TYPES.find((e) => e.value === k)?.name || k;
              return `โ€ข **${eventName}**: <#${v}>`;
            })
            .join("\n") || "None"
        : "None";

      const colorsList = config.colors
        ? Object.entries(config.colors)
            .map(([k, v]) => {
              const eventName = EVENT_TYPES.find((e) => e.value === k)?.name || k;
              return `โ€ข **${eventName}**: \`${v}\``;
            })
            .join("\n") || "None"
        : "None";

      const disabledList =
        config.disable?.length > 0
          ? config.disable.map((e) => {
              const eventName = EVENT_TYPES.find((ev) => ev.value === e)?.name || e;
              return `โ€ข ${eventName}`;
            }).join("\n")
          : "None";

      const enabledCount = EVENT_TYPES.length - (config.disable?.length || 0);

      const embed = new EmbedBuilder()
        .setTitle("๐Ÿ“Š Log Configuration")
        .setDescription(`**${enabledCount}/${EVENT_TYPES.length}** events are enabled`)
        .setColor("Blue")
        .addFields(
          {
            name: "๐Ÿ“ข Default Channel",
            value: config.channelId ? `<#${config.channelId}>` : "Not set",
            inline: true,
          },
          {
            name: "๐Ÿ“‚ Custom Channels",
            value: channelsList.slice(0, 1024) || "None",
            inline: false,
          },
          {
            name: "๐ŸŽจ Custom Colors",
            value: colorsList.slice(0, 1024) || "None",
            inline: false,
          },
          {
            name: "๐Ÿšซ Disabled Events",
            value: disabledList.slice(0, 1024) || "None",
            inline: false,
          }
        )
        .setFooter({ text: `Guild ID: ${guildId}` })
        .setTimestamp();

      return interaction.editReply({ embeds: [embed] });
    }

    // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    // ๐Ÿ—‘๏ธ RESET - Delete all configuration
    // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    if (subcommand === "reset") {
      await Log.findOneAndDelete({ guildId });
      
      clearLogCache(guildId);

      const embed = new EmbedBuilder()
        .setTitle("๐Ÿ—‘๏ธ Configuration Reset")
        .setDescription(
          "All logging settings have been deleted for this server."
        )
        .setColor("Red")
        .setTimestamp();

      return interaction.editReply({ embeds: [embed] });
    }
  },
};

๐Ÿ’ก Tips & Notes

  • ๐Ÿ”„ Caching: The system caches guild configurations for better performance.
  • ๐Ÿ” Permissions: Make sure your bot has View Audit Log permission for full functionality.
  • ๐Ÿ“ข Invite Tracking: Uses discord-inviter package for accurate invite tracking.
  • ๐ŸŽจ Default Colors: Each event type has sensible default colors if not customized.
  • ๐Ÿšซ Disabled Events: Events in the disable array will be completely ignored.
  • ๐Ÿ“‚ Channel Fallback: If no specific channel is set for an event, it uses channelId.
  • ๐Ÿ’พ Database Mode: Recommended for multi-server bots with dynamic configuration needs.
  • ๐ŸŒ Dashboard Integration: When using database mode, you can manage logs via the web dashboard!



๐Ÿ† Level System โ€“ XP, Levels & Leaderboard

The Level System module lets you track user experience points (XP) in text ๐Ÿ’ฌ and voice ๐ŸŽ™๏ธ, handle level-ups โฌ†๏ธ, and display leaderboards ๐Ÿ…. Perfect for gamifying your Discord server! ๐ŸŽฎโœจ

Note: To use this module, you MUST have DATABASE conection. | Note 2: You can get all data by requiring the Level module.


๐Ÿ“ฆ Module Exports

const { addXP, UserLevel, leaderboard } = require("djs-builder");
  • addXP(userId, guildId, options) โ†’ Adds XP for a user and handles level-ups ๐ŸŽฒ.
  • UserLevel(userId, guildId) โ†’ Fetch a user's XP and level ๐Ÿ‘ค.
  • leaderboard(guildId, type, limit) โ†’ Get top users ๐Ÿ….

๐ŸŽฒ addXP โ€“ Add Experience Points

Adds XP to a user and automatically handles level-ups.

const result = await addXP("USER_ID", "GUILD_ID", {
  type: "text", // "text" ๐Ÿ’ฌ | "voice" ๐ŸŽ™๏ธ
  minXP: 5, // Minimum random XP ๐ŸŸข
  maxXP: 15, // Maximum random XP ๐Ÿ”ต
  amount_add: 10, // Optional: fixed XP ๐Ÿ’Ž
  level_add: 1, // Optional: direct level boost โฌ†๏ธ
});

console.log(result);
/* Example output:
{
  newLevel: 3,
  oldLevel: 2,
  totalXP: 250,
  leveledUp: true
}
*/

๐Ÿง‘โ€๐Ÿคโ€๐Ÿง‘ UserLevel โ€“ Fetch User Data

Fetch a user's text XP, voice XP, total XP, and current level.

const data = await UserLevel("USER_ID", "GUILD_ID");
console.log(data);
/* Example output:
{
  text: 120 ๐Ÿ’ฌ,
  voice: 50 ๐ŸŽ™๏ธ,
  totalXP: 170 โญ,
  level: 2 โฌ†๏ธ
}
*/

Returns default values if the user is not found.


๐Ÿ… Leaderboard โ€“ Top Users

Get a sorted list of users based on XP or level.

const topUsers = await leaderboard("GUILD_ID", "totalXP", 5);
console.log(topUsers);
/* Example output:
[
  { userId: "123", totalXP: 500, level: 5 },
  { userId: "456", totalXP: 400, level: 4 },
  ...
]
*/

Parameters:

  • guildId โ†’ Server ID ๐Ÿ 
  • type โ†’ "totalXP", "text" ๐Ÿ’ฌ, "voice" ๐ŸŽ™๏ธ, or "level" โฌ†๏ธ. Default = "totalXP"
  • limit โ†’ Number of top users to return ๐Ÿ”ข. Default = 10

โšก Practical Example: messageCreate Event

const { addXP, UserLevel, leaderboard } = require("djs-builder");

module.exports = {
  name: "messageCreate",
  run: async (msg, client) => {
    if (msg.author.bot) return;

    // ๐ŸŽฒ Add XP on every message
    const result = await addXP(msg.author.id, msg.guild.id, {
      type: "text",
      minXP: 5,
      maxXP: 15,
    });

    // ๐ŸŽ‰ Level-up notification
    if (result.leveledUp) {
      msg.channel.send(`๐ŸŽŠ ${msg.author} new level **${result.newLevel}** โฌ†๏ธ`);
    }

    // ๐Ÿ“Š Check your rank
    if (msg.content === "!rank") {
      const data = await UserLevel(msg.author.id, msg.guild.id);
      msg.reply(`๐Ÿ“ˆ **level ** ${data.level} โฌ†๏ธ โ€“ **XP:** ${data.totalXP} โญ`);
    }

    // ๐Ÿ… Display top users
    if (msg.content === "!top") {
      const lb = await leaderboard(msg.guild.id, "totalXP", 5);
      msg.reply(
        lb
          .map(
            (u, i) =>
              `#${i + 1} <@${u.userId}> โ€“ Lv.${u.level} โฌ†๏ธ (${u.totalXP} โญ)`
          )
          .join("\n")
      );
    }
  },
};

๐Ÿ’ก Notes & Tips

  • ๐Ÿ’ฌ Text XP โ€“ Add XP for messages automatically.
  • ๐ŸŽ™๏ธ Voice XP โ€“ Add XP for voice activity.
  • โฌ†๏ธ Level Up โ€“ Trigger notifications when leveling up.
  • ๐Ÿ… Leaderboard โ€“ Display the top users in server using embeds for better look.
  • ๐ŸŽฎ Gamify your server easily with XP rewards, mini-games, and custom commands.


๐ŸŽ‰ Giveaway System โ€“ All-in-One Contest Management ๐Ÿ†โœจ

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. ๐Ÿšจ

Note: To use this module, you MUST have DATABASE conection. | Note 2: You can get all data by requiring the giveaway module.


๐Ÿ“ฆ Module Exports

const {
  Gstart,
  Gcheck,
  Greroll,
  Glist,
  Gpause,
  Gresume,
  Gdelete,
  GaddUser,
  GremoveUser,
  GaddTime,
  GremoveTime,
  Gdata,
} = require("djs-builder");

๐ŸŽฌ Gstart โ€“ Launch a Brand New Giveaway! ๐Ÿš€

This is the primary function to kick off a new giveaway. It handles creating the Discord message and persists all necessary data in the database (MongoDB). This function offers deep customization for embeds and entry methods. ๐ŸŽจ

โš™๏ธ Essential Options:

  • context: The Message or Interaction object that triggered the command.
  • endTime: The duration until the giveaway ends (in milliseconds โฑ๏ธ).
  • winers: The number of winners for the contest. ๐Ÿ…
  • channelId: The ID of the channel where the giveaway message will be posted. ๐Ÿ“ข
  • embed / endEmbed: Options to fully customize the starting message and the final end message.
  • reaction: To specify the entry method (button or reaction). ๐Ÿ–ฑ๏ธ

โšก Simple Usage Example (Basic Requirements Only):

This example provides a fast and minimalist way to start a giveaway with default embed colors, a simple title, and the default reaction entry type (if the reaction object is omitted or set to reaction).

const { Gstart } = require("djs-builder");

module.exports = {
  name: "gstart",
  description: "Starts a new simple giveaway.",
  run: async (client, message, args) => {
    // โฐ Giveaway ends in 1 hour
    const oneHour = 60 * 60 * 1000;
    const channelId = message.channel.id;

    await Gstart({
      context: message,
      endTime: oneHour,
      winers: 1,
      channelId: channelId,

      embed: {
        title: "๐ŸŽ‰ Simple Test Giveaway",
        description: "React to enter! Prize: Discord Nitro.",
      },
    });
    message.reply("๐ŸŽ‰ Simple Giveaway starte