Tips & Reference

Structures

When you fetch or receive Discord objects, Seyfert returns typed structures with useful methods and properties. Here's a reference for the most common ones.

Member

const member = ctx.member;

member.id;                          // User ID
member.guildId;                     // Guild ID
member.user;                        // User object
member.roles.keys;                  // readonly string[] — role IDs, including @everyone
await member.roles.list();          // GuildRoleStructure[]

Voice State

// From cache
const voice = await member.voice('cache');

// Cache with API fallback
const voiceFlow = await member.voice('flow');

voice?.channelId;   // Voice channel ID or null

Permissions

// From cache
const perms = await member.fetchPermissions();
perms.has(['Administrator']);                       // boolean
perms.missings(['SendMessages', 'EmbedLinks']);     // return missings permisions, empty array if not

Actions

await member.ban({ deleteMessageSeconds: 0, reason: 'Reason' });
await member.kick('Reason');
await member.edit({ nick: 'New Nickname' });
await member.write({ content: 'DM message' });    // Send DM

Guild

const guild = await ctx.guild();

guild.id;                                           // Guild ID
guild.name;                                         // Guild name
guild.memberCount;                                  // Approximate member count
await guild.members.fetch('userId');                // Fetch a specific member
await guild.members.list({ limit: 100 });          // List members

Channel

const channel = await client.channels.fetch('channelId');

channel.id;                    // Channel ID

// Type guards
channel.isThread();            // ThreadChannel
channel.isNews();              // AnnouncementChannel
channel.isVoice();             // VoiceChannel
channel.isStage();             // StageChannel

// Send a message
if (channel.isTextable()) await channel.messages.write({ content: 'Hello' });

Message

message.id;                    // Message ID
message.content;               // Text content
message.author;                // User who sent it
message.guildId;               // Guild ID (null in DMs)
message.channelId;             // Channel ID
message.createdTimestamp;      // Unix timestamp

// Actions
await message.reply({ content: 'Reply!' });
await message.edit({ content: 'Edited' });
await message.delete();
await message.crosspost();     // Publish in announcement channel

// Create a component collector
message.createComponentCollector({ /* ... */ });

Permissions

Common permission strings used in defaultMemberPermissions, botPermissions, and permission checks:

PermissionDescription
AdministratorFull access to everything
ManageGuildManage server settings
ManageRolesCreate and edit roles
ManageChannelsCreate and edit channels
KickMembersKick members
BanMembersBan members
ManageMessagesDelete and pin messages
SendMessagesSend messages in channels
EmbedLinksSend embedded content
AttachFilesUpload files
ReadMessageHistoryView channel history
ViewChannelView channels
ConnectConnect to voice channels
SpeakSpeak in voice channels
MoveMembersMove members between voice channels
ModerateMembersTimeout members

Interaction Type Guards

At Seyfert, we do not recommend using this event unless it is strictly necessary (such as for urgent support of a feature)

In the interactionCreate event or when manually handling interactions:

import { createEvent } from 'seyfert';

export default createEvent({
    data: { name: 'interactionCreate' },
    run(interaction, client) {
        if (interaction.isButton()) { /* ButtonInteraction */ }
        if (interaction.isStringSelectMenu()) { /* StringSelectMenuInteraction */ }
        if (interaction.isUserSelectMenu()) { /* UserSelectMenuInteraction */ }
        if (interaction.isRoleSelectMenu()) { /* RoleSelectMenuInteraction */ }
        if (interaction.isChannelSelectMenu()) { /* ChannelSelectMenuInteraction */ }
        if (interaction.isMentionableSelectMenu()) { /* ... */ }
        if (interaction.isModalSubmit()) { /* ModalSubmitInteraction */ }
        if (interaction.isAutocomplete()) { /* AutocompleteInteraction */ }
        if (interaction.isChatInput()) { /* ChatInputCommandInteraction */ }
    },
});

Shorters

Shorters are convenience methods on the client for common operations without needing to fetch full objects first:

// Users
await client.users.fetch('userId');
await client.users.createDM('userId');

// Messages
await client.messages.write('channelId', { content: 'Hello' });
await client.messages.edit('messageId', 'channelId', { content: 'Edited' });
await client.messages.delete('messageId', 'channelId');

// Members
await client.members.fetch('guildId', 'userId');
await client.members.edit('guildId', 'userId', { nick: 'New Name' });
await client.members.kick('guildId', 'userId');
await client.members.ban('guildId', 'userId');

// Roles
await client.roles.create('guildId', { name: 'New Role', color: 0xFF0000 });
await client.roles.edit('guildId', 'roleId', { name: 'Updated' });

// Guilds
await client.guilds.fetch('guildId');
await client.guilds.list();

For more on Shorters and the Proxy API, see Shorters and Proxy.

Transformers

A transformer is a function that takes the raw data Discord sends and turns it into whatever value you need. Instead of working with the default structures, you can replace them with your own shape, keeping a reference to the raw object when you still need it.

Define a transformer by assigning to Transformers.<Structure> and declare its type through the CustomStructures interface so the new shape is reflected across your whole project:

import { Transformers } from 'seyfert';

Transformers.User = (client, data) => {
    return {
        username: data.username,
        isAdmin: ['123456789012345678'].includes(data.id),
        raw() {
            return client.users.raw(data.id);
        },
    };
};

/*
At this point, you should have a `declare module "seyfert"` in your project,
if not, add it.
*/
declare module "seyfert" {
// Declaring the type this way will reflect in the typing throughout the entire project.
    interface CustomStructures {
        User: MyUser;
    }
// You can add as many transformers as you like with any type.
}

Let the autocomplete of your editor guide you and discover all the possibilities you have.

import { Transformers } from 'seyfert';

Transformers.Guil
  • Guild
  • GuildBan
  • GuildEmoji
  • GuildMember
  • GuildRole
  • GuildTemplate
dMember

Once defined, the transformed shape is used everywhere that structure appears. For the user transformer above, ctx.author now exposes your custom properties and methods:

import { type CommandContext, Command, Declare } from 'seyfert';

@Declare({
    name: 'ping',
    description: 'Ping!',
})
class Ping extends Command {
    async run(ctx: CommandContext) {
        const result = await ctx.author.
  • isAdmin
  • raw
  • username
raw();
console.log(result.id, result.username); } }