GUIDEMessage builders

Message builders

Build rich Discord messages with a fluent API. Embed builders, action rows, and component layouts with full type inference and validation.

Embed builder

Construct embed objects with a chainable builder that enforces Discord's embed limits at the type level.

typescript
import { EmbedBuilder } from "@theminesastudios/mini-interaction";

const embed = new EmbedBuilder()
  .setTitle("Server Info")
  .setDescription("Current server statistics")
  .setColor(0x6b4226)
  .setTimestamp(new Date())
  .addFields([
    { name: "Members", value: "1,234", inline: true },
    { name: "Online", value: "567", inline: true },
    { name: "Channels", value: "42", inline: true },
  ])
  .setFooter({ text: "Updated", iconUrl: "https://..." })
  .toJSON();

Embed validation

The builder validates against Discord's embed constraints:

  • Title: max 256 characters
  • Description: max 4096 characters
  • Fields: max 25 fields, name max 256, value max 1024
  • Footer text: max 2048 characters
  • Author name: max 256 characters
  • Total embed: max 6000 characters

Action rows & components

Compose buttons, select menus, and text inputs into action rows with automatic row distribution.

typescript
import { ActionRowBuilder, ButtonBuilder, SelectMenuBuilder } from "@theminesastudios/mini-interaction";
import { ButtonStyle, ComponentType } from "discord-api-types/v10";

const buttons = new ActionRowBuilder()
  .addComponents(
    new ButtonBuilder()
      .setCustomId("ticket:create:support")
      .setLabel("Support")
      .setStyle(ButtonStyle.Primary)
      .setEmoji({ name: "🎫" }),
    new ButtonBuilder()
      .setCustomId("ticket:close:modal")
      .setLabel("Close")
      .setStyle(ButtonStyle.Danger),
  );

const select = new ActionRowBuilder()
  .addComponents(
    new SelectMenuBuilder()
      .setCustomId("role_picker")
      .setPlaceholder("Choose a role...")
      .addOptions([
        { label: "Developer", value: "dev", description: "Get the developer role" },
        { label: "Designer", value: "design", description: "Get the designer role" },
        { label: "Moderator", value: "mod", description: "Get the mod role" },
      ]),
  );

// Use in a response
ctx.respond({
  embeds: [embed],
  components: [buttons, select],
});

Message flags

Control message visibility and behavior with Discord's message flags.

typescript
import { MessageFlags } from "discord-api-types/v10";

// Ephemeral message (only the user sees it)
ctx.respond({
  content: "This is private!",
  flags: MessageFlags.Ephemeral,
});

// Suppress embeds
ctx.respond({
  content: "https://example.com",
  flags: MessageFlags.SuppressEmbeds,
});

Response types

The framework supports all Discord interaction response types:

Type
Usage
Pong
ACK for ping interactions
ChannelMessageWithSource
Send a message (normal or ephemeral)
DeferredChannelMessageWithSource
Defer, then follow up with editReply
DeferredUpdateMessage
Defer for component updates
UpdateMessage
Immediately update the component message
Modal
Open a modal for the user

Builder API reference

Every builder method returns this for method chaining. Call .toJSON() to produce the raw payload for Discord's API.

typescript
// EmbedBuilder
.setTitle(text: string): EmbedBuilder
.setDescription(text: string): EmbedBuilder
.setColor(hex: number): EmbedBuilder
.setTimestamp(date?: Date): EmbedBuilder
.setFooter(footer): EmbedBuilder
.setImage(url: string): EmbedBuilder
.setThumbnail(url: string): EmbedBuilder
.setAuthor(author): EmbedBuilder
.addFields(fields: Field[]): EmbedBuilder
.toJSON(): APIEmbed

// ButtonBuilder
.setCustomId(id: string): ButtonBuilder
.setLabel(text: string): ButtonBuilder
.setStyle(style: ButtonStyle): ButtonBuilder
.setEmoji(emoji): ButtonBuilder
.setDisabled(disabled: boolean): ButtonBuilder
.toJSON(): APIButtonComponent

// SelectMenuBuilder
.setCustomId(id: string): SelectMenuBuilder
.setPlaceholder(text: string): SelectMenuBuilder
.addOptions(opts: SelectOption[]): SelectMenuBuilder
.setMinValues(n: number): SelectMenuBuilder
.setMaxValues(n: number): SelectMenuBuilder
.setDisabled(disabled: boolean): SelectMenuBuilder
.toJSON(): APISelectMenuComponent

// ActionRowBuilder
.addComponents(...components): ActionRowBuilder
.toJSON(): APIActionRowComponent