Skip to content

Handling components

Updating Seyfert config

Having sent the component within a channel it’s about time you want to handle the interaction from the component.

To handle them we have to tell seyfert where will be the components located in our project. We have to do this within our seyfert config file.

seyfert.config.mjs
// @ts-check
import {
const config: {
bot(data: RuntimeConfig): InternalRuntimeConfig;
http(data: RuntimeConfigHTTP): InternalRuntimeConfigHTTP;
}
config
} from "seyfert";
export default
const config: {
bot(data: RuntimeConfig): InternalRuntimeConfig;
http(data: RuntimeConfigHTTP): InternalRuntimeConfigHTTP;
}
config
.
function bot(data: RuntimeConfig): InternalRuntimeConfig

Configurations for the bot.

@paramdata - The runtime configuration data for gateway connections.

@returnsThe internal runtime configuration.

bot
({
token: string
token
:
var process: NodeJS.Process
process
.
NodeJS.Process.env: NodeJS.ProcessEnv

The process.env property returns an object containing the user environment. See environ(7).

An example of this object looks like:

{
TERM: 'xterm-256color',
SHELL: '/usr/local/bin/bash',
USER: 'maciej',
PATH: '~/.bin/:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin',
PWD: '/Users/maciej',
EDITOR: 'vim',
SHLVL: '1',
HOME: '/Users/maciej',
LOGNAME: 'maciej',
_: '/usr/local/bin/node'
}

It is possible to modify this object, but such modifications will not be reflected outside the Node.js process, or (unless explicitly requested) to other Worker threads. In other words, the following example would not work:

Terminal window
node -e 'process.env.foo = "bar"' && echo $foo

While the following will:

import { env } from 'node:process';
env.foo = 'bar';
console.log(env.foo);

Assigning a property on process.env will implicitly convert the value to a string. This behavior is deprecated. Future versions of Node.js may throw an error when the value is not a string, number, or boolean.

import { env } from 'node:process';
env.test = null;
console.log(env.test);
// => 'null'
env.test = undefined;
console.log(env.test);
// => 'undefined'

Use delete to delete a property from process.env.

import { env } from 'node:process';
env.TEST = 1;
delete env.TEST;
console.log(env.TEST);
// => undefined

On Windows operating systems, environment variables are case-insensitive.

import { env } from 'node:process';
env.TEST = 1;
console.log(env.test);
// => 1

Unless explicitly specified when creating a Worker instance, each Worker thread has its own copy of process.env, based on its parent thread's process.env, or whatever was specified as the env option to the Worker constructor. Changes to process.env will not be visible across Worker threads, and only the main thread can make changes that are visible to the operating system or to native add-ons. On Windows, a copy of process.env on a Worker instance operates in a case-sensitive manner unlike the main thread.

@sincev0.1.27

env
.
string | undefined
BOT_TOKEN
?? "",
intents?: number | IntentStrings | number[]
intents
: ["Guilds"],
locations: RCLocations
locations
: {
RCLocations.base: string
base
: "dist",
RCLocations.commands?: string
commands
: "commands",
RCLocations.events?: string
events
: "events",
RCLocations.components?: string
components
: 'components'
}
});

First of all we are going to create a file inside the directory which is set for the components.

Then we are going to create a class that extends ComponentCommand, something like what we do with commands, and then we are going to set the type of the component we want to handle (Buttons or whichever type of SelectMenu)

In this example I have created a component to reply Hello World to the interaction. I have set the customId of the button to hello-world.

import { ComponentCommand } from 'seyfert';
export default class HelloWorldButton extends ComponentCommand {
componentType = 'Button' as const;
}

Filtering component interactions

Now we want the handler to handle only the interactions created by the HelloWorld button so we will use the customId we have to set in all the components.

To filter the interactions we are using a function inherited by the ComponentCommand class in which we have to return a boolean.

import { ComponentCommand, type ComponentContext } from 'seyfert';
export default class HelloWorldButton extends ComponentCommand {
componentType = 'Button' as const;
filter(ctx: ComponentContext<typeof this.componentType>) {
//we are checking if the customId of the interaction is the same that the one set in my button
return ctx.customId === 'hello-world';
}
}

Running the component handler

If the filter function success and returns true the handler will then execute a run function with your code logic.

import {
class ComponentCommand
ComponentCommand
, type
class ComponentContext<Type extends keyof ContextComponentCommandInteractionMap = keyof ContextComponentCommandInteractionMap, M extends keyof RegisteredMiddlewares = never>
interface ComponentContext<Type extends keyof ContextComponentCommandInteractionMap = keyof ContextComponentCommandInteractionMap, M extends keyof RegisteredMiddlewares = never>

Represents a context for interacting with components in a Discord bot.

ComponentContext
} from 'seyfert';
import { MessageFlags } from 'seyfert/lib/types';
export default class
class HelloWorldButton
HelloWorldButton
extends
class ComponentCommand
ComponentCommand
{
HelloWorldButton.componentType: "Button"
componentType
= 'Button' as
type const = "Button"
const
;
//this can be a promise too.
HelloWorldButton.filter(ctx: ComponentContext<typeof this.componentType>): boolean
filter
(
ctx: ComponentContext<"Button", never>
ctx
:
class ComponentContext<Type extends keyof ContextComponentCommandInteractionMap = keyof ContextComponentCommandInteractionMap, M extends keyof RegisteredMiddlewares = never>
interface ComponentContext<Type extends keyof ContextComponentCommandInteractionMap = keyof ContextComponentCommandInteractionMap, M extends keyof RegisteredMiddlewares = never>

Represents a context for interacting with components in a Discord bot.

ComponentContext
<typeof
this: this
this
.
HelloWorldButton.componentType: "Button"
componentType
>) {
return
ctx: ComponentContext<"Button", never>
ctx
.
ComponentContext<"Button", never>.customId: string

Gets the custom ID of the interaction.

customId
=== 'hello-world';
}
async
HelloWorldButton.run(ctx: ComponentContext<typeof this.componentType>): Promise<void>
run
(
ctx: ComponentContext<"Button", never>
ctx
:
class ComponentContext<Type extends keyof ContextComponentCommandInteractionMap = keyof ContextComponentCommandInteractionMap, M extends keyof RegisteredMiddlewares = never>
interface ComponentContext<Type extends keyof ContextComponentCommandInteractionMap = keyof ContextComponentCommandInteractionMap, M extends keyof RegisteredMiddlewares = never>

Represents a context for interacting with components in a Discord bot.

ComponentContext
<typeof
this: this
this
.
HelloWorldButton.componentType: "Button"
componentType
>) {
return
ctx: ComponentContext<"Button", never>
ctx
.
ComponentContext<"Button", never>.write<false>(body: InteractionCreateBodyRequest, fetchReply?: false | undefined): Promise<void>

Writes a response to the interaction.

@parambody - The body of the response.

@paramfetchReply - Whether to fetch the reply or not.

write
({
content?: string | undefined

The message contents (up to 2000 characters)

content
: 'Hello World 👋',
flags?: MessageFlags

Message flags combined as a bitfield

flags
: MessageFlags.
function (enum member) MessageFlags.Ephemeral = 64

This message is only visible to the user who invoked the Interaction

Ephemeral
});
}
}