Skip to content

Files and attachments

Upload files with a reply and show them in the message. Covers the component that has to reference the upload, and the four fields.

A seedcord reply is made of components, so a file you upload needs two things: the bytes in files, and a component that points at them. Both transports take a ReplyFile, the bytes plus the name Discord shows.

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

class ReportCard extends BuilderComponent<'container'> {
    constructor(filename: string) {
        super('container');

        this.instance.addFileComponents((file) =>
            file.setURL(`attachment://${filename}`)
        );
    }
}

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

        await this.reply({
            components: [new ReportCard(name).component],
            files: [{ data: bytes, name }]
        });
    }
}

A component has to reference the upload

Under ComponentsV2, Discord renders an attachment where a component references it. Set the component's URL to attachment:// plus the name you gave the file. A file component, a thumbnail, and a media gallery item all take that URL.

Use a media gallery for images and video you want shown inline, a thumbnail for one small image beside a section's text, and a file component for a download row like report.pdf above.

An upload with no component pointing at it still reaches Discord. Nobody reading the message sees it.

The fields

fieldtakeswhat it does
dataUint8Arraythe bytes. A node Buffer assigns here, since it extends Uint8Array
namestringthe filename Discord shows, and what an attachment:// reference resolves against
descriptionstringalt text, read by screen readers and shown on hover
titlestringa display title Discord shows in place of the filename

data and name are required. A file missing its name fails to compile.

Prefix the name with SPOILER_ to blur the attachment until the viewer clicks it.

files: [
    {
        data: bytes,
        name: 'SPOILER_evidence.png',
        description: 'The message before it was edited',
        title: 'Evidence'
    }
];

Gateway and http differ

Http takes ReplyFile alone, so a discord.js file form is a compile error there.

Gateway takes every form that discord.js takes, since it passes files straight to the library.

files: [
    new AttachmentBuilder(createReadStream('./report.pdf'), {
        name: 'report.pdf'
    })
];

That includes AttachmentBuilder, an Attachment from an existing message, a bare Buffer, a node Stream, a path or URL string, and an { attachment, name } payload. One files array mixes them with ReplyFile entries freely, since each element types on its own.

Use GatewayReplyResponse to type a helper that returns one of these.