A modern, type-safe Discord client library built with TypeScript and designed for Bun/Node.js runtime.
bun add @hedystia/discord
# or
npm install @hedystia/discord
# or
yarn add @hedystia/discordimport Client, { Intents } from "@hedystia/discord";
const client = new Client({
token: process.env.DISCORD_TOKEN!,
intents: Intents.allNonPrivileged,
});
client.on("ready", () => {
console.log(`Logged in as ${client.me?.username}!`);
});
await client.login();- Client Configuration
- Events
- Slash Commands
- Voice Module
- Builders
- Collectors
- Managers
- Structures
- REST API
- Utilities
import Client, { Intents, ActivityType } from "@hedystia/discord";
const client = new Client({
token: "YOUR_BOT_TOKEN",
// Gateway intents (required for events)
intents: Intents.guilds | Intents.guildMessages | Intents.messageContent,
// Bot presence
presence: {
activities: [
{ name: "your game", type: ActivityType.Playing },
{ name: "music", type: ActivityType.Listening },
],
status: "online", // online, idle, dnd, invisible
},
// Sharding
shardsCount: "auto", // or a specific number like 4
// Cache configuration
cache: {
guilds: { maxSize: 1000, ttl: 3600000 },
users: { maxSize: 10000, ttl: 1800000, dynamicTTL: true },
channels: { maxSize: 5000 },
members: { maxSize: 50000 },
},
});
await client.login();import { Intents } from "@hedystia/discord";
// Individual intents
Intents.guilds;
Intents.guildMembers;
Intents.guildBans;
Intents.guildEmojisAndStickers;
Intents.guildIntegrations;
Intents.guildWebhooks;
Intents.guildInvites;
Intents.guildVoiceStates;
Intents.guildPresences;
Intents.guildMessages;
Intents.guildMessageReactions;
Intents.guildMessageTyping;
Intents.directMessages;
Intents.directMessageReactions;
Intents.directMessageTyping;
Intents.messageContent;
Intents.guildScheduledEvents;
Intents.autoModerationConfiguration;
Intents.autoModerationExecution;
Intents.guildMessagePolls;
Intents.directMessagePolls;
// Presets
Intents.allNonPrivileged; // All except privileged intents
Intents.allPrivileged; // guildMembers, guildPresences, messageContent
Intents.all; // Every intent// Managers
client.users; // UserManager
client.channels; // ChannelManager
client.guilds; // GuildManager
client.members; // MemberManager
client.roles; // RoleManager
client.emojis; // EmojiManager
client.stickers; // StickerManager
client.bans; // GuildBanManager
client.invites; // InviteManager
client.webhooks; // WebhookManager
client.voice; // VoiceManager
// REST API
client.rest; // REST client
// Bot info
client.me; // Current bot user (APIUser)
client.readyAt; // Date when client became ready
client.uptime; // Uptime in milliseconds
client.ping; // WebSocket ping
client.isReady; // Whether client is ready
client.ws; // WebSocket optionsThe client extends Node.js EventEmitter with full TypeScript support.
// Ready event
client.on("ready", (data) => {
console.log(`Logged in as ${client.me?.username}#${client.me?.discriminator}`);
console.log(`Serving ${client.guilds.cache.size} guilds`);
});
// Resumed event (after reconnection)
client.on("resumed", () => {
console.log("Session resumed");
});
// Interaction received
client.on("interactionCreate", (interaction) => {
// Handle interactions (commands, buttons, select menus)
});import type { MessageStructureInstance } from "@hedystia/discord";
client.on("messageCreate", (message: MessageStructureInstance) => {
if (message.author.bot) return;
if (message.content === "!ping") {
message.reply("Pong!");
}
});
client.on("messageUpdate", (oldMessage, newMessage) => {
console.log("Message edited");
});
client.on("messageDelete", (message) => {
console.log("Message deleted:", message.content);
});client.on("guildCreate", (guild) => {
console.log(`Joined guild: ${guild.name}`);
});
client.on("guildDelete", (guild) => {
console.log(`Left guild: ${guild.name}`);
});
client.on("guildMemberAdd", (member) => {
console.log(`New member: ${member.displayName}`);
});
client.on("guildMemberRemove", (member) => {
console.log(`Member left: ${member.displayName}`);
});
client.on("guildRoleCreate", (role) => {
console.log(`Role created: ${role.name}`);
});client.on("channelCreate", (channel) => {
console.log("Channel created:", channel.name);
});
client.on("channelDelete", (channel) => {
console.log("Channel deleted:", channel.name);
});
client.on("threadCreate", (thread) => {
console.log("Thread created:", thread.name);
});client.on("voiceStateUpdate", (oldState, newState) => {
console.log("Voice state changed");
});
client.on("voiceServerUpdate", (data) => {
console.log("Voice server updated");
});Click to expand full event list
ready,resumedinteractionCreatemessageCreate,messageUpdate,messageDelete,messageDeleteBulkmessageReactionAdd,messageReactionRemove,messageReactionRemoveAll,messageReactionRemoveEmojiguildCreate,guildDelete,guildUpdate,guildUnavailableguildMemberAdd,guildMemberRemove,guildMemberUpdateguildBanAdd,guildBanRemoveguildRoleCreate,guildRoleDelete,guildRoleUpdateguildEmojisUpdate,guildStickersUpdateguildIntegrationsUpdate,guildScheduledEventCreate,guildScheduledEventDelete,guildScheduledEventUpdate,guildScheduledEventUserAdd,guildScheduledEventUserRemovechannelCreate,channelDelete,channelUpdate,channelPinsUpdatethreadCreate,threadDelete,threadUpdate,threadListSync,threadMemberUpdate,threadMembersUpdatevoiceStateUpdate,voiceServerUpdate,voiceChannelEffectSendpresenceUpdate,typingStartwebhooksUpdate,integrationCreate,integrationDelete,integrationUpdateinviteCreate,inviteDeleteautoModerationActionExecution,autoModerationRuleCreate,autoModerationRuleDelete,autoModerationRuleUpdateentitlementCreate,entitlementDelete,entitlementUpdatesubscriptionCreate,subscriptionUpdatestageInstanceCreate,stageInstanceDelete,stageInstanceUpdateguildSoundboardSoundCreate,guildSoundboardSoundDelete,guildSoundboardSoundUpdate,soundboardSounduserInstall,passiveSubscriptionUpdate
import { SlashCommandBuilder } from "@hedystia/discord";
// Wait for client to be ready
client.on("ready", async () => {
// Register global commands (takes up to 1 hour to propagate)
await client.registerCommands([
new SlashCommandBuilder()
.setName("ping")
.setDescription("Replies with Pong!"),
new SlashCommandBuilder()
.setName("echo")
.setDescription("Repeats your message")
.addStringOption((option) =>
option
.setName("text")
.setDescription("The text to repeat")
.setRequired(true)
.setMinLength(1)
.setMaxLength(2000)
),
]);
// Register guild-specific commands (instant, for testing)
await client.registerGuildCommands("GUILD_ID", [
new SlashCommandBuilder()
.setName("test")
.setDescription("Test command for this guild"),
]);
});new SlashCommandBuilder()
.setName("command")
.setDescription("A command with all option types")
.setDefaultMemberPermissions(0n) // Permission bits (0 = no one)
.setDMPermission(false) // Disable in DMs
.setNSFW(true) // Mark as NSFW
// Text options
.addStringOption((option) =>
option
.setName("text")
.setDescription("Some text")
.setRequired(true)
.setMinLength(1)
.setMaxLength(100)
.addChoice("Option 1", "value1")
.addChoice("Option 2", "value2")
)
// Number options
.addIntegerOption((option) =>
option
.setName("number")
.setDescription("An integer")
.setMinValue(0)
.setMaxValue(100)
)
.addNumberOption((option) =>
option
.setName("decimal")
.setDescription("A decimal number")
)
// Boolean option
.addBooleanOption((option) =>
option.setName("toggle").setDescription("Toggle something")
)
// Discord objects
.addUserOption((option) =>
option.setName("user").setDescription("Target user")
)
.addChannelOption((option) =>
option.setName("channel").setDescription("Target channel")
)
.addRoleOption((option) =>
option.setName("role").setDescription("Target role")
)
// Mentionable (users or roles)
.addMentionableOption((option) =>
option.setName("mention").setDescription("Mention someone")
)
// File attachment
.addAttachmentOption((option) =>
option.setName("file").setDescription("Upload a file")
)
// Subcommands
.addSubcommand((sub) =>
sub
.setName("subcommand")
.setDescription("A subcommand")
.addStringOption((opt) => opt.setName("arg").setDescription("Argument"))
)
// Subcommand groups
.addSubcommandGroup((group) =>
group
.setName("group")
.setDescription("A group of subcommands")
.addSubcommand((sub) =>
sub.setName("nested").setDescription("Nested subcommand")
)
);client.on("interactionCreate", async (interaction) => {
// Application commands (slash commands)
if (interaction.type === 2) {
const { name, options } = interaction.data;
if (name === "ping") {
// Reply to interaction (initial response)
await interaction.reply({
content: "Pong! π",
});
}
if (name === "echo") {
const text = options?.[0]?.value;
// Defer first (shows "thinking..." state)
await interaction.defer();
// Then edit the original response
await interaction.editOriginal({ content: text });
}
if (name === "secret") {
// Ephemeral response (only visible to the user)
await interaction.reply({
content: "This is secret!",
flags: 64, // ephemeral flag
});
}
}
// Component interactions (buttons, select menus)
if (interaction.type === 3) {
const { custom_id } = interaction.data;
if (custom_id === "my_button") {
// Reply to button click (ephemeral)
await interaction.reply({
content: "Button clicked!",
flags: 64,
});
}
}
// Using other interaction methods
if (needsFollowUp) {
// Send additional messages after initial response
await interaction.sendFollowUp({
content: "Follow-up message",
ephemeral: true,
});
}
// Delete original response
await interaction.deleteOriginal();
});import { AudioPlayer } from "@hedystia/discord";
// Join a voice channel
const connection = await client.voice.joinVoiceChannel({
guildId: "GUILD_ID",
channelId: "VOICE_CHANNEL_ID",
selfMute: false,
selfDeaf: false,
selfVideo: false,
});
console.log("Joined voice channel!");// Create audio player
const player = new AudioPlayer();
player.setConnection(connection);
// Play audio file (requires ffmpeg)
player.play("path/to/audio.mp3", {
volume: 0.5, // 0.0 to 1.0
loop: false, // Loop the audio
seek: 0, // Start at seconds
});
// Play from URL
player.play("https://example.com/audio.mp3", {
volume: 0.8,
});// Playback control
player.pause();
player.resume();
player.stop();
// Volume control
player.setVolume(0.5); // 50%
player.getVolume(); // Get current volume
// Seek
player.seek(30); // Jump to 30 seconds
player.getCurrentTime(); // Get current position
// Events
player.on("start", () => console.log("Started playing"));
player.on("finish", () => console.log("Finished playing"));
player.on("error", (err) => console.error("Player error:", err));
player.on("debug", (info) => console.log("Debug:", info));connection.on("ready", (data) => {
console.log("Voice connection ready", data);
});
connection.on("error", (error) => {
console.error("Voice connection error:", error);
});
connection.on("close", () => {
console.log("Voice connection closed");
});
connection.on("stateChange", (oldState, newState) => {
console.log("State changed:", oldState, newState);
});// Leave specific guild
await client.voice.leaveVoiceChannel("GUILD_ID");
// Leave all voice channels
for (const guildId of client.voice.connections.keys()) {
await client.voice.leaveVoiceChannel(guildId);
}Builders are fluent interfaces for constructing Discord objects. They provide method chaining for easy configuration.
import { EmbedBuilder } from "@hedystia/discord";
const embed = new EmbedBuilder()
.setTitle("My Embed")
.setDescription("This is the description")
.setURL("https://example.com")
.setColor("#FF0000") // Hex or number: 0xFF0000
.setTimestamp() // Current time
.setFooter({
text: "Footer text",
iconURL: "https://example.com/icon.png",
})
.setThumbnail("https://example.com/thumbnail.png")
.setImage("https://example.com/image.png")
.setAuthor({
name: "Author Name",
url: "https://example.com",
iconURL: "https://example.com/author.png",
})
.addField({
name: "Field 1",
value: "Field value",
inline: true,
})
.addFields(
{ name: "Field 2", value: "Value 2" },
{ name: "Field 3", value: "Value 3", inline: true }
);
// Send with a channel (assuming you have a channel object)
channel.send({
content: "Check this out!",
embeds: [embed],
});
// Or with interaction response
interaction.reply({
embeds: [embed],
});import { ButtonBuilder, ButtonStyle } from "@hedystia/discord";
// Primary button
const primary = new ButtonBuilder()
.setLabel("Click Me")
.setCustomId("my_button")
.setStyle(ButtonStyle.Primary);
// Preset styles
ButtonBuilder.primary()
.setLabel("Primary")
.setCustomId("primary");
ButtonBuilder.secondary()
.setLabel("Secondary")
.setCustomId("secondary");
ButtonBuilder.success()
.setLabel("Success")
.setCustomId("success");
ButtonBuilder.danger()
.setLabel("Danger")
.setCustomId("danger");
// Link button (opens URL)
ButtonBuilder.link()
.setLabel("Visit Site")
.setURL("https://example.com");
// With emoji
button.setEmoji("π");
// or
button.setEmoji({ id: "emoji_id", name: "emoji", animated: false });
// Disabled state
button.setDisabled(true);import { ActionRowBuilder } from "@hedystia/discord";
const row = new ActionRowBuilder()
.addComponents(
ButtonBuilder.primary().setLabel("Button 1").setCustomId("btn1"),
ButtonBuilder.secondary().setLabel("Button 2").setCustomId("btn2")
);
// Or set all components at once
row.setComponents(button1, button2, button3);
// Send with message (builders are auto-converted)
channel.send({
content: "Click a button!",
components: [row],
});import {
ChannelSelectBuilder,
MentionableSelectBuilder,
RoleSelectBuilder,
UserSelectBuilder,
} from "@hedystia/discord";
// Channel select
const channelSelect = new ChannelSelectBuilder()
.setCustomId("channel_select")
.setPlaceholder("Select a channel")
.setMaxValues(3)
.setMinValues(1);
// User select
const userSelect = new UserSelectBuilder()
.setCustomId("user_select")
.setPlaceholder("Select a user")
.setMaxValues(5);
// Role select
const roleSelect = new RoleSelectBuilder()
.setCustomId("role_select")
.setPlaceholder("Select a role");
// Mentionable select (users or roles)
const mentionableSelect = new MentionableSelectBuilder()
.setCustomId("mentionable_select")
.setPlaceholder("Select someone");import {
ContainerBuilder,
SectionBuilder,
SeparatorBuilder,
TextDisplayBuilder,
MediaGalleryBuilder,
ThumbnailBuilder,
} from "@hedystia/discord";
// Text display (markdown)
const textDisplay = new TextDisplayBuilder()
.setContent("# Hello\nThis is **markdown** content");
// Separator
const separator = new SeparatorBuilder()
.setSpacing(1); // or 2, 3
// Section with components
const section = new SectionBuilder()
.addComponents(textDisplay, button);
// Container for grouping
const container = new ContainerBuilder()
.addComponents(section, separator);
// Media gallery
const gallery = new MediaGalleryBuilder()
.addItems({
url: "https://example.com/image.jpg",
description: "Image description",
});
// Thumbnail
const thumbnail = new ThumbnailBuilder()
.setURL("https://example.com/thumb.jpg")
.setHeight(100)
.setWidth(100);Collectors allow you to collect and handle multiple events over a period of time.
import { MessageCollector } from "@hedystia/discord";
const collector = new MessageCollector(client, {
time: 60000, // 1 minute
max: 10, // Max 10 messages
maxProcessing: 5, // Max 5 per second
filter: (msg) => msg.author.id === "USER_ID",
channelId: "CHANNEL_ID",
guildId: "GUILD_ID",
userId: "USER_ID",
dispose: true, // Remove from cache on dispose
resetTimer: true, // Reset timer on each collect
});
collector.on("collect", (message) => {
console.log("Collected:", message.content);
});
collector.on("ignore", (message) => {
console.log("Ignored:", message.content);
});
collector.on("dispose", (message) => {
console.log("Disposed:", message.content);
});
collector.on("end", (collected, reason) => {
console.log(`Ended: ${reason}`);
console.log(`Collected ${collected.size} messages`);
// Iterate over collected messages
for (const [id, msg] of collected.entries()) {
console.log(id, msg.content);
}
});
// Stop manually
collector.stop("user");import { InteractionCollector } from "@hedystia/discord";
// Button collector
const buttonCollector = InteractionCollector.createButtonCollector(
client,
"my_button_id", // Custom ID to filter
{
time: 30000,
max: 5,
channelId: "CHANNEL_ID",
guildId: "GUILD_ID",
userId: "USER_ID",
}
);
buttonCollector.on("collect", async (interaction) => {
console.log("Button clicked by:", interaction.user?.id);
// Acknowledge interaction
await interaction.reply({
content: "Button clicked!",
});
});
// Select menu collector
const selectCollector = InteractionCollector.createSelectMenuCollector(
client,
"select_id",
{ time: 60000 }
);
selectCollector.on("collect", (interaction) => {
const values = interaction.data.values;
console.log("Selected:", values);
});
// Message component collector (all interactions on a message)
const messageCollector = InteractionCollector.createMessageCollector(
client,
"MESSAGE_ID",
{ time: 120000 }
);import { ReactionCollector } from "@hedystia/discord";
const collector = new ReactionCollector(client, {
messageId: "MESSAGE_ID",
channelId: "CHANNEL_ID",
guildId: "GUILD_ID",
userId: "USER_ID",
emoji: "π", // Filter by emoji
maxReactions: 10, // Max total reactions
time: 60000,
});
collector.on("collect", (reaction, userId) => {
console.log(`Reaction ${reaction.emoji.name} by ${userId}`);
});
collector.on("end", (collected, reason) => {
console.log(`Total unique reactions: ${collector.uniqueReactions}`);
console.log(`Total reactions: ${collector.totalReactions}`);
});
// Static helpers
ReactionCollector.createMessageCollector(client, "MESSAGE_ID");
ReactionCollector.createEmojiCollector(client, "π");| Option | Type | Description |
|---|---|---|
time |
number |
Time in milliseconds before stopping |
max |
number |
Maximum number of items to collect |
maxProcessing |
number |
Maximum items per second |
filter |
function |
Filter function (item, ...args) => boolean |
dispose |
boolean |
Whether to dispose items when removed |
resetTimer |
boolean |
Whether to reset timer on each collect |
messageId |
string |
Filter by message ID |
channelId |
string |
Filter by channel ID |
guildId |
string |
Filter by guild ID |
userId |
string |
Filter by user ID |
emoji |
string |
Filter by emoji (ReactionCollector) |
customId |
string |
Filter by custom ID (InteractionCollector) |
componentType |
number |
Filter by component type |
Managers handle caching and fetching of Discord objects.
// Fetch a user
const user = await client.users.fetch("USER_ID");
// Access cache
const cached = client.users.cache.get("USER_ID");
// Iterate cache
for (const [id, user] of client.users.cache.entries()) {
console.log(id, user.username);
}// Fetch a guild
const guild = await client.guilds.fetch("GUILD_ID");
// Access cache
const cached = client.guilds.cache.get("GUILD_ID");
// Get all guilds
const allGuilds = await client.guilds.fetchAll();// Fetch a channel
const channel = await client.channels.fetch("CHANNEL_ID");
// Access cache
const cached = client.channels.cache.get("CHANNEL_ID");// Fetch a member
const member = await client.members.fetch("GUILD_ID", "USER_ID");
// Access cache
const cached = client.members.cache.get("USER_ID");
// Get all members in a guild
const guildMembers = await client.members.fetchGuildMembers("GUILD_ID");// Fetch a role
const role = await client.roles.fetch("GUILD_ID", "ROLE_ID");
// Access cache
const cached = client.roles.cache.get("ROLE_ID");// Fetch all emojis from a guild
const emojis = await client.emojis.fetch("GUILD_ID");
// Fetch single emoji
const emoji = await client.emojis.fetchOne("GUILD_ID", "EMOJI_ID");
// Access cache
const cached = client.emojis.cache.get("EMOJI_ID");const client = new Client({
cache: {
managers: {
users: {
enabled: true,
maxSize: 10000,
ttl: 1800000, // 30 minutes
dynamicTTL: true, // Extend TTL on access
},
guilds: {
enabled: true,
maxSize: 1000,
},
channels: {
enabled: true,
maxSize: 5000,
},
},
},
});Structures are rich wrappers around Discord API data.
// Properties
interaction.id; // Interaction ID
interaction.type; // Interaction type
interaction.token; // Interaction token
interaction.data; // Interaction data
interaction.message; // Message (for component interactions)
interaction.user; // User who triggered
interaction.member; // Member (in guilds)
interaction.customId; // Custom ID (for components)
interaction.userId; // User ID who triggered
interaction.isButton; // Is from a button
interaction.isSelectMenu; // Is from a select menu
interaction.isMessageComponent; // Is a message component
// Methods - Response handling
await interaction.reply({ // Initial response
content: "Hello!",
embeds: [embed],
components: [row],
flags: 64, // ephemeral (optional)
});
await interaction.defer(ephemeral); // "thinking..." state
await interaction.editOriginal({ // Edit original response
content: "Edited!",
embeds: [newEmbed],
});
await interaction.deleteOriginal(); // Delete original response
await interaction.sendFollowUp({ // Additional message
content: "Follow-up",
ephemeral: true,
});
// Methods - Collectors
interaction.createMessageComponentCollector(options);
interaction.createButtonCollector(customId, options);
interaction.createSelectMenuCollector(customId, options);// Properties
message.mention; // Message URL
message.author; // Author info
message.isFromCurrentUser; // Boolean
message.isCrossposted; // Boolean
message.isAutomaticModerationAction;
message.createdTimestamp; // Unix timestamp
message.createdAt; // Date object
message.editedTimestamp;
message.editedAt;
message.isEditable;
message.isDeletable;
message.isPinnable;
message.hasEmbeds;
message.hasAttachments;
message.hasReactions;
message.mentionsEveryone;
// Check mentions
message.mentionsRole("ROLE_ID");
message.mentionsUser("USER_ID");
message.mentionsChannel("CHANNEL_ID");
// Actions
await message.react("π");
await message.reply("Reply content");
await message.edit("New content");
await message.delete();
await message.pin();
await message.unpin();
await message.fetch(); // Refetch from API
await message.crosspost(); // For news channels
await message.startThread("Name", 1440); // 1440 = 24h
// Create collectors on message
message.createReactionCollector({ time: 60000 });
message.createButtonCollector("button_id", { time: 30000 });
message.createSelectMenuCollector("select_id");
message.createMessageComponentCollector({ time: 60000 });// URLs
guild.iconURL({ size: 1024, extension: "png" });
guild.bannerURL({ size: 1024 });
guild.splashURL();
guild.discoverySplashURL();
// Timestamps
guild.createdTimestamp;
guild.createdAt;
// Cache access
guild.members; // Members array from cache
guild.channels; // Channels array from cache
guild.roles; // Roles array from cache
// Properties
guild.isOwner; // Is current user the owner?
guild.available; // Is guild available?
guild.isLarge; // Is guild large (>250 members)?
// Comparison
guild.equals(otherGuild);// Mentions
member.mention; // <@user_id>
member.nicknameMention; // <@!user_id> or null
// Display name
member.displayName; // Nickname or username
// Avatar
member.avatarURL({ size: 1024, extension: "png" });
member.bannerURL({ size: 1024 });
// Timestamps
member.joinedTimestamp;
member.joinedAt;
member.premiumSinceTimestamp;
member.premiumSince;
member.communicationDisabledUntilTimestamp;
member.communicationDisabledUntil;
// Properties
member.isCommunicationDisabled;
member.isPremium; // Is boosting
member.isPending; // Pending verification
// Role checks
member.hasRole("ROLE_ID");
member.hasAnyRole("ROLE1", "ROLE2");
member.hasAllRoles("ROLE1", "ROLE2");// Mention
role.mention; // <@&role_id> or @everyone
// Color
role.hexColor; // #RRGGBB
// Timestamp
role.createdTimestamp;
role.createdAt;
// Properties
role.isEveryone; // Is @everyone
role.isBotRole; // Has bot_id tag
role.isIntegrationRole; // Has integration_id tag
role.isPremiumSubscriberRole;
role.isAvailableForPurchase;
role.isGuildLinkedRole;// Mention
user.mention; // <@user_id>
// Avatar
user.avatarURL({ size: 1024, extension: "png", forceStatic: false });
user.defaultAvatarURL; // Default Discord avatar
// Banner
user.bannerURL({ size: 1024 });
// Properties
user.isBot;
user.isSystem;
user.displayName; // Global name or username
// Timestamps
user.createdTimestamp;
user.createdAt;Note: For most use cases, prefer using the high-level methods from Structures (like
channel.send(),message.edit(),interaction.reply()). Use the REST API directly only when you need low-level control or when a method isn't available in the structures.
import REST from "@hedystia/discord";
const rest = new REST({
token: "Bot YOUR_TOKEN",
version: 10,
restRequestTimeout: 10000,
});
// GET request
const user = await rest.get("/users/@me");
// POST request
const message = await rest.post("/channels/CHANNEL_ID/messages", {
body: {
content: "Hello!",
embeds: [embed],
},
});
// PUT request (update)
await rest.put("/channels/CHANNEL_ID/messages/MSG_ID", {
body: { content: "Updated content" },
});
// PATCH request (partial update)
await rest.patch("/users/@me", {
body: { username: "New Name" },
});
// DELETE request
await rest.delete("/channels/CHANNEL_ID/messages/MSG_ID");await rest.get("/users/USER_ID", {
headers: {
"X-Custom-Header": "value",
},
query: {
with_counts: "true",
},
reason: "Audit log reason",
auth: true, // Include auth header
});import { Routes } from "@hedystia/discord";
// User routes
Routes.user(userId);
Routes.channel(channelId);
// Guild routes
Routes.guild(guildId);
Routes.guildChannels(guildId);
Routes.guildMembers(guildId);
Routes.guildMember(guildId, userId);
Routes.guildRoles(guildId);
Routes.guildRole(guildId, roleId);
Routes.guildBans(guildId);
Routes.guildBan(guildId, userId);
Routes.guildEmojis(guildId);
Routes.guildEmoji(guildId, emojiId);
// Command routes
Routes.applicationCommands(applicationId);
Routes.applicationCommand(applicationId, commandId);
Routes.applicationGuildCommands(applicationId, guildId);
Routes.applicationGuildCommand(applicationId, guildId, commandId);
// Interaction routes
Routes.interactionCallback(interactionId, token);
// Other routes
Routes.gatewayBot();
Routes.webhook(webhookId, token);
Routes.webhookMessage(webhookId, token, messageId);// Automatic rate limit handling
const info = rest.getRateLimitInfo("GET", "/channels/CHANNEL_ID/messages");
console.log(info.remaining, info.resetAfter);
// Check if rate limited
const isLimited = rest.isRateLimited("POST", "/channels/CHANNEL_ID/messages");
const timeUntilReset = rest.getTimeUntilReset("GET", "/users/@me");import { CDN, ImageFormat } from "@hedystia/discord";
// Avatar
const avatarUrl = CDN.avatar(userId, hash, {
size: 1024,
format: ImageFormat.PNG,
});
// Guild icons
const iconUrl = CDN.guildIcon(guildId, hash);
const bannerUrl = CDN.guildBanner(guildId, hash);
const splashUrl = CDN.splash(guildId, hash);
// Emoji
const emojiUrl = CDN.emoji(emojiId, { animated: true });
// App icons
const appIconUrl = CDN.appIcon(applicationId, assetId);
const appCoverImageUrl = CDN.appCoverImage(applicationId, assetId);
// All URLs include https://cdn.discordapp.com prefiximport { Cache } from "@hedystia/discord";
const cache = new Cache({
maxSize: 100,
ttl: 300000, // 5 minutes
dynamicTTL: true, // Extend on access
cleanupInterval: 60000,
});
// Basic operations
cache.set("key", "value");
cache.get("key");
cache.has("key");
cache.delete("key");
cache.clear();
// With per-item options
cache.set("key", "value", {
ttl: 60000, // Override TTL
keepForever: true, // Never expire
});
// Stats
const stats = cache.getStats();
console.log(`Hit ratio: ${(stats.hitRatio * 100).toFixed(2)}%`);
console.log(`Hits: ${stats.hits}, Misses: ${stats.misses}`);import { Collection } from "@hedystia/discord";
const collection = new Collection();
// Map-like operations
collection.set("key", "value");
collection.get("key");
collection.has("key");
collection.delete("key");
collection.clear();
collection.size;
// Array-like methods
collection.first(); // First value
collection.first(5); // First 5 values
collection.last(); // Last value
collection.at(0); // Value at index
collection.find((v, k) => v === "value");
collection.filter((v, k) => k.startsWith("prefix"));
collection.map((v, k) => v.toUpperCase());
collection.some((v, k) => v === "test");
collection.every((v, k) => v !== null);
collection.forEach((v, k) => console.log(k, v));
// Reduce
const sum = collection.reduce((acc, val) => acc + val, 0);
// Sorting
collection.sort((a, b) => a - b);
const sorted = collection.sorted((a, b) => a - b);
// Utilities
collection.clone();
collection.random();
collection.randomKey();
collection.equals(otherCollection);
collection.isEmpty();
// Set operations
const union = collection.union(other);
const intersection = collection.intersection(other);
const difference = collection.difference(other);
const symmetricDiff = collection.symmetricDifference(other);
// Math
collection.sum();
collection.average();
collection.min();
collection.max();import Client, {
Intents,
EmbedBuilder,
ButtonBuilder,
ActionRowBuilder,
SlashCommandBuilder,
ActivityType,
} from "@hedystia/discord";
const client = new Client({
token: process.env.DISCORD_TOKEN!,
intents: Intents.guilds | Intents.guildMessages | Intents.messageContent,
presence: {
activities: [{ name: "Discord", type: ActivityType.Playing }],
status: "online",
},
});
client.on("ready", async () => {
console.log(`β
Logged in as ${client.me?.username}`);
// Register commands
await client.registerCommands([
new SlashCommandBuilder()
.setName("ping")
.setDescription("Check bot latency"),
]);
});
client.on("interactionCreate", async (interaction) => {
if (interaction.type !== 2) return; // Not a command
if (interaction.data.name === "ping") {
const embed = new EmbedBuilder()
.setTitle("π Pong!")
.setDescription(`Latency: ${client.ping}ms`)
.setColor(0x00FF00)
.setTimestamp();
const button = ButtonBuilder.primary()
.setLabel("Refresh")
.setCustomId("refresh_ping");
const row = new ActionRowBuilder().addComponents(button);
// Reply to interaction using InteractionStructure methods
await interaction.reply({
embeds: [embed],
components: [row],
});
// Handle button clicks
const collector = interaction.createButtonCollector("refresh_ping", {
time: 60000
});
collector.on("collect", async (btnInteraction) => {
embed.setDescription(`Latency: ${client.ping}ms (refreshed)`);
// Edit the original response
await btnInteraction.editOriginal({
embeds: [embed],
});
// Acknowledge the button click (ephemeral)
await btnInteraction.defer(true);
});
}
});
client.on("messageCreate", (message) => {
if (message.author.bot) return;
if (message.content === "!hello") {
message.reply("Hello there! π");
}
});
await client.login();MIT