3
0
Fork 0
mirror of https://github.com/ZeppelinBot/Zeppelin.git synced 2025-03-18 15:00:00 +00:00

more fixes

Signed-off-by: GitHub <noreply@github.com>
This commit is contained in:
metal 2023-03-11 12:12:48 +00:00 committed by GitHub
parent 343a91e3c3
commit c33a216857
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 81 additions and 58 deletions

View file

@ -56,7 +56,7 @@ export function initDocs(app: express.Express) {
const name = plugin.name; const name = plugin.name;
const info = plugin.info || {}; const info = plugin.info || {};
const commands = (plugin.commands || []).map((cmd) => ({ const commands = (plugin.messageCommands || []).map((cmd) => ({
trigger: cmd.trigger, trigger: cmd.trigger,
permission: cmd.permission, permission: cmd.permission,
signature: cmd.signature, signature: cmd.signature,

View file

@ -1,5 +1,18 @@
import { GuildChannel, GuildMember, Snowflake, Util, User, GuildTextBasedChannel } from "discord.js"; import {
import { baseCommandParameterTypeHelpers, baseTypeConverters, CommandContext, TypeConversionError } from "knub"; GuildChannel,
GuildMember,
Snowflake,
User,
GuildTextBasedChannel,
escapeCodeBlock,
escapeInlineCode,
} from "discord.js";
import {
baseCommandParameterTypeHelpers,
messageCommandBaseTypeConverters,
CommandContext,
TypeConversionError,
} from "knub";
import { createTypeHelper } from "knub-command-manager"; import { createTypeHelper } from "knub-command-manager";
import { import {
channelMentionRegex, channelMentionRegex,
@ -14,11 +27,9 @@ import {
import { isValidTimezone } from "./utils/isValidTimezone"; import { isValidTimezone } from "./utils/isValidTimezone";
import { MessageTarget, resolveMessageTarget } from "./utils/resolveMessageTarget"; import { MessageTarget, resolveMessageTarget } from "./utils/resolveMessageTarget";
import { inputPatternToRegExp } from "./validatorUtils"; import { inputPatternToRegExp } from "./validatorUtils";
import { getChannelId } from "knub/dist/utils";
import { disableCodeBlocks } from "knub/dist/helpers";
export const commandTypes = { export const commandTypes = {
...baseTypeConverters, ...messageCommandBaseTypeConverters,
delay(value) { delay(value) {
const result = convertDelayStringToMS(value); const result = convertDelayStringToMS(value);
@ -32,7 +43,7 @@ export const commandTypes = {
async resolvedUser(value, context: CommandContext<any>) { async resolvedUser(value, context: CommandContext<any>) {
const result = await resolveUser(context.pluginData.client, value); const result = await resolveUser(context.pluginData.client, value);
if (result == null || result instanceof UnknownUser) { if (result == null || result instanceof UnknownUser) {
throw new TypeConversionError(`User \`${Util.escapeCodeBlock(value)}\` was not found`); throw new TypeConversionError(`User \`${escapeCodeBlock(value)}\` was not found`);
} }
return result; return result;
}, },
@ -40,7 +51,7 @@ export const commandTypes = {
async resolvedUserLoose(value, context: CommandContext<any>) { async resolvedUserLoose(value, context: CommandContext<any>) {
const result = await resolveUser(context.pluginData.client, value); const result = await resolveUser(context.pluginData.client, value);
if (result == null) { if (result == null) {
throw new TypeConversionError(`Invalid user: \`${Util.escapeCodeBlock(value)}\``); throw new TypeConversionError(`Invalid user: \`${escapeCodeBlock(value)}\``);
} }
return result; return result;
}, },
@ -52,9 +63,7 @@ export const commandTypes = {
const result = await resolveMember(context.pluginData.client, context.message.channel.guild, value); const result = await resolveMember(context.pluginData.client, context.message.channel.guild, value);
if (result == null) { if (result == null) {
throw new TypeConversionError( throw new TypeConversionError(`Member \`${escapeCodeBlock(value)}\` was not found or they have left the server`);
`Member \`${Util.escapeCodeBlock(value)}\` was not found or they have left the server`,
);
} }
return result; return result;
}, },
@ -64,7 +73,7 @@ export const commandTypes = {
const result = await resolveMessageTarget(context.pluginData, value); const result = await resolveMessageTarget(context.pluginData, value);
if (!result) { if (!result) {
throw new TypeConversionError(`Unknown message \`${Util.escapeInlineCode(value)}\``); throw new TypeConversionError(`Unknown message \`${escapeInlineCode(value)}\``);
} }
return result; return result;
@ -84,20 +93,20 @@ export const commandTypes = {
return value as Snowflake; return value as Snowflake;
} }
throw new TypeConversionError(`Could not parse ID: \`${Util.escapeInlineCode(value)}\``); throw new TypeConversionError(`Could not parse ID: \`${escapeInlineCode(value)}\``);
}, },
regex(value: string, context: CommandContext<any>): RegExp { regex(value: string, context: CommandContext<any>): RegExp {
try { try {
return inputPatternToRegExp(value); return inputPatternToRegExp(value);
} catch (e) { } catch (e) {
throw new TypeConversionError(`Could not parse RegExp: \`${Util.escapeInlineCode(e.message)}\``); throw new TypeConversionError(`Could not parse RegExp: \`${escapeInlineCode(e.message)}\``);
} }
}, },
timezone(value: string) { timezone(value: string) {
if (!isValidTimezone(value)) { if (!isValidTimezone(value)) {
throw new TypeConversionError(`Invalid timezone: ${Util.escapeInlineCode(value)}`); throw new TypeConversionError(`Invalid timezone: ${escapeInlineCode(value)}`);
} }
return value; return value;
@ -105,7 +114,7 @@ export const commandTypes = {
guildTextBasedChannel(value: string, context: CommandContext<any>) { guildTextBasedChannel(value: string, context: CommandContext<any>) {
// FIXME: Remove once Knub's types have been fixed // FIXME: Remove once Knub's types have been fixed
return baseTypeConverters.textChannel(value, context) as GuildTextBasedChannel; return messageCommandBaseTypeConverters.textChannel(value, context) as GuildTextBasedChannel;
}, },
}; };

View file

@ -53,13 +53,13 @@ export class GuildSavedMessages extends BaseGuildRepository<SavedMessage> {
title: embed.title, title: embed.title,
description: embed.description, description: embed.description,
url: embed.url, url: embed.url,
timestamp: embed.timestamp, timestamp: embed.timestamp ? Date.parse(embed.timestamp) : null,
color: embed.color, color: embed.color,
fields: embed.fields.map((field) => ({ fields: embed.fields.map((field) => ({
name: field.name, name: field.name,
value: field.value, value: field.value,
inline: field.inline, inline: field.inline ?? false,
})), })),
author: embed.author author: embed.author

View file

@ -1,4 +1,4 @@
import { Snowflake } from "discord.js"; import { Snowflake, StickerFormatType, StickerType } from "discord.js";
import { Column, Entity, PrimaryColumn } from "typeorm"; import { Column, Entity, PrimaryColumn } from "typeorm";
export interface ISavedMessageAttachmentData { export interface ISavedMessageAttachmentData {
@ -55,13 +55,13 @@ export interface ISavedMessageEmbedData {
} }
export interface ISavedMessageStickerData { export interface ISavedMessageStickerData {
format: string; format: StickerFormatType;
guildId: Snowflake | null; guildId: Snowflake | null;
id: Snowflake; id: Snowflake;
name: string; name: string;
description: string | null; description: string | null;
available: boolean | null; available: boolean | null;
type: string | null; type: StickerType | null;
} }
export interface ISavedMessageData { export interface ISavedMessageData {

View file

@ -38,7 +38,7 @@ export const AlertAction = automodAction({
const channel = pluginData.guild.channels.cache.get(actionConfig.channel as Snowflake); const channel = pluginData.guild.channels.cache.get(actionConfig.channel as Snowflake);
const logs = pluginData.getPlugin(LogsPlugin); const logs = pluginData.getPlugin(LogsPlugin);
if (channel?.isText()) { if (channel?.isTextBased()) {
const text = actionConfig.text; const text = actionConfig.text;
const theMessageLink = const theMessageLink =
contexts[0].message && messageLink(pluginData.guild.id, contexts[0].message.channel_id, contexts[0].message.id); contexts[0].message && messageLink(pluginData.guild.id, contexts[0].message.channel_id, contexts[0].message.id);

View file

@ -36,7 +36,7 @@ export const ReplyAction = automodAction({
.filter((c) => c.message?.channel_id) .filter((c) => c.message?.channel_id)
.filter((c) => { .filter((c) => {
const channel = pluginData.guild.channels.cache.get(c.message!.channel_id as Snowflake); const channel = pluginData.guild.channels.cache.get(c.message!.channel_id as Snowflake);
return channel?.isText(); return channel?.isTextBased();
}); });
const contextsByChannelId = contextsWithTextChannels.reduce((map: Map<string, AutomodContext[]>, context) => { const contextsByChannelId = contextsWithTextChannels.reduce((map: Map<string, AutomodContext[]>, context) => {

View file

@ -32,7 +32,7 @@ export const StartThreadAction = automodAction({
const threads = contexts.filter((c) => { const threads = contexts.filter((c) => {
if (!c.message || !c.user) return false; if (!c.message || !c.user) return false;
const channel = pluginData.guild.channels.cache.get(c.message.channel_id); const channel = pluginData.guild.channels.cache.get(c.message.channel_id);
if (channel?.type !== ChannelTypeStrings.TEXT || !channel.isText()) return false; // for some reason the typing here for channel.type defaults to ThreadChannelTypes (?) if (channel?.type !== ChannelTypeStrings.TEXT || !channel.isTextBased()) return false; // for some reason the typing here for channel.type defaults to ThreadChannelTypes (?)
// check against max threads per channel // check against max threads per channel
if (actionConfig.limit_per_channel && actionConfig.limit_per_channel > 0) { if (actionConfig.limit_per_channel && actionConfig.limit_per_channel > 0) {
const threadCount = channel.threads.cache.filter( const threadCount = channel.threads.cache.filter(

View file

@ -19,7 +19,7 @@ export function resolveActionContactMethods(
} }
const channel = pluginData.guild.channels.cache.get(actionConfig.notifyChannel as Snowflake); const channel = pluginData.guild.channels.cache.get(actionConfig.notifyChannel as Snowflake);
if (!channel?.isText()) { if (!channel?.isTextBased()) {
throw new RecoverablePluginError(ERRORS.INVALID_USER_NOTIFICATION_CHANNEL); throw new RecoverablePluginError(ERRORS.INVALID_USER_NOTIFICATION_CHANNEL);
} }

View file

@ -68,7 +68,7 @@ export const ViewCounterCmd = guildPluginMessageCommand<CountersPluginType>()({
} }
const potentialChannel = pluginData.guild.channels.resolve(reply.content as Snowflake); const potentialChannel = pluginData.guild.channels.resolve(reply.content as Snowflake);
if (!potentialChannel?.isText()) { if (!potentialChannel?.isTextBased()) {
sendErrorMessage(pluginData, message.channel, "Channel is not a text channel, cancelling"); sendErrorMessage(pluginData, message.channel, "Channel is not a text channel, cancelling");
return; return;
} }

View file

@ -88,7 +88,7 @@ export async function log<TLogType extends keyof ILogTypeData>(
logChannelLoop: for (const [channelId, opts] of Object.entries(logChannels)) { logChannelLoop: for (const [channelId, opts] of Object.entries(logChannels)) {
const channel = pluginData.guild.channels.cache.get(channelId as Snowflake); const channel = pluginData.guild.channels.cache.get(channelId as Snowflake);
if (!channel?.isText()) continue; if (!channel?.isTextBased()) continue;
if (pluginData.state.channelCooldowns.isOnCooldown(channelId)) continue; if (pluginData.state.channelCooldowns.isOnCooldown(channelId)) continue;
if (opts.include?.length && !opts.include.includes(typeStr)) continue; if (opts.include?.length && !opts.include.includes(typeStr)) continue;
if (opts.exclude && opts.exclude.includes(typeStr)) continue; if (opts.exclude && opts.exclude.includes(typeStr)) continue;

View file

@ -186,7 +186,7 @@ export async function muteUser(
const channel = config.message_channel const channel = config.message_channel
? pluginData.guild.channels.cache.get(config.message_channel as Snowflake) ? pluginData.guild.channels.cache.get(config.message_channel as Snowflake)
: null; : null;
if (useChannel && channel?.isText()) { if (useChannel && channel?.isTextBased()) {
contactMethods.push({ type: "channel", channel }); contactMethods.push({ type: "channel", channel });
} }
} }

View file

@ -30,7 +30,7 @@ export async function actualPostCmd(
"repeat-times"?: number; "repeat-times"?: number;
} = {}, } = {},
) { ) {
if (!targetChannel.isText()) { if (!targetChannel.isTextBased()) {
msg.channel.send(errorMessage("Specified channel is not a text-based channel")); msg.channel.send(errorMessage("Specified channel is not a text-based channel"));
return; return;
} }

View file

@ -45,7 +45,7 @@ export async function postScheduledPost(pluginData: GuildPluginData<PostPluginTy
// Post the message // Post the message
const channel = pluginData.guild.channels.cache.get(post.channel_id as Snowflake); const channel = pluginData.guild.channels.cache.get(post.channel_id as Snowflake);
if (channel?.isText() || channel?.isThread()) { if (channel?.isTextBased() || channel?.isThread()) {
const [username, discriminator] = post.author_name.split("#"); const [username, discriminator] = post.author_name.split("#");
const author: User = (await pluginData.client.users.fetch(post.author_id as Snowflake)) || { const author: User = (await pluginData.client.users.fetch(post.author_id as Snowflake)) || {
id: post.author_id, id: post.author_id,

View file

@ -9,7 +9,7 @@ import humanizeDuration from "humanize-duration";
export async function postReminder(pluginData: GuildPluginData<RemindersPluginType>, reminder: Reminder) { export async function postReminder(pluginData: GuildPluginData<RemindersPluginType>, reminder: Reminder) {
const channel = pluginData.guild.channels.cache.get(reminder.channel_id as Snowflake); const channel = pluginData.guild.channels.cache.get(reminder.channel_id as Snowflake);
if (channel && (channel.isText() || channel.isThread())) { if (channel && (channel.isTextBased() || channel.isThread())) {
try { try {
// Only show created at date if one exists // Only show created at date if one exists
if (moment.utc(reminder.created_at).isValid()) { if (moment.utc(reminder.created_at).isValid()) {

View file

@ -19,7 +19,7 @@ export async function applyRoleButtons(
// Remove existing role buttons, if any // Remove existing role buttons, if any
if (existingSavedButtons?.channel_id) { if (existingSavedButtons?.channel_id) {
const existingChannel = await pluginData.guild.channels.fetch(configItem.message.channel_id).catch(() => null); const existingChannel = await pluginData.guild.channels.fetch(configItem.message.channel_id).catch(() => null);
const existingMessage = await (existingChannel?.isText() && const existingMessage = await (existingChannel?.isTextBased() &&
existingChannel.messages.fetch(existingSavedButtons.message_id).catch(() => null)); existingChannel.messages.fetch(existingSavedButtons.message_id).catch(() => null));
if (existingMessage && existingMessage.components.length) { if (existingMessage && existingMessage.components.length) {
await existingMessage.edit({ await existingMessage.edit({
@ -32,7 +32,7 @@ export async function applyRoleButtons(
if ("message_id" in configItem.message) { if ("message_id" in configItem.message) {
// channel id + message id: apply role buttons to existing message // channel id + message id: apply role buttons to existing message
const channel = await pluginData.guild.channels.fetch(configItem.message.channel_id).catch(() => null); const channel = await pluginData.guild.channels.fetch(configItem.message.channel_id).catch(() => null);
const messageCandidate = await (channel?.isText() && const messageCandidate = await (channel?.isTextBased() &&
channel.messages.fetch(configItem.message.message_id).catch(() => null)); channel.messages.fetch(configItem.message.message_id).catch(() => null));
if (!messageCandidate) { if (!messageCandidate) {
pluginData.getPlugin(LogsPlugin).logBotAlert({ pluginData.getPlugin(LogsPlugin).logBotAlert({
@ -55,10 +55,10 @@ export async function applyRoleButtons(
} }
const channel = await pluginData.guild.channels.fetch(configItem.message.channel_id).catch(() => null); const channel = await pluginData.guild.channels.fetch(configItem.message.channel_id).catch(() => null);
if (channel && (!channel.isText || typeof channel.isText !== "function")) { if (channel && (!channel.isTextBased || typeof channel.isTextBased !== "function")) {
console.log("wtf", pluginData.guild?.id, configItem.message.channel_id); console.log("wtf", pluginData.guild?.id, configItem.message.channel_id);
} }
if (!channel || !channel?.isText?.()) { if (!channel || !channel?.isTextBased()) {
pluginData.getPlugin(LogsPlugin).logBotAlert({ pluginData.getPlugin(LogsPlugin).logBotAlert({
body: `Text channel not found for role_buttons/${configItem.name}`, body: `Text channel not found for role_buttons/${configItem.name}`,
}); });

View file

@ -1,3 +1,4 @@
import { ChannelType } from "discord.js";
import { GuildPluginData } from "knub"; import { GuildPluginData } from "knub";
import { StarboardMessage } from "../../../data/entities/StarboardMessage"; import { StarboardMessage } from "../../../data/entities/StarboardMessage";
import { noop } from "../../../utils"; import { noop } from "../../../utils";
@ -12,7 +13,7 @@ export async function removeMessageFromStarboard(
// this code is now Almeida-certified and no longer ugly :ok_hand: :cake: // this code is now Almeida-certified and no longer ugly :ok_hand: :cake:
const channel = pluginData.client.channels.cache.find((c) => c.id === msg.starboard_channel_id); const channel = pluginData.client.channels.cache.find((c) => c.id === msg.starboard_channel_id);
if (!channel?.isText()) return; if (channel?.type !== ChannelType.GuildText) return;
const message = await channel.messages.fetch(msg.starboard_message_id).catch(noop); const message = await channel.messages.fetch(msg.starboard_message_id).catch(noop);
if (!message?.deletable) return; if (!message?.deletable) return;
await message.delete().catch(noop); await message.delete().catch(noop);

View file

@ -81,7 +81,7 @@ export async function cleanCmd(pluginData: GuildPluginData<UtilityPluginType>, a
} }
const targetChannel = args.channel ? pluginData.guild.channels.cache.get(args.channel as Snowflake) : msg.channel; const targetChannel = args.channel ? pluginData.guild.channels.cache.get(args.channel as Snowflake) : msg.channel;
if (!targetChannel?.isText()) { if (!targetChannel?.isTextBased()) {
sendErrorMessage(pluginData, msg.channel, `Invalid channel specified`); sendErrorMessage(pluginData, msg.channel, `Invalid channel specified`);
return; return;
} }

View file

@ -1,4 +1,4 @@
import { MessageEmbedOptions, Role } from "discord.js"; import { MessageEmbedOptions } from "discord.js";
import humanizeDuration from "humanize-duration"; import humanizeDuration from "humanize-duration";
import { GuildPluginData } from "knub"; import { GuildPluginData } from "knub";
import moment from "moment-timezone"; import moment from "moment-timezone";

View file

@ -1,7 +1,7 @@
import * as t from "io-ts"; import * as t from "io-ts";
import { BaseConfig, Knub } from "knub"; import { BaseConfig, Knub } from "knub";
export interface ZeppelinGuildConfig extends BaseConfig<any> { export interface ZeppelinGuildConfig extends BaseConfig {
success_emoji?: string; success_emoji?: string;
error_emoji?: string; error_emoji?: string;
@ -26,7 +26,7 @@ export const ZeppelinGuildConfigSchema = t.type({
}); });
export const PartialZeppelinGuildConfigSchema = t.partial(ZeppelinGuildConfigSchema.props); export const PartialZeppelinGuildConfigSchema = t.partial(ZeppelinGuildConfigSchema.props);
export interface ZeppelinGlobalConfig extends BaseConfig<any> { export interface ZeppelinGlobalConfig extends BaseConfig {
url: string; url: string;
owners?: string[]; owners?: string[];
} }
@ -37,7 +37,7 @@ export const ZeppelinGlobalConfigSchema = t.type({
plugins: t.record(t.string, t.unknown), plugins: t.record(t.string, t.unknown),
}); });
export type TZeppelinKnub = Knub<ZeppelinGuildConfig, ZeppelinGlobalConfig>; export type TZeppelinKnub = Knub;
/** /**
* Wrapper for the string type that indicates the text will be parsed as Markdown later * Wrapper for the string type that indicates the text will be parsed as Markdown later

View file

@ -1,10 +1,10 @@
import { Channel, ThreadChannel } from "discord.js"; import { AnyThreadChannel, Channel, ChannelType } from "discord.js";
import { ChannelTypeStrings } from "src/types"; import { ChannelTypeStrings } from "src/types";
export function isThreadChannel(channel: Channel): channel is ThreadChannel { export function isThreadChannel(channel: Channel): channel is AnyThreadChannel {
return ( return (
channel.type === ChannelTypeStrings.NEWS_THREAD || channel.type === ChannelType.PublicThread ||
channel.type === ChannelTypeStrings.PUBLIC_THREAD || channel.type === ChannelType.PrivateThread ||
channel.type === ChannelTypeStrings.PRIVATE_THREAD channel.type === ChannelType.AnnouncementThread
); );
} }

View file

@ -47,7 +47,7 @@ export async function resolveMessageTarget(pluginData: GuildPluginData<any>, val
} }
const channel = pluginData.guild.channels.resolve(result.channelId as Snowflake); const channel = pluginData.guild.channels.resolve(result.channelId as Snowflake);
if (!channel?.isText()) { if (!channel?.isTextBased()) {
return null; return null;
} }

View file

@ -9,6 +9,7 @@ import {
Snowflake, Snowflake,
StageInstance, StageInstance,
Sticker, Sticker,
StickerFormatType,
ThreadChannel, ThreadChannel,
User, User,
} from "discord.js"; } from "discord.js";
@ -239,7 +240,7 @@ export function userToTemplateSafeUser(user: User | UnknownUser): TemplateSafeUs
discriminator: user.discriminator, discriminator: user.discriminator,
mention: `<@${user.id}>`, mention: `<@${user.id}>`,
tag: user.tag, tag: user.tag,
avatarURL: user.displayAvatarURL?.({ dynamic: true }), avatarURL: user.displayAvatarURL?.(),
bot: user.bot, bot: user.bot,
createdAt: user.createdTimestamp, createdAt: user.createdTimestamp,
}); });
@ -305,9 +306,9 @@ export function stickerToTemplateSafeSticker(sticker: Sticker): TemplateSafeStic
packId: sticker.packId ?? undefined, packId: sticker.packId ?? undefined,
name: sticker.name, name: sticker.name,
description: sticker.description ?? "", description: sticker.description ?? "",
tags: sticker.tags?.join(", ") ?? "", tags: sticker.tags ?? "",
format: sticker.format, format: sticker.format,
animated: sticker.format === "PNG" ? false : true, animated: sticker.format === StickerFormatType.PNG ? false : true,
url: sticker.url, url: sticker.url,
}); });
} }

View file

@ -1,23 +1,35 @@
import { MessageActionRow, MessageButton, MessageComponentInteraction, MessageOptions, TextChannel } from "discord.js"; import {
ActionRow,
ActionRowBuilder,
ButtonBuilder,
ButtonComponent,
ButtonStyle,
Message,
MessageActionRowComponentBuilder,
MessageComponentInteraction,
MessageCreateOptions,
MessagePayloadOption,
TextChannel,
} from "discord.js";
import { noop } from "knub/dist/utils"; import { noop } from "knub/dist/utils";
import moment from "moment"; import moment from "moment";
import uuidv4 from "uuid/v4"; import uuidv4 from "uuid/v4";
export async function waitForButtonConfirm( export async function waitForButtonConfirm(
channel: TextChannel, channel: TextChannel,
toPost: MessageOptions, toPost: MessageCreateOptions,
options?: WaitForOptions, options?: WaitForOptions,
): Promise<boolean> { ): Promise<boolean> {
return new Promise(async (resolve) => { return new Promise(async (resolve) => {
const idMod = `${channel.guild.id}-${moment.utc().valueOf()}`; const idMod = `${channel.guild.id}-${moment.utc().valueOf()}`;
const row = new MessageActionRow().addComponents([ const row = new ActionRowBuilder<MessageActionRowComponentBuilder>().addComponents([
new MessageButton() new ButtonBuilder()
.setStyle("SUCCESS") .setStyle(ButtonStyle.Success)
.setLabel(options?.confirmText || "Confirm") .setLabel(options?.confirmText || "Confirm")
.setCustomId(`confirmButton:${idMod}:${uuidv4()}`), .setCustomId(`confirmButton:${idMod}:${uuidv4()}`),
new MessageButton() new ButtonBuilder()
.setStyle("DANGER") .setStyle(ButtonStyle.Danger)
.setLabel(options?.cancelText || "Cancel") .setLabel(options?.cancelText || "Cancel")
.setCustomId(`cancelButton:${idMod}:${uuidv4()}`), .setCustomId(`cancelButton:${idMod}:${uuidv4()}`),
]); ]);
@ -41,7 +53,7 @@ export async function waitForButtonConfirm(
} }
}); });
collector.on("end", () => { collector.on("end", () => {
if (!message.deleted) message.delete().catch(noop); if (message.deletable) message.delete().catch(noop);
resolve(false); resolve(false);
}); });
}); });