Build rich Discord messages with a fluent API. Embed builders, action rows, and component layouts with full type inference and validation.
Construct embed objects with a chainable builder that enforces Discord's embed limits at the type level.
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();The builder validates against Discord's embed constraints:
Compose buttons, select menus, and text inputs into action rows with automatic row distribution.
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],
});Control message visibility and behavior with Discord's message flags.
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,
});The framework supports all Discord interaction response types:
PongChannelMessageWithSourceDeferredChannelMessageWithSourceDeferredUpdateMessageUpdateMessageModalEvery builder method returns this for method chaining. Call .toJSON() to produce the raw payload for Discord's API.
// 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