Advanced Features

Disapp framework includes powerful advanced features that dramatically reduce boilerplate code and improve developer experience.

Smart Component Handling

Automatically manage button clicks and select menu interactions without manual collector setup.

With onClick Handlers

import { v2 } from "@disapp/core";
import { ButtonStyle } from "discord.js";

const message = v2()
  .text("# Menu")
  .buttons(
    {
      id: "button1",
      label: "Option 1",
      style: ButtonStyle.Primary,
      onClick: async (i) => {
        await i.reply("You clicked Option 1!");
      },
    },
    {
      id: "button2",
      label: "Option 2",
      style: ButtonStyle.Success,
      onClick: async (i) => {
        await i.reply("You clicked Option 2!");
      },
    },
  )
  .build();

await interaction.reply(message);

Select Menus with onChange

const message = v2()
  .text("# Choose an option")
  .select(
    "my_select",
    "Select something",
    [
      { label: "Option A", value: "a" },
      { label: "Option B", value: "b" },
    ],
    async (i) => {
      const selected = i.values[0];
      await i.reply(`You selected: ${selected}`);
    },
  )
  .build();

Benefits

  • 90% less code - No manual collector setup
  • Memory safe - Auto cleanup after timeout
  • Type safe - Full TypeScript support
  • Centralized - All handlers in one place

Auto-Chunking

Automatically split long messages that exceed Discord's 2000 character limit.

const message = v2()
  .enableAutoChunking({
    maxLength: 2000,
    preserveCodeBlocks: true,
  })
  .text(veryLongText)
  .build();

Command Middleware

Add reusable logic to commands with middleware functions.

Built-in Middleware

import { Command, OnlyAdmin, Cooldown } from "@disapp/core";

export default class BanCommand extends Command {
  constructor() {
    super({
      name: "ban",
      description: "Ban a user",
      data: new SlashCommandBuilder()
        .setName("ban")
        .setDescription("Ban a user"),
      middlewares: [OnlyAdmin(), Cooldown(5000)],
      execute: async () => {},
    });
  }

  async execute(interaction: any) {
    await interaction.reply("User banned!");
  }
}

Available Middleware

MiddlewareDescriptionUsage
OnlyAdmin()Requires Administrator permissionmiddlewares: [OnlyAdmin()]
RequirePermission(perm)Requires specific permissionmiddlewares: [RequirePermission(PermissionFlagsBits.ManageMessages)]
Cooldown(ms)Adds cooldown per usermiddlewares: [Cooldown(5000)]
RateLimit(max, window)Limits uses per time windowmiddlewares: [RateLimit(3, 60000)]
RequireDatabase()Requires database connectionmiddlewares: [RequireDatabase()]
RequireGuild()Requires command in servermiddlewares: [RequireGuild()]
RequireRole(roleId)Requires specific rolemiddlewares: [RequireRole('123456789')]
OwnerOnly(ownerId)Only bot owner can usemiddlewares: [OwnerOnly('123456789')]

Custom Middleware

import { MiddlewareFunction } from "@disapp/core";

function RequireLevel(minLevel: number): MiddlewareFunction {
  return async (ctx) => {
    const userLevel = await getUserLevel(ctx.interaction.user.id);

    if (userLevel < minLevel) {
      await ctx.interaction.reply({
        content: `❌ You need level ${minLevel} to use this command!`,
        flags: 64,
      });
      return false;
    }

    return true;
  };
}

export default class AdvancedCommand extends Command {
  constructor() {
    super({
      name: "advanced",
      description: "Advanced command",
      data: new SlashCommandBuilder()
        .setName("advanced")
        .setDescription("Advanced command"),
      middlewares: [RequireLevel(10)],
      execute: async () => {},
    });
  }
}

Dynamic Configuration

Hot-reload bot configuration without restarting.

import { DynamicConfig } from "@disapp/core";

const config = DynamicConfig.getInstance("./config.json");

config.on("changed", (newConfig, oldConfig) => {
  console.log("Config updated!", newConfig);
});

if (config.isMaintenanceMode()) {
  await interaction.reply("🔧 Bot is in maintenance mode!");
  return;
}

const color = config.get("color");

Internationalization (i18n)

Multi-language support with JSON-based translations.

import { I18nHelper } from "@disapp/core";

const lang = interaction.locale?.split("-")[0] || "en";
const message = I18nHelper.command("ping.response", lang, { latency: 50 });

await interaction.reply(message);

With Components V2

const lang = interaction.locale?.split("-")[0] || "en";
const t = (key: string, params?: Record<string, any>) =>
  I18nHelper.command(key, lang, params);

const message = v2()
  .text(t("menu.title"))
  .buttons({
    id: "confirm",
    label: I18nHelper.button("confirm", lang),
    onClick: async (i) => {
      await i.reply(t("menu.confirmed"));
    },
  })
  .build();

Complete Example

Combining all features:

import {
  Command,
  v2,
  OnlyAdmin,
  Cooldown,
  DynamicConfig,
  I18nHelper,
} from "@disapp/core";
import { SlashCommandBuilder, ButtonStyle } from "discord.js";

export default class AdvancedCommand extends Command {
  constructor() {
    super({
      name: "advanced",
      description: "Advanced command with all features",
      data: new SlashCommandBuilder()
        .setName("advanced")
        .setDescription("Advanced command with all features"),
      middlewares: [OnlyAdmin(), Cooldown(5000)],
      execute: async () => {},
    });
  }

  async execute(interaction: any) {
    const config = DynamicConfig.getInstance();
    const color = config.get("color") || 0x5865f2;
    const lang = interaction.locale?.split("-")[0] || "en";

    const message = v2()
      .enableAutoChunking()
      .accentColor(color)
      .text(`# ${I18nHelper.t("advanced.title", lang)}`)
      .separator()
      .buttons(
        {
          id: "refresh",
          label: I18nHelper.button("refresh", lang),
          style: ButtonStyle.Primary,
          emoji: "🔄",
          onClick: async (i) => {
            await i.update({
              content: "Refreshed at " + new Date().toLocaleTimeString(),
            });
          },
        },
        {
          id: "config",
          label: I18nHelper.button("config", lang),
          style: ButtonStyle.Secondary,
          emoji: "⚙️",
          onClick: async (i) => {
            const cfg = config.getAll();
            await i.reply({
              content: `\`\`\`json\n${JSON.stringify(cfg, null, 2)}\n\`\`\``,
              flags: 64,
            });
          },
        },
      )
      .build();

    await interaction.reply(message);
  }
}

Performance

All features are optimized for performance:

  • Smart Handlers: O(1) lookup, automatic cleanup
  • Auto-Chunking: Lazy evaluation, minimal overhead
  • Middleware: Short-circuit on failure, cached results
  • Dynamic Config: File watching with debounce, event-driven

Best Practices

  1. Use middleware for common checks - Don't repeat yourself
  2. Enable auto-chunking for user-generated content - Prevent errors
  3. Use smart handlers for complex interactions - Cleaner code
  4. Watch config in production - Live updates without downtime