Skip to content

Follow-ups and edits

Send more messages after the first reply, then edit or delete them later. Covers the targets that have to come from this interaction, and send() picking the method for you.

Once you've replied or deferred, this.followUp() sends another message. Every one of reply(), followUp(), and edit() resolves to the message it wrote. Pass one back to edit() to rewrite it.

src/handlers/Ban.ts
import { SlashHandler, SlashRoute } from '@seedcord/gateway';

@SlashRoute('ban')
export class Ban extends SlashHandler<'ban'> {
    public async execute(): Promise<void> {
        const target = this.options.getUser('target');

        await this.reply(`Banned ${target.username}.`);

        const progress = await this.followUp('Revoking sessions.');
        const revoked = await revokeSessions(target.id);

        await this.edit(progress, `Revoked ${revoked} sessions.`);
    }
}

edit() with one argument rewrites the first reply. edit(message, response) rewrites the message you pass.

Gateway and http differ

That message is a discord.js Message on gateway and an APIMessage on http. Passing it back to edit() or delete() works on both.

Targets have to come from this interaction

Discord lets an interaction's token edit and delete only the messages sent with that token. seedcord stores the id of every message it sends, and a targeted edit() or delete() checks the id against that list before calling Discord.

edit() was passed message 1287, which this interaction did not send.
Pass a message this interaction sent, returned by reply(),
followUp(), edit(), or update(). (route slash:ban)

delete() checks the same list. Without an argument it removes the first reply. delete(message) removes the one you pass, so that id leaves the list and a later edit of it throws.

const notice = await this.followUp('Working.');

await this.delete(notice);
await this.delete();

send() picks the method for you

this.send() works from every state, so it never throws the wrong-state error that the other methods throw.

statesend() calls
nothing sent yetreply()
deferred a replyedit(), filling the placeholder
deferred an updatefollowUp()
already repliedfollowUp()

ephemeral and silent apply only when send() creates a message. On the edit() row it drops them, since edit() doesn't take options.

Use send() in code that runs from more than one state, like a helper that a deferring handler and a replying handler both call.

If you already know the state, call reply() or edit() directly. Each one throws on a state it can't run in, so a misplaced defer() surfaces as a throw from reply().

After a deferral, send() edits the placeholder. Call followUp() for a new message.