rendering to channel + simplified adapter interface
This commit is contained in:
147
library/core/reacord-discord-js.ts
Normal file
147
library/core/reacord-discord-js.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
import type * as Discord from "discord.js"
|
||||
import { raise } from "../../helpers/raise"
|
||||
import { toUpper } from "../../helpers/to-upper"
|
||||
import type { ComponentInteraction } from "../internal/interaction"
|
||||
import type { Message, MessageOptions } from "../internal/message"
|
||||
import type { ReacordConfig, ReacordInstance } from "./reacord"
|
||||
import { Reacord } from "./reacord"
|
||||
|
||||
export class ReacordDiscordJs extends Reacord {
|
||||
constructor(client: Discord.Client, config: ReacordConfig = {}) {
|
||||
super(config)
|
||||
|
||||
client.on("interactionCreate", (interaction) => {
|
||||
if (interaction.isMessageComponent()) {
|
||||
this.handleComponentInteraction(
|
||||
createReacordComponentInteraction(interaction),
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override send(channel: Discord.TextBasedChannel): ReacordInstance {
|
||||
return this.createChannelRendererInstance({
|
||||
send: async (options) => {
|
||||
const message = await channel.send(getDiscordMessageOptions(options))
|
||||
return createReacordMessage(message)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
override reply(interaction: Discord.CommandInteraction): ReacordInstance {
|
||||
return this.createCommandReplyRendererInstance({
|
||||
type: "command",
|
||||
id: interaction.id,
|
||||
channelId: interaction.channelId,
|
||||
reply: async (options) => {
|
||||
const message = await interaction.reply({
|
||||
...getDiscordMessageOptions(options),
|
||||
fetchReply: true,
|
||||
})
|
||||
return createReacordMessage(message as Discord.Message)
|
||||
},
|
||||
followUp: async (options) => {
|
||||
const message = await interaction.followUp({
|
||||
...getDiscordMessageOptions(options),
|
||||
fetchReply: true,
|
||||
})
|
||||
return createReacordMessage(message as Discord.Message)
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function createReacordComponentInteraction(
|
||||
interaction: Discord.MessageComponentInteraction,
|
||||
): ComponentInteraction {
|
||||
if (interaction.isButton()) {
|
||||
return {
|
||||
type: "button",
|
||||
id: interaction.id,
|
||||
channelId: interaction.channelId,
|
||||
customId: interaction.customId,
|
||||
update: async (options) => {
|
||||
await interaction.update(getDiscordMessageOptions(options))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (interaction.isSelectMenu()) {
|
||||
return {
|
||||
type: "select",
|
||||
id: interaction.id,
|
||||
channelId: interaction.channelId,
|
||||
customId: interaction.customId,
|
||||
values: interaction.values,
|
||||
update: async (options) => {
|
||||
await interaction.update(getDiscordMessageOptions(options))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
raise(`Unsupported component interaction type: ${interaction.type}`)
|
||||
}
|
||||
|
||||
// TODO: this could be a part of the core library,
|
||||
// and also handle some edge cases, e.g. empty messages
|
||||
function getDiscordMessageOptions(
|
||||
options: MessageOptions,
|
||||
): Discord.MessageOptions {
|
||||
return {
|
||||
// eslint-disable-next-line unicorn/no-null
|
||||
content: options.content || null,
|
||||
embeds: options.embeds,
|
||||
components: options.actionRows.map((row) => ({
|
||||
type: "ACTION_ROW",
|
||||
components: row.map(
|
||||
(component): Discord.MessageActionRowComponentOptions => {
|
||||
if (component.type === "button") {
|
||||
return {
|
||||
type: "BUTTON",
|
||||
customId: component.customId,
|
||||
label: component.label ?? "",
|
||||
style: toUpper(component.style ?? "secondary"),
|
||||
disabled: component.disabled,
|
||||
emoji: component.emoji,
|
||||
}
|
||||
}
|
||||
|
||||
if (component.type === "select") {
|
||||
return {
|
||||
...component,
|
||||
type: "SELECT_MENU",
|
||||
options: component.options.map((option) => ({
|
||||
...option,
|
||||
default: component.values?.includes(option.value),
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
raise(`Unsupported component type: ${component.type}`)
|
||||
},
|
||||
),
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
function createReacordMessage(message: Discord.Message): Message {
|
||||
return {
|
||||
edit: async (options) => {
|
||||
await message.edit(getDiscordMessageOptions(options))
|
||||
},
|
||||
disableComponents: async () => {
|
||||
for (const actionRow of message.components) {
|
||||
for (const component of actionRow.components) {
|
||||
component.setDisabled(true)
|
||||
}
|
||||
}
|
||||
|
||||
await message.edit({
|
||||
components: message.components,
|
||||
})
|
||||
},
|
||||
delete: async () => {
|
||||
await message.delete()
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user