This commit is contained in:
Skillz4Killz
2022-02-21 05:17:13 +00:00
committed by GitHub
121 changed files with 2478 additions and 189 deletions

View File

@@ -22,11 +22,11 @@ export async function createChannel(bot: Bot, guildId: bigint, options?: CreateG
position: options.position,
parent_id: options.parentId?.toString(),
nsfw: options.nsfw,
permission_overwrites: options?.permissionOverwrites?.map((perm) => ({
id: perm.id.toString(),
type: perm.type,
allow: perm.allow ? bot.utils.calculateBits(perm.allow) : "0",
deny: perm.deny ? bot.utils.calculateBits(perm.deny) : "0",
permission_overwrites: options?.permissionOverwrites?.map((overwrite) => ({
id: overwrite.id.toString(),
type: overwrite.type,
allow: overwrite.allow ? bot.utils.calculateBits(overwrite.allow) : null,
deny: overwrite.deny ? bot.utils.calculateBits(overwrite.deny) : null,
})),
type: options?.type || ChannelTypes.GuildText,
reason,

View File

@@ -46,13 +46,12 @@ export async function editChannel(bot: Bot, channelId: bigint, options: ModifyCh
locked: options.locked,
invitable: options.invitable,
permission_overwrites: options.permissionOverwrites
? options.permissionOverwrites?.map((overwrite) => {
return {
...overwrite,
allow: overwrite.allow ? bot.utils.calculateBits(overwrite.allow) : "0",
deny: overwrite.deny ? bot.utils.calculateBits(overwrite.deny) : "0",
};
})
? options.permissionOverwrites?.map((overwrite) => ({
id: overwrite.id.toString(),
type: overwrite.type,
allow: overwrite.allow ? bot.utils.calculateBits(overwrite.allow) : null,
deny: overwrite.deny ? bot.utils.calculateBits(overwrite.deny) : null,
}))
: undefined,
reason,
});

View File

@@ -4,7 +4,7 @@ import { requireBotGuildPermissions } from "../permissions.ts";
export default function deleteChannel(bot: BotWithCache) {
const deleteChannelOld = bot.helpers.deleteChannel;
bot.helpers.deleteChannel = function (channelId, reason) {
bot.helpers.deleteChannel = async function (channelId, reason) {
const channel = bot.channels.get(channelId);
if (channel?.guildId) {
@@ -32,6 +32,6 @@ export default function deleteChannel(bot: BotWithCache) {
);
}
return deleteChannelOld(channelId, reason);
return await deleteChannelOld(channelId, reason);
};
}

View File

@@ -4,13 +4,13 @@ import { requireBotChannelPermissions } from "../permissions.ts";
export default function deleteChannelOverwrite(bot: BotWithCache) {
const deleteChannelOverwriteOld = bot.helpers.deleteChannelOverwrite;
bot.helpers.deleteChannelOverwrite = function (channelId, overwriteId) {
bot.helpers.deleteChannelOverwrite = async function (channelId, overwriteId) {
const channel = bot.channels.get(channelId);
if (channel?.guildId) {
requireBotChannelPermissions(bot, channelId, ["MANAGE_ROLES"]);
}
return deleteChannelOverwriteOld(channelId, overwriteId);
return await deleteChannelOverwriteOld(channelId, overwriteId);
};
}

View File

@@ -5,7 +5,7 @@ import { requireBotChannelPermissions } from "../permissions.ts";
export default function editChannel(bot: BotWithCache) {
const editChannelOld = bot.helpers.editChannel;
bot.helpers.editChannel = function (channelId, options, reason) {
bot.helpers.editChannel = async function (channelId, options, reason) {
const channel = bot.channels.get(channelId);
if (channel?.guildId) {
@@ -118,6 +118,6 @@ export default function editChannel(bot: BotWithCache) {
}
}
return editChannelOld(channelId, options, reason);
return await editChannelOld(channelId, options, reason);
};
}

View File

@@ -4,12 +4,12 @@ import { requireBotChannelPermissions } from "../permissions.ts";
export default function editChannelOverwrite(bot: BotWithCache) {
const editChannelOverwriteOld = bot.helpers.editChannelOverwrite;
bot.helpers.editChannelOverwrite = function (channelId, overwriteId, options) {
bot.helpers.editChannelOverwrite = async function (channelId, overwriteId, options) {
const channel = bot.channels.get(channelId);
if (channel?.guildId) {
requireBotChannelPermissions(bot, channelId, ["MANAGE_ROLES"]);
}
return editChannelOverwriteOld(channelId, overwriteId, options);
return await editChannelOverwriteOld(channelId, overwriteId, options);
};
}

View File

@@ -4,12 +4,12 @@ import { requireBotChannelPermissions } from "../permissions.ts";
export default function followChannel(bot: BotWithCache) {
const followChannelOld = bot.helpers.followChannel;
bot.helpers.followChannel = function (sourceChannelId, targetChannelId) {
bot.helpers.followChannel = async function (sourceChannelId, targetChannelId) {
const channel = bot.channels.get(targetChannelId);
if (channel?.guildId) {
requireBotChannelPermissions(bot, channel, ["MANAGE_WEBHOOKS"]);
}
return followChannelOld(sourceChannelId, targetChannelId);
return await followChannelOld(sourceChannelId, targetChannelId);
};
}

View File

@@ -4,12 +4,12 @@ import { requireBotChannelPermissions } from "../permissions.ts";
export default function getChannelWebhooks(bot: BotWithCache) {
const getChannelWebhooksOld = bot.helpers.getChannelWebhooks;
bot.helpers.getChannelWebhooks = function (channelId) {
bot.helpers.getChannelWebhooks = async function (channelId) {
const channel = bot.channels.get(channelId);
if (channel?.guildId) {
requireBotChannelPermissions(bot, channelId, ["MANAGE_WEBHOOKS"]);
}
return getChannelWebhooksOld(channelId);
return await getChannelWebhooksOld(channelId);
};
}

View File

@@ -4,7 +4,7 @@ import { requireBotChannelPermissions } from "../permissions.ts";
export function createStageInstance(bot: BotWithCache) {
const createStageInstanceOld = bot.helpers.createStageInstance;
bot.helpers.createStageInstance = function (channelId, topic, privacyLevel) {
bot.helpers.createStageInstance = async function (channelId, topic, privacyLevel) {
if (!bot.utils.validateLength(topic, { max: 120, min: 1 })) {
throw new Error(
"The topic length for creating a stage instance must be between 1-120.",
@@ -17,35 +17,35 @@ export function createStageInstance(bot: BotWithCache) {
"MOVE_MEMBERS",
]);
return createStageInstanceOld(channelId, topic, privacyLevel);
return await createStageInstanceOld(channelId, topic, privacyLevel);
};
}
export function deleteStageInstance(bot: BotWithCache) {
const deleteStageInstanceOld = bot.helpers.deleteStageInstance;
bot.helpers.deleteStageInstance = function (channelId) {
bot.helpers.deleteStageInstance = async function (channelId) {
requireBotChannelPermissions(bot, channelId, [
"MANAGE_CHANNELS",
"MUTE_MEMBERS",
"MOVE_MEMBERS",
]);
return deleteStageInstanceOld(channelId);
return await deleteStageInstanceOld(channelId);
};
}
export function updateStageInstance(bot: BotWithCache) {
const updateStageInstanceOld = bot.helpers.updateStageInstance;
bot.helpers.updateStageInstance = function (channelId, data) {
bot.helpers.updateStageInstance = async function (channelId, data) {
requireBotChannelPermissions(bot, channelId, [
"MANAGE_CHANNELS",
"MUTE_MEMBERS",
"MOVE_MEMBERS",
]);
return updateStageInstanceOld(channelId, data);
return await updateStageInstanceOld(channelId, data);
};
}

View File

@@ -4,9 +4,9 @@ import { requireBotGuildPermissions } from "../permissions.ts";
export default function swapChannels(bot: BotWithCache) {
const swapChannelsOld = bot.helpers.swapChannels;
bot.helpers.swapChannels = function (guildId, channelPositions) {
bot.helpers.swapChannels = async function (guildId, channelPositions) {
requireBotGuildPermissions(bot, guildId, ["MANAGE_CHANNELS"]);
return swapChannelsOld(guildId, channelPositions);
return await swapChannelsOld(guildId, channelPositions);
};
}

View File

@@ -21,6 +21,6 @@ export default function addToThread(bot: BotWithCache) {
await requireBotChannelPermissions(bot, channel, ["SEND_MESSAGES"]);
}
return addToThreadOld(threadId, userId);
return await addToThreadOld(threadId, userId);
};
}

View File

@@ -15,6 +15,6 @@ export default function getArchivedThreads(bot: BotWithCache) {
);
}
return getArchivedThreadsOld(channelId, options);
return await getArchivedThreadsOld(channelId, options);
};
}

View File

@@ -3,7 +3,7 @@ import { BotWithCache, GatewayIntents } from "../../../deps.ts";
export default function getThreadMembers(bot: BotWithCache) {
const getThreadMembersOld = bot.helpers.getThreadMembers;
bot.helpers.getThreadMembers = function (threadId) {
bot.helpers.getThreadMembers = async function (threadId) {
const hasIntent = bot.intents & GatewayIntents.GuildMembers;
if (!hasIntent) {
throw new Error(
@@ -11,6 +11,6 @@ export default function getThreadMembers(bot: BotWithCache) {
);
}
return getThreadMembersOld(threadId);
return await getThreadMembersOld(threadId);
};
}

View File

@@ -3,13 +3,13 @@ import { BotWithCache } from "../../../deps.ts";
export default function joinThread(bot: BotWithCache) {
const joinThreadOld = bot.helpers.joinThread;
bot.helpers.joinThread = function (threadId) {
bot.helpers.joinThread = async function (threadId) {
const channel = bot.channels.get(threadId);
if (channel && !channel.archived) {
throw new Error("You can not join an archived channel.");
}
return joinThreadOld(threadId);
return await joinThreadOld(threadId);
};
}

View File

@@ -3,13 +3,13 @@ import { BotWithCache } from "../../../deps.ts";
export default function leaveThread(bot: BotWithCache) {
const leaveThreadOld = bot.helpers.leaveThread;
bot.helpers.leaveThread = function (threadId) {
bot.helpers.leaveThread = async function (threadId) {
const channel = bot.channels.get(threadId);
if (channel && !channel.archived) {
throw new Error("You can not leave an archived channel.");
}
return leaveThreadOld(threadId);
return await leaveThreadOld(threadId);
};
}

View File

@@ -28,6 +28,6 @@ export default function removeThreadMember(bot: BotWithCache) {
}
}
return removeThreadMemberOld(threadId, userId);
return await removeThreadMemberOld(threadId, userId);
};
}

View File

@@ -40,6 +40,6 @@ export default function connectToVoiceChannel(bot: BotWithCache) {
await requireBotChannelPermissions(bot, channel, permsNeeded);
return connectToVoiceChannelOld(guildId, channelId, options);
return await connectToVoiceChannelOld(guildId, channelId, options);
};
}

View File

@@ -4,40 +4,40 @@ import { requireBotGuildPermissions } from "./permissions.ts";
export function addDiscoverySubcategory(bot: BotWithCache) {
const addDiscoverySubcategoryOld = bot.helpers.addDiscoverySubcategory;
bot.helpers.addDiscoverySubcategory = function (guildId, categoryId) {
bot.helpers.addDiscoverySubcategory = async function (guildId, categoryId) {
requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
return addDiscoverySubcategoryOld(guildId, categoryId);
return await addDiscoverySubcategoryOld(guildId, categoryId);
};
}
export function removeDiscoverySubcategory(bot: BotWithCache) {
const removeDiscoverySubcategoryOld = bot.helpers.removeDiscoverySubcategory;
bot.helpers.removeDiscoverySubcategory = function (guildId, categoryId) {
bot.helpers.removeDiscoverySubcategory = async function (guildId, categoryId) {
requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
return removeDiscoverySubcategoryOld(guildId, categoryId);
return await removeDiscoverySubcategoryOld(guildId, categoryId);
};
}
export function getDiscovery(bot: BotWithCache) {
const getDiscoveryOld = bot.helpers.getDiscovery;
bot.helpers.getDiscovery = function (guildId) {
bot.helpers.getDiscovery = async function (guildId) {
requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
return getDiscoveryOld(guildId);
return await getDiscoveryOld(guildId);
};
}
export function editDiscovery(bot: BotWithCache) {
const editDiscoveryOld = bot.helpers.editDiscovery;
bot.helpers.editDiscovery = function (guildId, data) {
bot.helpers.editDiscovery = async function (guildId, data) {
requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
return editDiscoveryOld(guildId, data);
return await editDiscoveryOld(guildId, data);
};
}

View File

@@ -59,6 +59,6 @@ export default function editMember(bot: BotWithCache) {
...requiredPerms,
]);
return editMemberOld(guildId, memberId, options);
return await editMemberOld(guildId, memberId, options);
};
}

View File

@@ -4,30 +4,30 @@ import { requireBotGuildPermissions } from "./permissions.ts";
export function createEmoji(bot: BotWithCache) {
const createEmojiOld = bot.helpers.createEmoji;
bot.helpers.createEmoji = function (guildId, id) {
bot.helpers.createEmoji = async function (guildId, id) {
requireBotGuildPermissions(bot, guildId, ["MANAGE_EMOJIS"]);
return createEmojiOld(guildId, id);
return await createEmojiOld(guildId, id);
};
}
export function deleteEmoji(bot: BotWithCache) {
const deleteEmojiOld = bot.helpers.deleteEmoji;
bot.helpers.deleteEmoji = function (guildId, id) {
bot.helpers.deleteEmoji = async function (guildId, id) {
requireBotGuildPermissions(bot, guildId, ["MANAGE_EMOJIS"]);
return deleteEmojiOld(guildId, id);
return await deleteEmojiOld(guildId, id);
};
}
export function editEmoji(bot: BotWithCache) {
const editEmojiOld = bot.helpers.editEmoji;
bot.helpers.editEmoji = function (guildId, id, options) {
bot.helpers.editEmoji = async function (guildId, id, options) {
requireBotGuildPermissions(bot, guildId, ["MANAGE_EMOJIS"]);
return editEmojiOld(guildId, id, options);
return await editEmojiOld(guildId, id, options);
};
}

View File

@@ -3,7 +3,7 @@ import { BotWithCache } from "../../deps.ts";
export default function createGuild(bot: BotWithCache) {
const createGuildOld = bot.helpers.createGuild;
bot.helpers.createGuild = function (options) {
bot.helpers.createGuild = async function (options) {
if (bot.guilds.size > 10) {
throw new Error(
"A bot can not create a guild if it is already in 10 guilds.",
@@ -17,6 +17,6 @@ export default function createGuild(bot: BotWithCache) {
throw new Error("The guild name must be between 2 and 100 characters.");
}
return createGuildOld(options);
return await createGuildOld(options);
};
}

View File

@@ -3,12 +3,12 @@ import { BotWithCache } from "../../deps.ts";
export default function deleteGuild(bot: BotWithCache) {
const deleteGuildOld = bot.helpers.deleteGuild;
bot.helpers.deleteGuild = function (guildId) {
bot.helpers.deleteGuild = async function (guildId) {
const guild = bot.guilds.get(guildId);
if (guild && guild.ownerId !== bot.id) {
throw new Error("A bot can only delete a guild it owns.");
}
return deleteGuildOld(guildId);
return await deleteGuildOld(guildId);
};
}

View File

@@ -4,9 +4,9 @@ import { requireBotGuildPermissions } from "../permissions.ts";
export default function editGuild(bot: BotWithCache) {
const editGuildOld = bot.helpers.editGuild;
bot.helpers.editGuild = function (guildId, options, shardId) {
bot.helpers.editGuild = async function (guildId, options, shardId) {
requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
return editGuildOld(guildId, options, shardId);
return await editGuildOld(guildId, options, shardId);
};
}

View File

@@ -4,7 +4,7 @@ import { requireBotChannelPermissions, requireBotGuildPermissions } from "../per
export function createScheduledEvent(bot: BotWithCache) {
const createScheduledEventOld = bot.helpers.createScheduledEvent;
bot.helpers.createScheduledEvent = function (guildId, options) {
bot.helpers.createScheduledEvent = async function (guildId, options) {
if (options.entityType === ScheduledEventEntityType.StageInstance) {
if (!options.channelId) {
throw new Error(
@@ -64,14 +64,14 @@ export function createScheduledEvent(bot: BotWithCache) {
"MANAGE_EVENTS",
]);
return createScheduledEventOld(guildId, options);
return await createScheduledEventOld(guildId, options);
};
}
export function editScheduledEvent(bot: BotWithCache) {
const editScheduledEventOld = bot.helpers.editScheduledEvent;
bot.helpers.editScheduledEvent = function (guildId, eventId, options) {
bot.helpers.editScheduledEvent = async function (guildId, eventId, options) {
if (options.entityType === ScheduledEventEntityType.StageInstance) {
if (!options.channelId) {
throw new Error(
@@ -131,7 +131,7 @@ export function editScheduledEvent(bot: BotWithCache) {
"MANAGE_EVENTS",
]);
return editScheduledEventOld(guildId, eventId, options);
return await editScheduledEventOld(guildId, eventId, options);
};
}

View File

@@ -4,9 +4,9 @@ import { requireBotGuildPermissions } from "../permissions.ts";
export default function getAuditLogs(bot: BotWithCache) {
const getAuditLogsOld = bot.helpers.getAuditLogs;
bot.helpers.getAuditLogs = function (guildId, options) {
bot.helpers.getAuditLogs = async function (guildId, options) {
requireBotGuildPermissions(bot, guildId, ["VIEW_AUDIT_LOG"]);
return getAuditLogsOld(guildId, options);
return await getAuditLogsOld(guildId, options);
};
}

View File

@@ -4,9 +4,9 @@ import { requireBotGuildPermissions } from "../permissions.ts";
export default function getBan(bot: BotWithCache) {
const getBanOld = bot.helpers.getBan;
bot.helpers.getBan = function (guildId, memberId) {
bot.helpers.getBan = async function (guildId, memberId) {
requireBotGuildPermissions(bot, guildId, ["BAN_MEMBERS"]);
return getBanOld(guildId, memberId);
return await getBanOld(guildId, memberId);
};
}

View File

@@ -4,9 +4,9 @@ import { requireBotGuildPermissions } from "../permissions.ts";
export default function getBans(bot: BotWithCache) {
const getBansOld = bot.helpers.getBans;
bot.helpers.getBans = function (guildId) {
bot.helpers.getBans = async function (guildId) {
requireBotGuildPermissions(bot, guildId, ["BAN_MEMBERS"]);
return getBansOld(guildId);
return await getBansOld(guildId);
};
}

View File

@@ -4,9 +4,9 @@ import { requireBotGuildPermissions } from "../permissions.ts";
export default function getPruneCount(bot: BotWithCache) {
const getPruneCountOld = bot.helpers.getPruneCount;
bot.helpers.getPruneCount = function (guildId, options) {
bot.helpers.getPruneCount = async function (guildId, options) {
requireBotGuildPermissions(bot, guildId, ["KICK_MEMBERS"]);
return getPruneCountOld(guildId, options);
return await getPruneCountOld(guildId, options);
};
}

View File

@@ -4,9 +4,9 @@ import { requireBotGuildPermissions } from "../permissions.ts";
export default function getVanityUrl(bot: BotWithCache) {
const getVanityUrlOld = bot.helpers.getVanityUrl;
bot.helpers.getVanityUrl = function (guildId) {
bot.helpers.getVanityUrl = async function (guildId) {
requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
return getVanityUrlOld(guildId);
return await getVanityUrlOld(guildId);
};
}

View File

@@ -4,23 +4,23 @@ import { requireBotGuildPermissions } from "../permissions.ts";
export function getWelcomeScreen(bot: BotWithCache) {
const getWelcomeScreenOld = bot.helpers.getWelcomeScreen;
bot.helpers.getWelcomeScreen = function (guildId) {
bot.helpers.getWelcomeScreen = async function (guildId) {
const guild = bot.guilds.get(guildId);
if (!guild?.welcomeScreen) {
requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
}
return getWelcomeScreenOld(guildId);
return await getWelcomeScreenOld(guildId);
};
}
export function editWelcomeScreen(bot: BotWithCache) {
const editWelcomeScreenOld = bot.helpers.editWelcomeScreen;
bot.helpers.editWelcomeScreen = function (guildId, options) {
bot.helpers.editWelcomeScreen = async function (guildId, options) {
requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
return editWelcomeScreenOld(guildId, options);
return await editWelcomeScreenOld(guildId, options);
};
}

View File

@@ -4,10 +4,10 @@ import { requireBotGuildPermissions } from "../permissions.ts";
export function editWidget(bot: BotWithCache) {
const editWidgetOld = bot.helpers.editWidget;
bot.helpers.editWidget = function (guildId, enabled, channelId) {
bot.helpers.editWidget = async function (guildId, enabled, channelId) {
requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
return editWidgetOld(guildId, enabled, channelId);
return await editWidgetOld(guildId, enabled, channelId);
};
}

View File

@@ -4,20 +4,20 @@ import { requireBotGuildPermissions } from "./permissions.ts";
export function deleteIntegration(bot: BotWithCache) {
const deleteIntegrationOld = bot.helpers.deleteIntegration;
bot.helpers.deleteIntegration = function (guildId, id) {
bot.helpers.deleteIntegration = async function (guildId, id) {
requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
return deleteIntegrationOld(guildId, id);
return await deleteIntegrationOld(guildId, id);
};
}
export function getIntegrations(bot: BotWithCache) {
const getIntegrationsOld = bot.helpers.getIntegrations;
bot.helpers.getIntegrations = function (guildId) {
bot.helpers.getIntegrations = async function (guildId) {
requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
return getIntegrationsOld(guildId);
return await getIntegrationsOld(guildId);
};
}

View File

@@ -76,7 +76,7 @@ export function validateApplicationCommandOptions(
export function createApplicationCommand(bot: BotWithCache) {
const createApplicationCommandOld = bot.helpers.createApplicationCommand;
bot.helpers.createApplicationCommand = function (options, guildId) {
bot.helpers.createApplicationCommand = async function (options, guildId) {
const isChatInput = !options.type ||
options.type === ApplicationCommandTypes.ChatInput;
@@ -135,14 +135,14 @@ export function createApplicationCommand(bot: BotWithCache) {
options.options = validateApplicationCommandOptions(bot, options.options);
}
return createApplicationCommandOld(options, guildId);
return await createApplicationCommandOld(options, guildId);
};
}
export function editInteractionResponse(bot: BotWithCache) {
const editInteractionResponseOld = bot.helpers.editInteractionResponse;
bot.helpers.editInteractionResponse = function (token, options) {
bot.helpers.editInteractionResponse = async function (token, options) {
if (options.content && options.content.length > 2000) {
throw Error(bot.constants.Errors.MESSAGE_MAX_LENGTH);
}
@@ -191,7 +191,7 @@ export function editInteractionResponse(bot: BotWithCache) {
}
}
return editInteractionResponseOld(token, options);
return await editInteractionResponseOld(token, options);
};
}

View File

@@ -3,7 +3,7 @@ import { AllowedMentionsTypes, BotWithCache } from "../../deps.ts";
export default function editFollowupMessage(bot: BotWithCache) {
const editFollowupMessageOld = bot.helpers.editFollowupMessage;
bot.helpers.editFollowupMessage = function (
bot.helpers.editFollowupMessage = async function (
token,
messageId,
options,
@@ -56,6 +56,6 @@ export default function editFollowupMessage(bot: BotWithCache) {
}
}
return editFollowupMessageOld(token, messageId, options);
return await editFollowupMessageOld(token, messageId, options);
};
}

View File

@@ -4,7 +4,7 @@ import { requireBotChannelPermissions } from "./permissions.ts";
export function createInvite(bot: BotWithCache) {
const createInviteOld = bot.helpers.createInvite;
bot.helpers.createInvite = function (channelId, options = {}) {
bot.helpers.createInvite = async function (channelId, options = {}) {
if (options.maxAge && (options.maxAge < 0 || options.maxAge > 604800)) {
throw new Error(
"The max age for an invite must be between 0 and 604800.",
@@ -16,27 +16,27 @@ export function createInvite(bot: BotWithCache) {
requireBotChannelPermissions(bot, channelId, ["CREATE_INSTANT_INVITE"]);
return createInviteOld(channelId, options);
return await createInviteOld(channelId, options);
};
}
export function getChannelInvites(bot: BotWithCache) {
const getChannelInvitesOld = bot.helpers.getChannelInvites;
bot.helpers.getChannelInvites = function (channelId) {
bot.helpers.getChannelInvites = async function (channelId) {
requireBotChannelPermissions(bot, channelId, ["MANAGE_CHANNELS"]);
return getChannelInvitesOld(channelId);
return await getChannelInvitesOld(channelId);
};
}
export function getInvites(bot: BotWithCache) {
const getInvitesOld = bot.helpers.getInvites;
bot.helpers.getInvites = function (guildId) {
bot.helpers.getInvites = async function (guildId) {
requireBotChannelPermissions(bot, guildId, ["MANAGE_GUILD"]);
return getInvitesOld(guildId);
return await getInvitesOld(guildId);
};
}

View File

@@ -4,20 +4,20 @@ import { requireBotGuildPermissions } from "../permissions.ts";
export function banMember(bot: BotWithCache) {
const banMemberOld = bot.helpers.banMember;
bot.helpers.banMember = function (guildId, id, options) {
bot.helpers.banMember = async function (guildId, id, options) {
requireBotGuildPermissions(bot, guildId, ["BAN_MEMBERS"]);
return banMemberOld(guildId, id, options);
return await banMemberOld(guildId, id, options);
};
}
export function unbanMember(bot: BotWithCache) {
const unbanMemberOld = bot.helpers.unbanMember;
bot.helpers.unbanMember = function (guildId, id) {
bot.helpers.unbanMember = async function (guildId, id) {
requireBotGuildPermissions(bot, guildId, ["BAN_MEMBERS"]);
return unbanMemberOld(guildId, id);
return await unbanMemberOld(guildId, id);
};
}

View File

@@ -4,9 +4,9 @@ import { requireBotGuildPermissions } from "../permissions.ts";
export default function editBotNickname(bot: BotWithCache) {
const editBotNicknameOld = bot.helpers.editBotNickname;
bot.helpers.editBotNickname = function (guildId, options) {
bot.helpers.editBotNickname = async function (guildId, options) {
requireBotGuildPermissions(bot, guildId, ["CHANGE_NICKNAME"]);
return editBotNicknameOld(guildId, options);
return await editBotNicknameOld(guildId, options);
};
}

View File

@@ -4,7 +4,7 @@ import { requireBotGuildPermissions } from "../permissions.ts";
export default function editMember(bot: BotWithCache) {
const editMemberOld = bot.helpers.editMember;
bot.helpers.editMember = function (guildId, memberId, options) {
bot.helpers.editMember = async function (guildId, memberId, options) {
const requiredPerms: PermissionStrings[] = [];
if (options.roles) requiredPerms.push("MANAGE_ROLES");
// NULL IS ALLOWED
@@ -17,6 +17,6 @@ export default function editMember(bot: BotWithCache) {
requireBotGuildPermissions(bot, guildId, requiredPerms);
}
return editMemberOld(guildId, memberId, options);
return await editMemberOld(guildId, memberId, options);
};
}

View File

@@ -4,9 +4,9 @@ import { requireBotGuildPermissions } from "../permissions.ts";
export default function kickMember(bot: BotWithCache) {
const editMemberOld = bot.helpers.kickMember;
bot.helpers.kickMember = function (guildId, memberId, reason) {
bot.helpers.kickMember = async function (guildId, memberId, reason) {
requireBotGuildPermissions(bot, guildId, ["KICK_MEMBERS"]);
return editMemberOld(guildId, memberId, reason);
return await editMemberOld(guildId, memberId, reason);
};
}

View File

@@ -4,9 +4,9 @@ import { requireBotGuildPermissions } from "../permissions.ts";
export default function pruneMembers(bot: BotWithCache) {
const pruneMembersOld = bot.helpers.pruneMembers;
bot.helpers.pruneMembers = function (guildId, options) {
bot.helpers.pruneMembers = async function (guildId, options) {
requireBotGuildPermissions(bot, guildId, ["KICK_MEMBERS"]);
return pruneMembersOld(guildId, options);
return await pruneMembersOld(guildId, options);
};
}

View File

@@ -5,7 +5,7 @@ import { requireBotChannelPermissions } from "../permissions.ts";
export function sendMessage(bot: BotWithCache) {
const sendMessageOld = bot.helpers.sendMessage;
bot.helpers.sendMessage = function (
bot.helpers.sendMessage = async function (
channelId,
content,
) {
@@ -90,7 +90,7 @@ export function sendMessage(bot: BotWithCache) {
}
}
return sendMessageOld(channelId, content);
return await sendMessageOld(channelId, content);
};
}

View File

@@ -4,7 +4,7 @@ import { requireBotChannelPermissions } from "../permissions.ts";
export function deleteMessage(bot: BotWithCache) {
const deleteMessageOld = bot.helpers.deleteMessage;
bot.helpers.deleteMessage = function (
bot.helpers.deleteMessage = async function (
channelId,
messageId,
reason,
@@ -27,14 +27,14 @@ export function deleteMessage(bot: BotWithCache) {
);
}
return deleteMessageOld(channelId, messageId, reason, milliseconds);
return await deleteMessageOld(channelId, messageId, reason, milliseconds);
};
}
export function deleteMessages(bot: BotWithCache) {
const deleteMessagesOld = bot.helpers.deleteMessages;
bot.helpers.deleteMessages = function (
bot.helpers.deleteMessages = async function (
channelId,
ids,
reason,
@@ -70,7 +70,7 @@ export function deleteMessages(bot: BotWithCache) {
"MANAGE_MESSAGES",
]);
return deleteMessagesOld(channelId, ids, reason);
return await deleteMessagesOld(channelId, ids, reason);
};
}

View File

@@ -4,7 +4,7 @@ import { requireBotChannelPermissions } from "../permissions.ts";
export function getMessage(bot: BotWithCache) {
const getMessageOld = bot.helpers.getMessage;
bot.helpers.getMessage = function (
bot.helpers.getMessage = async function (
channelId,
messageId,
) {
@@ -15,14 +15,14 @@ export function getMessage(bot: BotWithCache) {
]);
}
return getMessageOld(channelId, messageId);
return await getMessageOld(channelId, messageId);
};
}
export function getMessages(bot: BotWithCache) {
const getMessagesOld = bot.helpers.getMessages;
bot.helpers.getMessages = function (
bot.helpers.getMessages = async function (
channelId,
options,
) {
@@ -34,7 +34,7 @@ export function getMessages(bot: BotWithCache) {
]);
}
return getMessagesOld(channelId, options);
return await getMessagesOld(channelId, options);
};
}

View File

@@ -4,7 +4,7 @@ import { requireBotChannelPermissions } from "../permissions.ts";
export function pinMessage(bot: BotWithCache) {
const pinMessageOld = bot.helpers.pinMessage;
bot.helpers.pinMessage = function (
bot.helpers.pinMessage = async function (
channelId,
messageId,
) {
@@ -12,14 +12,14 @@ export function pinMessage(bot: BotWithCache) {
"MANAGE_MESSAGES",
]);
return pinMessageOld(channelId, messageId);
return await pinMessageOld(channelId, messageId);
};
}
export function unpinMessage(bot: BotWithCache) {
const unpinMessageOld = bot.helpers.unpinMessage;
bot.helpers.unpinMessage = function (
bot.helpers.unpinMessage = async function (
channelId,
messageId,
) {
@@ -27,7 +27,7 @@ export function unpinMessage(bot: BotWithCache) {
"MANAGE_MESSAGES",
]);
return unpinMessageOld(channelId, messageId);
return await unpinMessageOld(channelId, messageId);
};
}

View File

@@ -4,20 +4,20 @@ import { requireBotChannelPermissions } from "../permissions.ts";
export function addReaction(bot: BotWithCache) {
const addReactionOld = bot.helpers.addReaction;
bot.helpers.addReaction = function (channelId, messageId, reaction) {
bot.helpers.addReaction = async function (channelId, messageId, reaction) {
requireBotChannelPermissions(bot, channelId, [
"READ_MESSAGE_HISTORY",
"ADD_REACTIONS",
]);
return addReactionOld(channelId, messageId, reaction);
return await addReactionOld(channelId, messageId, reaction);
};
}
export function addReactions(bot: BotWithCache) {
const addReactionsOld = bot.helpers.addReactions;
bot.helpers.addReactions = function (
bot.helpers.addReactions = async function (
channelId,
messageId,
reactions,
@@ -28,14 +28,14 @@ export function addReactions(bot: BotWithCache) {
"ADD_REACTIONS",
]);
return addReactionsOld(channelId, messageId, reactions, ordered);
return await addReactionsOld(channelId, messageId, reactions, ordered);
};
}
export function removeReaction(bot: BotWithCache) {
const removeReactionOld = bot.helpers.removeReaction;
bot.helpers.removeReaction = function (
bot.helpers.removeReaction = async function (
channelId,
messageId,
reactions,
@@ -48,14 +48,14 @@ export function removeReaction(bot: BotWithCache) {
]);
}
return removeReactionOld(channelId, messageId, reactions, options);
return await removeReactionOld(channelId, messageId, reactions, options);
};
}
export function removeAllReactions(bot: BotWithCache) {
const removeAllReactionsOld = bot.helpers.removeAllReactions;
bot.helpers.removeAllReactions = function (
bot.helpers.removeAllReactions = async function (
channelId,
messageId,
) {
@@ -63,14 +63,14 @@ export function removeAllReactions(bot: BotWithCache) {
"MANAGE_MESSAGES",
]);
return removeAllReactionsOld(channelId, messageId);
return await removeAllReactionsOld(channelId, messageId);
};
}
export function removeReactionEmoji(bot: BotWithCache) {
const removeReactionEmojiOld = bot.helpers.removeReactionEmoji;
bot.helpers.removeReactionEmoji = function (
bot.helpers.removeReactionEmoji = async function (
channelId,
messageId,
reaction,
@@ -79,7 +79,7 @@ export function removeReactionEmoji(bot: BotWithCache) {
"MANAGE_MESSAGES",
]);
return removeReactionEmojiOld(channelId, messageId, reaction);
return await removeReactionEmojiOld(channelId, messageId, reaction);
};
}

View File

@@ -3,7 +3,7 @@ import { BotWithCache } from "../../deps.ts";
export function editBotProfile(bot: BotWithCache) {
const editBotProfileOld = bot.helpers.editBotProfile;
bot.helpers.editBotProfile = function (
bot.helpers.editBotProfile = async function (
options,
) {
// Nothing was edited
@@ -36,7 +36,7 @@ export function editBotProfile(bot: BotWithCache) {
}
}
return editBotProfileOld(options);
return await editBotProfileOld(options);
};
}

View File

@@ -5,7 +5,7 @@ import { highestRole, requireBotGuildPermissions } from "../permissions.ts";
export default function addRole(bot: BotWithCache) {
const addRoleOld = bot.helpers.addRole;
bot.helpers.addRole = function (
bot.helpers.addRole = async function (
guildId,
memberId,
roleId,
@@ -27,6 +27,6 @@ export default function addRole(bot: BotWithCache) {
requireBotGuildPermissions(bot, guild, ["MANAGE_ROLES"]);
}
return addRoleOld(guildId, memberId, roleId, reason);
return await addRoleOld(guildId, memberId, roleId, reason);
};
}

View File

@@ -4,13 +4,13 @@ import { requireBotGuildPermissions } from "../permissions.ts";
export default function createRole(bot: BotWithCache) {
const createRoleOld = bot.helpers.createRole;
bot.helpers.createRole = function (
bot.helpers.createRole = async function (
guildId,
options,
reason,
) {
requireBotGuildPermissions(bot, guildId, ["MANAGE_ROLES"]);
return createRoleOld(guildId, options, reason);
return await createRoleOld(guildId, options, reason);
};
}

View File

@@ -4,12 +4,12 @@ import { requireBotGuildPermissions } from "../permissions.ts";
export default function deleteRole(bot: BotWithCache) {
const deleteRoleOld = bot.helpers.deleteRole;
bot.helpers.deleteRole = function (
bot.helpers.deleteRole = async function (
guildId,
id,
) {
requireBotGuildPermissions(bot, guildId, ["MANAGE_ROLES"]);
return deleteRoleOld(guildId, id);
return await deleteRoleOld(guildId, id);
};
}

View File

@@ -5,7 +5,7 @@ import { highestRole, requireBotGuildPermissions } from "../permissions.ts";
export default function editRole(bot: BotWithCache) {
const editRoleOld = bot.helpers.editRole;
bot.helpers.editRole = function (
bot.helpers.editRole = async function (
guildId,
id,
options,
@@ -26,6 +26,6 @@ export default function editRole(bot: BotWithCache) {
requireBotGuildPermissions(bot, guild, ["MANAGE_ROLES"]);
}
return editRoleOld(guildId, id, options);
return await editRoleOld(guildId, id, options);
};
}

View File

@@ -5,7 +5,7 @@ import { highestRole, requireBotGuildPermissions } from "../permissions.ts";
export default function removeRole(bot: BotWithCache) {
const removeRoleOld = bot.helpers.removeRole;
bot.helpers.removeRole = function (
bot.helpers.removeRole = async function (
guildId,
memberId,
roleId,
@@ -27,6 +27,6 @@ export default function removeRole(bot: BotWithCache) {
requireBotGuildPermissions(bot, guild, ["MANAGE_ROLES"]);
}
return removeRoleOld(guildId, memberId, roleId, reason);
return await removeRoleOld(guildId, memberId, roleId, reason);
};
}

View File

@@ -4,7 +4,7 @@ import { requireBotChannelPermissions } from "../permissions.ts";
export default function createWebhook(bot: BotWithCache) {
const createWebhookOld = bot.helpers.createWebhook;
bot.helpers.createWebhook = function (channelId, options) {
bot.helpers.createWebhook = async function (channelId, options) {
requireBotChannelPermissions(bot, channelId, ["MANAGE_WEBHOOKS"]);
if (
@@ -17,6 +17,6 @@ export default function createWebhook(bot: BotWithCache) {
);
}
return createWebhookOld(channelId, options);
return await createWebhookOld(channelId, options);
};
}

View File

@@ -4,9 +4,9 @@ import { requireBotChannelPermissions } from "../permissions.ts";
export default function deleteWebhook(bot: BotWithCache) {
const deleteWebhookOld = bot.helpers.deleteWebhook;
bot.helpers.deleteWebhook = function (channelId, options) {
bot.helpers.deleteWebhook = async function (channelId, options) {
requireBotChannelPermissions(bot, channelId, ["MANAGE_WEBHOOKS"]);
return deleteWebhookOld(channelId, options);
return await deleteWebhookOld(channelId, options);
};
}

View File

@@ -4,7 +4,7 @@ import { requireBotChannelPermissions } from "../permissions.ts";
export default function editWebhook(bot: BotWithCache) {
const editWebhookOld = bot.helpers.editWebhook;
bot.helpers.editWebhook = function (channelId, webhookId, options) {
bot.helpers.editWebhook = async function (channelId, webhookId, options) {
requireBotChannelPermissions(bot, channelId, ["MANAGE_WEBHOOKS"]);
if (options.name) {
if (
@@ -18,6 +18,6 @@ export default function editWebhook(bot: BotWithCache) {
}
}
return editWebhookOld(channelId, webhookId, options);
return await editWebhookOld(channelId, webhookId, options);
};
}

View File

@@ -4,7 +4,7 @@ import { validateComponents } from "../components.ts";
export function editWebhookMessage(bot: BotWithCache) {
const editWebhookMessageOld = bot.helpers.editWebhookMessage;
bot.helpers.editWebhookMessage = function (
bot.helpers.editWebhookMessage = async function (
webhookId,
webhookToken,
options,
@@ -62,7 +62,7 @@ export function editWebhookMessage(bot: BotWithCache) {
if (options.components) validateComponents(bot, options.components);
return editWebhookMessageOld(webhookId, webhookToken, options);
return await editWebhookMessageOld(webhookId, webhookToken, options);
};
}

View File

@@ -4,7 +4,7 @@ import { validateComponents } from "../components.ts";
export default function sendWebhook(bot: BotWithCache) {
const sendWebhookOld = bot.helpers.sendWebhook;
bot.helpers.sendWebhook = function (webhookId, webhookToken, options) {
bot.helpers.sendWebhook = async function (webhookId, webhookToken, options) {
if (
options.content &&
!bot.utils.validateLength(options.content, { max: 2000 })
@@ -62,6 +62,6 @@ export default function sendWebhook(bot: BotWithCache) {
);
}
return sendWebhookOld(webhookId, webhookToken, options);
return await sendWebhookOld(webhookId, webhookToken, options);
};
}

View File

@@ -18,6 +18,7 @@ export function createRequestBody(rest: RestManager, queuedRequest: { request: R
// IF A REASON IS PROVIDED ENCODE IT IN HEADERS
if (queuedRequest.payload.body?.reason) {
headers["X-Audit-Log-Reason"] = encodeURIComponent(queuedRequest.payload.body.reason as string);
queuedRequest.payload.body.reason = undefined;
}
// IF A FILE/ATTACHMENT IS PRESENT WE NEED SPECIAL HANDLING

View File

@@ -10,9 +10,10 @@ import { RestPayload, RestRateLimitedPath, RestRequest } from "./rest.ts";
import { runMethod } from "./runMethod.ts";
import { simplifyUrl } from "./simplifyUrl.ts";
import { baseEndpoints } from "../util/constants.ts";
import { API_VERSION } from "../util/constants.ts";
export function createRestManager(options: CreateRestManagerOptions) {
const version = options.version || "9";
const version = options.version || API_VERSION;
if (options.customUrl) {
baseEndpoints.BASE_URL = `${options.customUrl}/v${version}`;

View File

@@ -0,0 +1,4 @@
{
"label": "Command Handler",
"position": 7
}

View File

@@ -0,0 +1,91 @@
---
sidebar_position: 2
---
# Command Manager
Currently, you probably have something like this in your code:
```js
const Discord = require("discordeno");
// Ideally you should move to an `.env` file
const config = require("./config.json");
const client = Discord.createBot({
events: {
messageCreate(client, message) {
if (message.content === "!ping") {
client.helpers.sendMessage(message.channelId, { content: "pong" });
}
},
},
intents: ["Guilds", "GuildMessages"],
token: config.token,
});
Discord.startBot(client);
```
Of course, if you add more and more commands and as your code base grows, you can lose track very quickly.
To avoid this, it is recommended to store the commands in separate folders divided into different categories.
[Previously, we introduced you to our plugin structure, which has a lot of advantages.](../design.md)
```root
├Plugins/
├── General/
│ ├── commands/
│ │ ├── ping.js
│ │ └── ...
├── Developer/
│ ├── commands/
│ │ ├── eval.js
│ │ └── ...
└── ...
```
**Get [this file](https://github.com/discordeno/discordeno/tree/main/template/nodejs/Managers/CommandManager.js) from
the [nodejs template](https://github.com/discordeno/discordeno/tree/main/template)**
```js
const CommandManager = require("./template/Managers/CommandManager.js");
const manager = new CommandManager({});
manager.load({ plugin: true }); // Load the commands
client.commands = manager;
client.commands.cache.get("ping"); // Get the `ping` command
```
The Manager will automatically iterate through all files in the folder and then load them into the cache property, which
is mapped on the command name.
**Take a look at [Create Command](./create-command.md) to learn how to create a command.**
## Handle Command
The manager also contains a handler for executing the command when a message is received.
:::important
Currently checks for permissions, cooldowns, and rate limits are not covered, but these will be added soon.
:::
### Message Create Event:
```js
module.exports = async (client, message) => {
client.commands.isCommand(message);
};
```
### Interaction Create Event:
```js
module.exports = async (client, interaction) => {
client.commands.isInteraction(interaction);
};
```
You can also customize the `isCommand` function to your use case.

View File

@@ -0,0 +1,61 @@
---
sidebar_position: 3
---
# Create Command
One of the most important features we wanted in our template, was that you can use the same code for handling
`slash commands` and `message based commands`.
This can be done by saving the static class in the command cache, creating a constructor and passing the desired data.
Moreover the `BaseCommand` is extended with the `Response Command` class, so you can take advantage of functions such as
`.reply()`
**Copy the [`BaseCommand`](https://github.com/discordeno/discordeno/tree/main/template/nodejs/Structures/BaseCommand.js)
&
[`CommandResponses`](https://github.com/discordeno/discordeno/tree/main/template/nodejs/Structures/CommandResponses.js)
code from the template**
### Creating a Ping Command:
```js
const BaseCommand = require("../../../Structures/BaseCommand.js");
const Embed = require("../../../Structures/Embed.js");
class pingCommand extends BaseCommand {
static name = "ping";
static description = "See if the bot latency is okay";
static usage = "";
static category = "General";
static slash = { name: "ping", category: "info" };
constructor(data) {
super(data);
}
async execute() {
const msg = await this.reply({content: `Pinging...`});
// Assign properties to the response
const ping = msg.timestamp - this.message.timestamp;
const embed = new Embed()
.setTitle(`The Bots ping is ${ping} ms`)
.toJSON();
// Edit Message with the Embed
return await msg.edit({embeds: [embed] });
});
}
}
module.exports = pingCommand;
```
- The `BaseCommand` is extended with the `CommandResponses` class.
- The ping command class is been extended with the `BaseCommand` class.
- Some static properties are assigned to the ping command class, in order to access it in the cache, such as `name`,
`description`, `usage`, `category` and `slash`...
- The `execute()` function will be called, when the command has been run by the user.
- The constructor allows to access data, such as `this.message`, `this.args`, `this.client`...
You can customize the `CommandManager` file, in order to pass arguments in the `execute()` function.

View File

@@ -0,0 +1,22 @@
---
sidebar_position: 1
---
# Getting Started with the Command Manager
One of the most important characteristics of bots is that they have commands that can be used to interact with the bot.
Hard coding your commands in an event function is not the best code practice and should be strictly prevented.
In the following we will show you how to create a command manager, which is compatible with Discordeno's Client.
- Load Commands
- Handle Commands
- Reload Commands
:::info template
You can also copy the
[`CommandManager` from the template repo](https://github.com/discordeno/discordeno/tree/main/template/nodejs/Managers/CommandManager.js).
:::

View File

@@ -0,0 +1,4 @@
{
"label": "Event Handler",
"position": 6
}

View File

@@ -0,0 +1,119 @@
---
sidebar_position: 2
---
# Create Event Manager
In order to process certain events, you must provide the Discordeno client with functions for these events.
```js
const Discord = require("discordeno");
const config = require("./config.json");
const client = Discord.createBot({
events: {
ready(client, payload) {
console.log(`Successfully connected Shard ${payload.shardId} to the gateway`);
},
async messageCreate(client, message) {
if (message.content === "!ping") {
await client.helpers.sendMessage(message.channelId, { content: "pong" });
}
console.log(`Received message: ${message.content || message.embeds}`);
},
},
intents: ["Guilds", "GuildMessages"],
token: config.token,
});
Discord.startBot(client);
```
As you listen to more and more events, the functions code grows along with them, so you can quickly lose track.
To avoid this, we recommend storing the event functions divided into files in a separate folder.
## Create Event Folder
Create a folder called `events` in your project folder.
:::info note
The event files have to be named using camelCase so that they can be understood by the client. e.g `message` ->
`messageCreate.js`. You can check the typings see how the events are called.
:::
Ready Event:
```js
module.exports = (client, payload) => {
if (payload.shardId + 1 === client.gateway.maxShards) {
// All Shards are ready
console.log(`Successfully connected to the gateway as ${payload.user.username}#${payload.user.discriminator}`);
}
};
```
## Load your Events
```js
const fs = require("fs");
const path = require("path");
const resolveFolder = (folderName) => path.resolve(__dirname, ".", folderName);
class EventManager {
constructor(client) {
this.cache = new Map();
this._events = {};
}
load(options = {}) {
const eventsFolder = resolveFolder("../events");
fs.readdirSync(eventsFolder).map(async (file) => {
if (!file.endsWith(".js")) return;
const fileName = path.join(eventsFolder, file);
const event = require(fileName);
const eventName = file.split(".")[0];
this._events[`${eventName}`] = event;
});
return this._events;
}
}
module.exports = EventManager;
```
The code above, which can also be found in the
[template repo](https://github.com/discordeno/discordeno/tree/main/template/nodejs/Managers/EventManager.js) will loop
through all the files in the `events` folder and load the functions into the `_events` object.
In order to let the client know which events should be processed, you need to pass the functions in the
`createBot<options>.events` object.
```js
const Discord = require("discordeno");
const config = require("./config.json");
const EventManager = require("./Managers/EventManager.js");
const events = new EventManager({});
const client = Discord.createBot({
events: events.load({}),
intents: ["Guilds", "GuildMessages"],
token: config.token,
});
Discord.startBot(client);
```
Moreover, you can customize the `EventManager` and add more functionality to it and make it exactly fit your your needs
or even emit events, by extending it.
Of course you wonder what you can do with all of this now. We will explain this further on the next page.

View File

@@ -0,0 +1,29 @@
---
sidebar_position: 1
---
# Getting Started with the Event Handler
An event handler is essential to process the data, which Discord sends to you.
With a good implementation, you will have a nice code structure and thus have a good overview in long term.
Since the `EventEmitter` class is commonly used you probably already know it from other libraries.
Discordeno decided against it as it comes with several downsides which are mentioned below.
Performance plays a more important role than handling, however this event management system can be easily implemented
since it only needs a few changes in your code.
- It's easy to create memory leaks, when you add too many listeners or go carelessly with it.
- Many fragmented parts of event code complicate maintenance.
- ErrorHandling is difficult and debugging is harder when many listeners are open for the same events.
In the following we will show you, how to create an event manager, which is compatible with Discordeno's Client.
:::info template
You can also copy the
[`EventManager` from the template repo](https://github.com/discordeno/discordeno/tree/main/template/nodejs/Managers/EventManager.js).
:::

View File

@@ -0,0 +1,74 @@
---
sidebar_position: 3
---
# Handle Events
When an event is fired, Discordeno sends two important things: the `client` instance and the `payload`.
As mentioned in the `Structure` section the `payload` object, does not contain any functions, its a plain json object.
In order to take use of our nice built structures, we need to transform the payload into a structure.
:::info
The Structures can be found [here](https://github.com/discordeno/discordeno/tree/main/template/nodejs/Structures)
:::
Sometimes it's important to listen to events, in order to get informed of changes and updating the cache based on it.
### Message Event
This file should be called `messageCreate.js`.
```js
const Message = require("./structures/Message");
module.exports = async (client, payload) => {
const message = new Message(client, payload);
if (message.isBot) return;
if (message.content === "!ping") return await message.reply("pong");
};
```
### Interaction Event
This file should be called `interactionCreate.js`.
```js
const Interaction = require("./structures/Interaction");
module.exports = async (client, payload) => {
const interaction = new Interaction(client, payload);
if (interaction.data.name === "ping") return await interaction.reply({ content: "pong" });
};
```
### Ready Event
This file should be called `ready.js`.
:::tip
There is a small difference with the `ready` Event. The Event is fired `shard` wise, in other words it fires every time
a `shard` becomes ready.
:::
In order to fire the "real event" a small code snippet has to be added to the `ready` Event.
```js
const User = require("../Structures/User");
module.exports = async (client, payload) => {
client.user = new User(client, payload.user);
if (payload.shardId + 1 === client.gateway.maxShards) {
// All Shards are ready
console.log(`Successfully connected to the gateway as ${client.user.tag}`);
}
};
```

View File

@@ -0,0 +1,4 @@
{
"label": "Structures",
"position": 5
}

View File

@@ -0,0 +1,219 @@
---
sidebar_position: 4
---
# Create Components
Since Discord has decided to make message content accessible only to privileged bots, components will play an
increasingly important role in the future. Discord has released some components already and many more will follow. Of
course, this opens up completely new possibilities. On the one hand, it improves the user experience and on the other
hand, the interactions can be easily handled by the developer.
To take advantage of this, we'll go into more detail on how to use them.
:::note Runtime Overhead
Constructor classes are nice to use and make your code look better, but they incur a slight runtime overhead compared to
just using raw data because they still execute methods, which takes more time to process.
:::
We already have a Template for `Components`, which can be found
[here](https://github.com/discordeno/discordeno/tree/main/template/nodejs/structures/Component.js).
## Different Components:
There are many different components, which you can quickly read about here:
### Action Row (`type: 1`):
This is a top level component, which contains a limited amount of other components. It can be described as container.
An Action Row ...
- can not include an action row
- can maximal have 5 Buttons
- can have 1 SelectMenu
- can have 1 Text Input (only available in modal responses)
### Button (`type: 2`):
Buttons are interactive components, are bound to a message and they sent an interaction payload, when a user clicks on
it.
![Different Button Styles](https://i.imgur.com/jUE2Kp0.png)
- Needs a customId, except the Link Button
- An Action Row can have maximal 5 Buttons
There are different styles of buttons, which can be used:
- `1` - PRIMARY - blurple - customId required
- `2` - DEFAULT - grey - customId required
- `3` - SUCCESS - green - customId required
- `4` - DANGER - red - customId required
- `5` - LINK - grey - url required
### Select Menu (`type: 3`):
Select Menus are a simple drop-down with selectable options. They accept a set of allowed selects, which sends an
interaction payload, when a user selects sth. from the menu.
![Select Menu](https://i.imgur.com/42Hwiuw.png)
- You can specify a range of allowed selects (`minValue` and `maxValue`)
- Every Select Item can have an `emoji` and has a `value`, in order to identify the selected item
- A default Select Item can be set
- An Action Row can have maximal 1 Select Menu
### Text Input (`type: 4`):
Text Inputs are interactive components, which can just be sent with a modal response.
- You can specify a range of text length (`minLength` and `maxLength`)
- You can add a placeholder, a pre-filled value and specify whether the text input is required
- An Action Row can have maximal 1 Text Input
## Send Components
As mentioned above there are different types of components. This requires to define a type, so that Discord knows, which
component you want to use.
```js
class ActionRow {
constructor(options = {}) {
this.type = 1;
}
setComponents(...components) {
this.components = components;
return this;
}
}
```
```js
const button = new Button();
const button2 = new Button();
const actionRow = new ActionRow().setComponents(button, button2);
```
This code will obviously not work because it's a missing a lot required of data. The other reason is that we can't send
a class to Discord, we need sth. to transform it to a json object.
We have a pre-made class for components which you can find
[here](https://github.com/discordeno/discordeno/tree/main/template/nodejs/structures/Component.js).
### Button
```js
const button = new Component()
.setType("BUTTON")
.setStyle("LINK")
.setLabel("Click me!")
.setUrl("https://google.com")
.toJSON();
// Button with raw types
const button2 = new Component()
.setType(2)
.setStyle(4)
.setLabel("DO NOT CLICK")
.setCustomId("12345")
.toJSON();
const actionRow = new Component()
.setType("ACTION_ROW")
.setComponents(button, button2)
.toJSON();
// Message to send
const messageOptions = { content: "hello", components: [actionRow] };
await client.helpers.sendMessage(channelId, messageOptions); // You can also use the Message Structure
```
As you can see, for simplicity you can use strings instead of numbers (types), which are hard to remember.
### Select Menu
```js
const selectMenu = new Component()
.setType("SELECT_MENU")
.setCustomId("12345")
.setOptions([
{
label: "Option 1",
value: "1",
description: `This is option 1`,
},
{
label: "Option 2",
value: "2",
description: `This is option 2`,
},
{
label: "Default Option",
value: "3",
description: `Default option...`,
default: true,
},
])
.setPlaceholder("Select an option")
.toJSON();
const actionRow = new Component()
.setType("ACTION_ROW")
.setComponents(selectMenu)
.toJSON();
const messageOptions = { content: "hello", components: [actionRow] };
client.helpers.sendMessage(channelId, messageOptions); // You can also use the Message Structure
```
### Text Input
```js
const textInput = new Component()
.setType("TEXT_INPUT")
.setStyle("SHORT")
.setCustomId("t1")
.setLabel("User ID")
.setPlaceholder("User ID")
.setRequired(true)
.setMaxLength(20)
.setMinLength(1)
.toJSON();
const textInput2 = new Component()
.setType("TEXT_INPUT")
.setStyle("PARAGRAPH")
.setCustomId("t2")
.setLabel("Reason")
.setPlaceholder("Reason for Ban")
.setRequired(false)
.setMaxLength(300)
.toJSON();
const actionRow = new Component().setType("ACTION_ROW").setComponents(textInput).toJSON();
const actionRow2 = new Component().setType("ACTION_ROW").setComponents(textInput2).toJSON();
new Interaction(client, interaction).popupModal({
customId: "ban_modal",
title: "Ban User",
components: [actionRow, actionRow2],
});
```
### Receive Interactions
When a user clicks a button or selects an option from a Select Menu, Discord sends an `interactionCreate` event, which
contains the information necessary to process it.
:::note Collecting
An `InteractionCollector` can also be used to handle prompts, which requires some tweaks, but will be added soon in the
guide and the template repo.
:::

View File

@@ -0,0 +1,79 @@
---
sidebar_position: 2
---
# Create Structure
Structures are often used to transform data and add methods to existing objects. To make it easier to work with them.
Imagine you have a channel object to which you want to send a message.
```js
const data = {
id: 806947972004839444n,
name: "spam-and-bots",
};
```
The recommended way would be:
```js
await client.helpers.sendMessage(data.id, { content: "hello" });
```
However, you probably want to use something shorter, such as the following:
```js
const Channel {
constructor(client, data) {
this.client = client;
this.id = data.id;
this.name = data.name;
}
async send(options) {
return await client.helpers.sendMessage(this.id, options);
}
}
```
Now you can use the `.send()` method on the channel object without using such a long code:
```js
const channel = new Channel(client, data);
await channel.send({ content: "hello" });
```
Moreover, you can modify the `.send()` method to better suit your use case e.g not send the message if the channel is
blacklisted.
This naturally opens a lot of opportunities and makes coding a lot easier. Because you decide what you want to do with
the data, how the methods are named and how you want to process the request.
## Using Template Structures:
When you are migrating from another library, you'll likely choose to continue using special structures. Therefore why we
have ready-made structures in our template repo:
- [Guild](https://github.com/discordeno/discordeno/tree/main/template/nodejs/structures/Guild.js)
- [Channel](https://github.com/discordeno/discordeno/tree/main/template/nodejs/structures/Channel.js)
- [Role](https://github.com/discordeno/discordeno/tree/main/template/nodejs/structures/Role.js)
- [Member](https://github.com/discordeno/discordeno/tree/main/template/nodejs/structures/Member.js)
- [User](https://github.com/discordeno/discordeno/tree/main/template/nodejs/structures/User.js)
- [Message](https://github.com/discordeno/discordeno/tree/main/template/nodejs/structures/Message.js)
- [Interaction](https://github.com/discordeno/discordeno/tree/main/template/nodejs/structures/Interaction.js)
We recommend that you clone the whole template repo, since some structures are based on other files.
**Using the Structures:**
```js
const Guild = require("./structures/Guild"); // Path to your structure
const guild = new Guild(client, data); // DiscordenoClient and DiscordenoPayloadData
```
Some popular methods have been added to the structures so that you can use them without having to come up with your own.
Of course, you can add your own methods and customize the structures to fit your needs.
Next we're going to give a better insight into how create [`Embeds`](embeds) and [`Components`](components) with the
template structures.

View File

@@ -0,0 +1,107 @@
---
sidebar_position: 3
---
# Create Embeds
Embeds are widely used by bots in order to display messages in a fancy way.
Unfortunately, the Discord API does not accept funky classes such as `new MessageEmbed().setTitle("hello")`, instead it
takes a json object, e.g. `{ title: "hello" }`. Therefore, we need to create an embed Structure that converts the
user-supplied data into the format which Discord uses.
:::note Runtime Overhead
Constructor classes are nice to use and make your code look better, but they incur a slight runtime overhead compared to
just using raw data because they still execute methods, which takes more time to process.
:::
```js
class Embed() {
constructor() {}
setTitle(title) {
this.title = title;
}
}
```
Now we have created a class which we can use to create embeds. But we can't just send this to Discord.
So we need an additional method which will convert the data from the class to the correct format.
```js
class Embed(){
constructor() {}
setTitle(title) {
this.title = title;
}
toJSON() {
return {
title: this.title
}
}
}
```
Wow, now you can create a embed and send it to Discord.
```js
const Channel = require("./structures/Channel"); // Path to structure
const channel = new Channel(client, data);
await channel.send({ embeds: [embed] });
```
You probably want more methods which you can use to create embeds.
[We also have a Template for this](https://github.com/discordeno/discordeno/tree/main/template/nodejs/structures/Embed.js)
### Using the Embed Structure:
```js
const Embed = require("./structures/Embed"); // Path to structure
const Channel = require("./structures/Channel"); // Path to structure
const channel = new Channel(client, data);
const showCaseEmbed = new Embed()
.setColor(0x00AE86)
.setTitle("A Random Title")
.setURL("https://github.com/discordeno")
.setAuthor({
name: "Author name",
iconUrl: "https://raw.githubusercontent.com/discordeno/discordeno/main/site/static/img/logo.png",
url: "https://github.com/discordeno",
})
.setDescription("A Random Description")
.setThumbnail("https://raw.githubusercontent.com/discordeno/discordeno/main/site/static/img/logo.png")
.addFields(
{ name: "Field 1 Name", value: "Normal Field Value" },
{ name: "\u200B", value: "\u200B" },
{ name: "Field 2 Name", value: "Inline Field Value", inline: true },
{ name: "Field 3 Name", value: "Inline Field Value", inline: true },
)
.addField({ name: "Field 4", value: "Field Value" })
.setImage("https://raw.githubusercontent.com/discordeno/discordeno/main/site/static/img/logo.png")
.setTimestamp()
.setFooter({
text: "A Footer Text",
iconUrl: "https://raw.githubusercontent.com/discordeno/discordeno/main/site/static/img/logo.png",
})
.toJSON();
await channel.send({ embeds: [showCaseEmbed] });
```
### Embed Limits:
- Title: 256 characters
- Description: 4096 characters
- Field Name: 256 characters
- Field Value: 1024 characters
- Footer Text: 2048 characters
- Author Name: 256 characters
- 10 Embeds per message
- In total over all 10 Embeds not more than 6000 characters

View File

@@ -0,0 +1,30 @@
---
sidebar_position: 1
---
# Getting Started with Structures
As previously mentioned, Discordeno was built with as few classes as possible, this is in favor of performance.
For example, you cannot execute functions on objects.
```diff
- message.channel.send({content: "hello"})
+ client.helpers.sendMessage(message.channel.id, {content: "hello"})
```
This seems to be more complicated at first, but has many advantages:
- You get full control over the actions
- Errors are easier to debug
- A validation by classes does not have to take place
One of the disadvantages is that you have to change a lot in your code.
Of course, we recommend that you try out the upper way, but we will introduce structures in this guide because they are
used by many users who eventually want to migrate.
For example, if you want to get correctly formatted objects, structures are obviously beneficial, because they support
the readability of the code by their ease of use
In the following, we will introduce how to create your own structures and how to use the ones available in the template.

View File

@@ -0,0 +1,4 @@
{
"label": "Nodejs",
"position": 3
}

View File

@@ -0,0 +1,29 @@
---
sidebar_position: 3
---
# Create Application
1. Go to the [Developer Portal](https://discord.com/developers/applications) and create a new application.
2. Navigate to the Section `Bot` and confirm with "Yes, do it!"
3. Now copy your token and save it under a safe environment.
:::caution Token Security
Keep your token safe, because it is like a password that grants access to your bot, which then can be used for mass
DMing, mass banning or any other kind of malicious activity.
:::
## Add your Bot to your Server
In order to use your Bot, it should be in a server where you can interact with it.
1. Go to the [Developer Portal](https://discord.com/developers/applications) and click on your previously created bot.
2. Click on `OAuth2` and there go to the `URL Generator`.
3. Select the `bot` and the `applications.commands` scope.
4. Scroll down and select the `Administrator` permission.
5. Copy the generated URL and open it in your browser.
6. Select your Server and click the invite button.
The bot should now have been added to your server and show as an offline user.

203
site/docs/nodejs/design.md Normal file
View File

@@ -0,0 +1,203 @@
---
sidebar_position: 6
---
# Design
In order to ensure long-term scalability and maintainability, the code structure is of enormous importance. In the
following, we show how such a code structure could look like.
The essential parts are a `CommandHandler/CommandManager`, `EventHandler/EventManager`, lots of `Structures` in order to
code faster and `Plugins`, where your different features will be, such as `Commands`, `DB Stuff`...
## Code Structure
We recommend following structure for your code:
```root
├index.js
├─Structures/
├─Managers/
├─events/
├─Plugins/
├── General/
│ ├── commands/
│ │ ├── ping.js
│ │ └── ...
├── Developer/
│ ├── commands/
│ │ ├── eval.js
│ │ └── ...
├─Util/
└── ...
```
The following explains why this structure is suitable. If you want to follow this guide further, you should create these
folders.
In the `Managers` folder the Managers will be added e.g. `CommandManager.js`, `EventManager.js`. Generally codes, which
manage the system.
While in the `Structures` folder mainly classes are added like `BaseCommand.js`, `CommandResponse.js`, `Embed.js`,
`Components.js`, which make it easier to add methods to objects.
The `events` folder will contain the event handlers such as `messageCreate.js`, `debug.js`
Your many useful features and categories end up in the `Plugins` folder, where they should be categorically divided into
many folders.
The `Util` folder contains functions or classes that help you convert certain things, such as timestamps, into a
human-readable format.
## CommandHandler & BaseCommand
The `CommandHandler` is the main class of the bot, which will handle all the commands and the events received from
Discord.
The `BaseCommand` is the base class of all commands, which will be extended with the`CommandResponse` class.
### Steps showed in the following Guide
- Loading commands from different plugins
- Deploying slash commands
- Handling `messageCreate` & `interactionCreate` events
- Command rate limit handling
- Handle `Interaction` & `Message` commands with the same code
- Validating user provided arguments
- Correct permission and error handling
- Hot reloading commands
- Creating message and interaction collectors
## EventHandler
You probably realized that Discordeno does not use an `EventEmitter` to fire the events, but your own event function is
fired.
There are ways to adapt to an `EventEmitter`, but we decided against it for the following reasons:
- It's easy to create memory leaks, when you add too many listeners or go carelessly with it.
- Many fragmented parts of event code complicate maintenance.
- ErrorHandling is difficult and debugging is harder when many listeners are open for the same events.
## Structures
Structures are essential to abstract larger parts of code in smaller ready-made methods and to modify them if necessary.
Example:
```js
class Command {
static name = "ping";
static aliases = ["pong"];
static botPermission = ["SEND_EMBED_LINKS"];
run(message, args) {
// do something
}
}
```
It would be annoying adding everytime the `botPermission` property to the class Command, when the Permission is used
from every Command, then it is unnecessary to add it, when you can extend the class.
It would be annoying to add the `botPermission` property to the command class every time the same permissions are used
by each command. Extending the class makes this extra step obsolete.
```js
class BaseCommand {
constructor(client) {
this.client = client;
this.basePermission = ["SEND_EMBED_LINKS"];
}
}
class Command extends BaseCommand {
static name = "ping";
static aliases = ["pong"];
constructor(data) {
super(data);
}
run(message, args) {
// do something
}
}
```
## Plugins
The plugins folder helps you categorize your code into many parts to give some structure.
Of course, this has many advantages, you have a much clearer code, you can debug problems much easier.
This also opens possibilities for open source contributions, since not all parts of the code have to be published in
order to add new plugins, since they are "independent".
There will be the main `Plugins` folder, which by default contains a `General` folder for all your base commands. The
`Plugins` folder will also contain all your other plugins.
## Error Handling
One of the most important things is how to handle errors. This is done to provide a user-friendly experience and to find
errors faster.
You should catch errors and log them in your logger so you can fix them later. There are several open source `Sentry`'s
that give you a good overview of the latest errors through a website.
Sometimes errors have a positive effect on maintainability and scalability.
In addition, handling errors caused by users is very important to increase transparency. If they don't know why the
error happened, then they'll be very surprised with what they did wrong and might even remove your bot from their
server.
## Caching
Normally libraries cache all the info they get, which can of course be helpful at the beginning to discover all
functionalities but later it turns out to be a resource-consuming method. Therefore, this way should be avoided.
Discordeno allows `Custom Caching` and even `Custom Property Caching` which gives you fine-grained control over the
caching of data. Normally you only need 20% of the data received by Discord, which makes caching unnecessary in most
cases.
There are also some `Filter` and `Sweeper` methods which help you to empty unused cache values.
## Cross Communication & Scaling
If you are running many different processes, such as a Welcomer API, communication is of central importance in order to
send or receive data, with which you can then perform certain actions.
Cross communication can be easily done with sockets or a TCP client.
This brings up this Structure:
```js
Bridge (Heart)
- Machine 1
- Cluster [0-9]
- Machine 2
- Cluster [10-18]
- Machine 3 -> Welcomer Api
- Machine 4 -> Dashboard
```
It's important to use something fast to have a proper "real time" communication.
Discordeno already offers many internal options for scaling bots, no matter what size.
As you scale, you will likely separate many parts of your bot and put them in separate processes, such as a
`RestManager`, a `Gateway Manager` etc.
This of course opens up a lot of possibilities:
- Zero downtime updates
- Global cache
- Synced rate limits
[Check the Github Readme for more information](https://github.com/discordeno/discordeno#features)
:::tip congratulations
You just learned how to design a scalable bot, let's get into implementing it with the next pages.
:::

View File

@@ -0,0 +1,48 @@
---
sidebar_position: 1
---
# Getting Started
If you are reading this, you probably want to create a Discord bot with Discordeno or migrate from popular libraries
like Discord.js.
If this is going to be your first time making a bot, you should use Deno instead of Node.js. Although in some cases Deno
might not be suitable for you, because of missing packages or a code base which too large to migrate to a slightly
different language.
This guide will help you making your first Discord Bot using Node.js or even migrating your Bot from a other Library.
:::important Disclaimer
Some features are not documented yet. If you want to know more about them, kindly ask for help in the
[Discord Server](https://discord.gg/ddeno).
:::
## Why should I switch?
Discordeno was built with the purpose of being scalable, flexible and easy to use.
Libraries like `Discord.js` and `Eris` often have excessive caching behavior that can only be changed slightly without
breaking the entire library. There is a lack of customization and many nested classes, which makes it almost impossible
to edit the code without having unwanted side effects. Moreover scalability is only possible on a limited extend.
Discordeno has been kept plain and simple, which opens up a lot of opportunities for customization such as
`custom-caching (custom-property-caching)`, [`Standalone Rest`](../big-bot-guide/rest.md),
[`Gateway`](../big-bot-guide/gateway.md), [`Cache`](../big-bot-guide/cache.md) and more. Check the detailed advantages
[here](https://github.com/discordeno/discordeno#features).
This guide will also help you making your code more scalable and easier to maintain with bringing you closer to the
Discord API.
# Before you start
Before you start digging in this guide, you should have a solid understanding of `javascript`. If you are not familiar
with it, then you should take a look at some popular resources.
- [W3Schools Course](https://www.w3schools.com/js/DEFAULT.asp)
- [Mozilla Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
- [JavaScript.Info](https://javascript.info)
A basic understanding is of great importance in order to solve problems skillfully.

View File

@@ -0,0 +1,46 @@
---
sidebar_position: 4
---
# Initial Setup
## Config File
Ideally, you should save your configs in an `.env` file. Out of simplicity for this guide, we are saving it in a
`config.json` file.
Create a file named `config.json` in your project folder and insert the following content:
```json
{
"token": "YOUR_TOKEN_HERE",
"prefix": "!"
}
```
## Edit the main file
Open the `index.js` file which you have created earlier and then insert the following content:
```js
const Discord = require("discordeno");
const config = require("./config.json");
const client = Discord.createBot({
events: {
ready(client, payload) {
console.log(`Successfully connected Shard ${payload.shardId} to the gateway`);
},
},
intents: ["Guilds", "GuildMessages"],
token: config.token,
});
Discord.startBot(client);
```
Now you can start your bot by running the following command in your terminal:
```cli
$ node index.js
```

View File

@@ -0,0 +1,29 @@
---
sidebar_position: 2
---
# Installing Node.js and Discordeno
To use the Discordeno library you first need to install Node.js and then Discordeno from NPM.
Go to [nodejs.org](https://nodejs.org/en/) and download the latest version of Node.js. Open the downloaded file and
follow the instructions of the installer to install Node.js.
## Create a Folder
Open your file manager and create a new folder (e.g.: `discordbot`) in your desired directory. Then open the code editor
of your choice and create a new file (e.g.: `index.js`) in the folder you just have created.
### Initalize NPM & Install Discordeno
In order to keep track of the dependencies, you need to initialize NPM, which generates a `package.json` file.
```cli
$ npm init --yes
```
Then you need to install Discordeno. Go to your terminal and run the following command:
```cli
$ npm install discordeno
```

View File

@@ -0,0 +1,64 @@
---
sidebar_position: 5
---
# Slash Commands
Since Discord has decided to make message content accessible only to privileged bots, message commands will play a
subordinate role in the future. Discord users will be more used to slash commands. That's why it's essential that every
bot offers them.
In the following we will show you how to create slash commands:
## Deploying Slash Commands
There is a difference between global and guild commands. Global commands take a while to appear in all guilds. Guild
commands show up directly.
For this reason, we will now show how to create guild commands, in order to test them immediately.
```js
const guildId = BigInt("YOUR_GUILD_ID");
const command = {
name: "ping",
description: "Retrieves the Bot latency",
options: [],
};
client.helpers.createApplicationCommand(command, guildId);
```
This is just very simple example, you can also add sub commands, select options and much more.
## Handling Slash Commands
Discord sends a WebSocket Event, when a user runs a slash command. You can listen to this event by add the
`interactionCreate` function in the client.
```js
const Discord = require("discordeno");
const config = require("./config.json");
const client = Discord.createBot({
events: {
ready(client, payload) {
console.log(`Successfully connected Shard ${payload.shardId} to the gateway`);
},
async interactionCreate(client, interaction) {
if (interaction.data?.name === "ping") {
return await client.helpers.sendInteractionResponse(interaction.id, interaction.token, {
type: Discord.InteractionResponseTypes.ChannelMessageWithSource,
data: { content: "🏓 Pong!" },
});
}
},
},
intents: ["Guilds"],
token: config.token,
});
Discord.startBot(client);
```
The handling may see complicated in the beginning, but as mentioned before, we will introduce structures to make it
easier.

12
site/package-lock.json generated
View File

@@ -6140,9 +6140,9 @@
}
},
"node_modules/follow-redirects": {
"version": "1.14.7",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz",
"integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==",
"version": "1.14.8",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==",
"funding": [
{
"type": "individual",
@@ -17396,9 +17396,9 @@
}
},
"follow-redirects": {
"version": "1.14.7",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz",
"integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ=="
"version": "1.14.8",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA=="
},
"fork-ts-checker-webpack-plugin": {
"version": "6.5.0",

View File

@@ -0,0 +1,17 @@
const Channel = require("../Structures/Channel");
class Channels {
constructor(client, data = {}, options = {}) {
this.client = client;
if (options.guild) this.guild = options.guild;
}
async create(options = {}, reason) {
return new Channel(this.client, options).create(options, reason);
}
forge(data = {}) {
return new Channel(this.client, data);
}
}
module.exports = Channels;

View File

@@ -0,0 +1,136 @@
const resolveFolder = (folderName) => path.resolve(__dirname, ".", folderName);
const fs = require("fs");
const path = require("path");
class CommandManager {
constructor(client) {
this.client = client;
this.cache = new Map();
this.aliases = new Map();
}
load(options = {}) {
const commandFolderPath = options.path || "../Plugins";
const commandFolder = resolveFolder(commandFolderPath);
if (options.category === undefined) options.category = true;
if (options.plugins === undefined) options.plugins = true;
//PluginMode will iterate through all SubFolders
fs.readdirSync(commandFolder).map(async (dir) => {
if (dir.endsWith(".txt")) return;
if (!options.category && dir.endsWith(".js")) {
const commandPath = path.join(commandFolder, dir);
this.loadCommand(commandPath);
} else {
fs.readdirSync(path.join(commandFolder, dir)).map((cmd) => {
if (cmd.endsWith(".js") && !options.plugins) {
const commandPath = path.join(commandFolder, dir, cmd);
this.loadCommand(commandPath);
} else if (commandFolderPath === "../Plugins") {
if (cmd !== "commands") return;
fs.readdirSync(path.join(commandFolder, dir, cmd)).map((cmdfile) => {
if (!cmdfile.endsWith(".js")) return;
const commandPath = path.join(commandFolder, dir, cmd, cmdfile);
this.loadCommand(commandPath);
});
}
});
}
});
}
loadCommand(commandPath) {
const pull = require(path.join(commandPath));
if (pull.name) {
pull.path = commandPath;
this.cache.set(pull.name, pull);
}
if (pull.aliases) {
pull.aliases.map((p) => this.aliases.set(p, pull));
}
return pull;
}
reloadCommand(commandName) {
const command = this.cache.get(commandName);
if (!command) return;
const commandPath = path.join(command.path);
delete require.cache[require.resolve(commandPath)];
return this.loadCommand(commandPath);
}
isCommand(message) {
if (message.isBot) return false;
const prefix = "!";
const escapeRegex = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const prefixRegex = new RegExp(`^(<@!?${this.client.id}>|${escapeRegex(prefix)})\\s*`);
if (!prefixRegex.test(message.content)) return false;
const [, matchedPrefix] = message.content.match(prefixRegex);
const args = message.content.slice(matchedPrefix.length).trim().split(/ +/);
this.onMessage(message, prefix, args);
return true;
}
isInteraction(interaction) {
if (interaction.type !== 2) return;
this.onInteraction(interaction);
}
async onMessage(message, guild, args) {
const commandName = args.shift().toLowerCase();
const command = this.cache.get(commandName); //|| this.cache.find(cmd => cmd.aliases && cmd.aliases.includes(commandName));
if (!command && message.content.includes(this.client.id)) {
//Handle, when Command has not been found
const options = { content: "I did not found the Command!" };
this.client.helpers.sendMessage(message.channelId, options);
}
if (!command) return;
const messagecommand = new command({
manager: this,
message: message,
client: this.client,
args: args,
settings: {},
commandName: command.name,
});
messagecommand.execute()?.catch?.((error) => {
console.log(error);
// Call Function on CommandResponse.js, handle the error
return messagecommand.onError(error ?? "custom");
});
}
async onInteraction(interaction) {
const command = this.cache.get(interaction.data.name);
if (!command) return;
const args = [];
//Map all Values and Args
interaction.data.options.map((o) => {
if (o.name) args.push(o.name);
if (o.options) {
o.options.map((o2) => {
if (o2.value) return args.push(o2.value);
if (o2.name) args.push(o2.name);
if (o2.options) o2.options.map((v) => args.push(v.value));
});
}
});
const messagecommand = new command({
manager: this,
interaction: interaction,
client: this.client,
args: args,
settings: {},
commandName: command.name,
});
messagecommand.execute()?.catch?.((error) => {
console.log(error);
// Call Function on CommandResponse.js, handle the error
return messagecommand.onError(error ?? "custom");
});
}
}
module.exports = CommandManager;

View File

@@ -0,0 +1,32 @@
const fs = require("fs");
const path = require("path");
const resolveFolder = (folderName) => path.resolve(__dirname, ".", folderName);
const EventEmitter = require("events");
class EventManager extends EventEmitter {
constructor(client) {
super();
this.cache = new Map();
this._events = {};
}
load(options = {}) {
const eventsFolder = resolveFolder("../events");
fs.readdirSync(eventsFolder).map(async (file) => {
if (!file.endsWith(".js")) return;
const fileName = path.join(eventsFolder, file);
const event = require(fileName);
const eventName = file.split(".")[0];
this._events[`${eventName}`] = event;
/* When the event should be emitted on client.events.on(eventName, (...args) => {...})
this._events[`${eventName}`] = function(...args) {
this.emit(eventName, ...args);
return event(...args);
};
*/
});
return this._events;
}
}
module.exports = EventManager;

View File

@@ -0,0 +1,13 @@
const Member = require("../Structures/Member");
class Members {
constructor(client, data = {}, options = {}) {
this.client = client;
if (options.guild) this.guild = options.guild;
}
forge(data = {}) {
return new Member(this.client, data, { guild: this.guild });
}
}
module.exports = Members;

View File

@@ -0,0 +1,29 @@
const Role = require("../Structures/Role");
class Roles {
constructor(client, data = {}, options = {}) {
this.client = client;
if (options.member) this.member = options.member;
if (options.guild) this.guild = options.guild;
}
async create(options = {}, reason) {
return new Role(this.client, options).create(options, reason);
}
forge(data = {}) {
return new Roles(this.client, data);
}
async add(options = {}, reason) {
const guildId = (this.guild ? this.guild.id : options.guildId);
const memberId = (this.member ? this.member.id : options.memberId);
return this.client.helpers.addRole(guildId, memberId, options.roleId, reason);
}
async remove(options = {}, reason) {
const guildId = (this.guild ? this.guild.id : options.guildId);
const memberId = (this.member ? this.member.id : options.memberId);
return this.client.helpers.removeRole(guildId, memberId, options.roleId, reason);
}
}
module.exports = Roles;

View File

@@ -0,0 +1,49 @@
const BaseCommand = require("../../../Structures/BaseCommand.js");
const Embed = require("../../../Structures/Embed.js");
class evalcommand extends BaseCommand {
static name = "eval";
static description = "danger !!!";
static category = "Developer";
static slash = { name: "eval", category: "dev" };
constructor(data) {
super(data);
}
async execute() {
if (!this.client.config.owners.includes(String(this.user.id))) return;
if (!(this.args.length > 0)) return this.reply({ content: "**You must provide something to eval!**" });
let inputOfEval = this.args.join(" ");
let outputOfEval;
let typeOfEval;
try {
if (this.args.includes("await")) {
outputOfEval = await eval("(async () => {" + inputOfEval + "})()");
} else {
outputOfEval = await eval(inputOfEval);
}
} catch (e) {
outputOfEval = e.message;
typeOfEval = e.name;
}
var seen = [];
outputOfEval = typeof outputOfEval === "object"
? JSON.stringify(outputOfEval, (_, value) => {
if (value == `Bot ${this.client.config.token}`) return `BOT_TOKEN`;
if (typeof value === "bigint") value = value.toString();
if (typeof value === "object" && value !== null) {
if (seen.indexOf(value) !== -1) return;
else seen.push(value);
}
return value;
}, 1)
: outputOfEval;
const embed = new Embed()
.addField({ name: "Input", value: "```js\n" + inputOfEval + "```" })
.addField({ name: "Output", value: "```json\n" + `${outputOfEval}`.slice(0, 1000) + "```" });
this.reply({ embeds: [embed] });
}
}
module.exports = evalcommand;

View File

@@ -0,0 +1,19 @@
const BaseCommand = require("../../../Structures/BaseCommand.js");
const Embed = require("../../../Structures/Embed.js");
class reloadcommand extends BaseCommand {
static name = "reload";
static description = "Reloads a Command";
static category = "Developer";
static slash = { name: "reload", category: "dev" };
constructor(data) {
super(data);
}
async execute() {
if (!this.client.config.owners.includes(String(this.user.id))) return;
if (!this.args[0]) return this.reply({ content: "**You must provide a command to reload!**" });
const op = this.client.commands.reloadCommand(this.args[0]);
if (!op) return this.reply({ content: "**That command doesn't exist!**" });
return this.reply({ content: "**Reloaded Command: `" + this.args[0] + "`**" });
}
}
module.exports = reloadcommand;

View File

@@ -0,0 +1,24 @@
const BaseCommand = require("../../../Structures/BaseCommand.js");
const Embed = require("../../../Structures/Embed.js");
class pingcommand extends BaseCommand {
static name = "ping";
static description = "See if the bot latency is okay";
static usage = "";
static category = "General";
static slash = { name: "ping", category: "info" };
constructor(data) {
super(data);
}
async execute() {
const msg = await this.reply({ content: `Pinging...` });
//Assign properties to the response
const ping = msg.timestamp - this.message.timestamp;
const embed = new Embed()
.setTitle(`The Bots ping is ${ping} ms`)
.toJSON();
//Edit Message with the Embed
return msg.edit({ embeds: [embed] });
}
}
module.exports = pingcommand;

View File

View File

@@ -0,0 +1,40 @@
const BaseCommand = require("../../../Structures/BaseCommand.js");
const Component = require("../../../Structures/Component.js");
class bancommand extends BaseCommand {
static name = "ban";
static description = "Ban a user from the server";
static usage = "";
static category = "Moderation";
static slash = { name: "ban", category: "mod" };
constructor(data) {
super(data);
}
async execute() {
//Show Case Modal
// Because no permission system has not been added
if (!this.client.config.owners.includes(String(this.user.id))) return;
const textinput = new Component()
.setType("TEXT_INPUT")
.setStyle("SHORT")
.setCustomId("t1")
.setLabel("User ID")
.setPlaceholder("User ID")
.setRequired(true)
.setMaxLength(20)
.setMinLength(1)
.setValue(this.args[0])
.toJSON();
const textinput2 = new Component().setType("TEXT_INPUT").setStyle("PARAGRAPH").setCustomId("t2")
.setLabel("Reason").setPlaceholder("Reason for Ban").setRequired(false)
.setMaxLength(300).toJSON();
const actionrow = new Component().setType(1).setComponents(textinput).toJSON();
const actionrow2 = new Component().setType(1).setComponents(textinput2).toJSON();
this.interaction.popupModal({ customId: "ban_modal", title: "Ban User", components: [actionrow, actionrow2] });
}
}
module.exports = bancommand;

View File

@@ -0,0 +1,17 @@
const UtilCommand = require("./CommandResponse.js");
const Message = require("./Message.js");
const Interaction = require("./Interaction.js");
class BaseCommand extends UtilCommand {
constructor(data) {
super(data);
this.message = data.message && new Message(data.client, data.message);
this.interaction = data.interaction && new Interaction(data.client, data.interaction);
this.user = this.message ? this.message.author : this.interaction.user;
this.guild = this.message ? this.message.guild : this.interaction.guild;
this.member = this.message ? this.message.member : this.interaction.member;
this.channel = this.message ? this.message.channel : this.interaction.channel;
this.client = data.client;
this.settings = data.settings ?? {};
}
}
module.exports = BaseCommand;

View File

@@ -0,0 +1,29 @@
const DestructObject = require("./DestructObject");
const Guild = require("./Guild");
class Channel extends DestructObject {
constructor(client, channel = {}, options = {}) {
super(channel);
if (options.guild) this.guild = options.guild;
else if (channel.guildId) this.guild = new Guild(client, { id: channel.guildId });
this.client = client;
}
async create(options = {}, reason) {
return this.client.helpers.createChannel(this.guildId, options, reason);
}
async edit(options = {}, reason) {
return this.client.helpers.editChannel(this.id, options, reason);
}
async delete(reason) {
return this.client.helpers.deleteChannel(this.id, reason);
}
async send(options = {}) {
return this.client.helpers.sendMessage(this.id, options);
}
}
module.exports = Channel;

View File

@@ -0,0 +1,57 @@
const Message = require("./Message");
class Responses {
constructor(data) {
this.manager = data.manager;
this.args = this._validateArguments(data.args);
this.replied = false;
}
async reply(content) {
// When just a string is passed, we assume it's the content -> transform to correct formatted payload
if (typeof content === "string") content = { content };
if (this.interaction) {
if (this.replied) return this.followUp(content);
const reply = await this.interaction.reply(content);
//Assign properties to the response
const response = new Message(this.client, reply);
this.replied = true;
return response;
}
if (this.message) {
if (this.replied) return this.followUp(content);
const msg = await this.message.channel.send(content);
//Assign properties to the response
const response = new Message(this.client, msg);
this.replied = true;
return response;
}
}
async followUp(content) {
if (this.interaction) {
const reply = await this.interaction.followUp(content);
const response = new Message(this.client, reply);
return response;
}
if (this.message) {
const msg = await this.message.channel.send(content);
const response = new Message(this.client, msg);
return response;
}
}
onError(error) {
return this.reply({ content: `A unknown Error happend: \n> ${error}` });
}
_validateArguments(args) {
this.args = args;
return args;
}
}
module.exports = Responses;

View File

@@ -0,0 +1,171 @@
const Constants = {
PRIMARY: 1,
SECONDARY: 2,
SUCCESS: 3,
DANGER: 4,
LINK: 5,
SHORT: 1,
PARAGRAPH: 2,
ACTION_ROW: 1,
BUTTON: 2,
SELECT_MENU: 3,
TEXT_INPUT: 4,
};
class Component {
constructor(options = {}) {
this.type = options.type;
this.custom_id = options.custom_id ?? options.customId;
this.disabled = options.disabled;
this.style = options.style;
this.label = options.label;
this.emoji = options.emoji;
this.url = options.url;
//Select Menu
this.options = options.options;
this.placeholder = options.placeholder;
this.min_values = options.min_values ?? options.minValues;
this.max_values = options.max_values ?? options.maxValues;
//Action Row
this.components = options.components;
//Modal
this.value = options.value;
this.min_length = options.min_length ?? options.minLength;
this.max_length = options.max_length ?? options.maxLength;
this.required = options.required;
}
setType(type) {
if (typeof type === "string") {
this.type = Constants[type.toUpperCase()];
if (!this.type) throw new Error(`Invalid Component Type: ${type}`);
} else this.type = type;
return this;
}
setCustomId(custom_id) {
if (!this.url) this.custom_id = custom_id;
return this;
}
setDisabled(disabled) {
this.disabled = disabled;
return this;
}
setRequired(required) {
this.required = required;
return this;
}
setStyle(style) {
if (!this.url) {
if (typeof style === "string") {
this.style = Constants[style.toUpperCase()];
if (!this.style) throw new Error(`Invalid Button Style Type: ${type}`);
} else this.style = style;
}
return this;
}
setLabel(label) {
this.label = label;
return this;
}
setEmoji(emoji) {
this.emoji = emoji;
return this;
}
setUrl(url) {
this.url = url;
this.style = 5;
this.custom_id = undefined;
return this;
}
setOptions(options) {
this.options = options;
return this;
}
setValue(value) {
this.value = value;
return this;
}
setPlaceholder(placeholder) {
this.placeholder = placeholder;
return this;
}
setMinValues(min_values) {
this.min_values = min_values;
return this;
}
setMaxValues(max_values) {
this.max_values = max_values;
return this;
}
setMinLength(min_values) {
this.min_length = min_values;
return this;
}
setMaxLength(max_values) {
this.max_length = max_values;
return this;
}
setComponents(...components) {
this.components = components;
return this;
}
toJSON() {
if (!this.type) throw new Error("Component must have a type");
const json = {
type: this.type,
};
if (this.type === 1) {
json.components = this.components;
}
if (this.type === 2) {
json.customId = this.custom_id;
json.style = this.style;
json.label = this.label;
json.emoji = this.emoji;
json.url = this.url;
json.disabled = this.disabled;
}
if (this.type === 3) {
json.customId = this.custom_id;
json.options = this.options;
json.placeholder = this.placeholder;
json.minValues = this.min_values;
json.maxValues = this.max_values;
json.disabled = this.disabled;
}
if (this.type === 4) {
json.customId = this.custom_id;
json.style = this.style;
json.label = this.label;
json.minLength = this.min_length;
json.maxLength = this.max_length;
json.required = this.required;
json.value = this.value;
json.placeholder = this.placeholder;
}
return json;
}
}
module.exports = Component;

View File

@@ -0,0 +1,16 @@
class DestructObject {
constructor(message = {}) {
this.destructObject(message);
}
destructObject(message) {
for (let [key, value] of Object.entries(message)) {
this[key] = value;
}
return this;
}
toJSON() {
return { ...this };
}
}
module.exports = DestructObject;

View File

@@ -0,0 +1,99 @@
class Embed {
constructor(options = {}) {
this.title = options.title;
this.description = options.description;
this.fields = options.fields;
this.thumbnail = options.thumbnail;
this.image = options.image;
this.author = options.author;
this.color = options.color;
this.timestamp = options.timestamp;
this.footer = options.footer;
this.url = options.url;
this.fields = options.fields ?? [];
}
setTitle(title) {
this.title = title;
return this;
}
setDescription(description) {
this.description = description;
return this;
}
setThumbnail(thumbnail) {
this.thumbnail = thumbnail;
return this;
}
setImage(image) {
this.image = image;
return this;
}
setAuthor(author) {
if (typeof author !== "object") throw new Error("Author must be an object");
this.author = author;
return this;
}
setColor(color) {
this.color = color;
return this;
}
setTimestamp(timestamp) {
this.timestamp = timestamp ?? Date.now();
return this;
}
setFooter(footer) {
if (typeof footer !== "object") throw new Error("Footer must be an object");
this.footer = footer;
return this;
}
setURL(url) {
this.url = url;
return this;
}
addField(field) {
this.fields.push(field);
return this;
}
addFields(...fields) {
fields.map((x) => this.addField(x));
return this;
}
toJSON() {
return {
title: this.title,
type: "rich",
description: this.description,
color: this.color,
timestamp: this.timestamp ? new Date(this.timestamp).toISOString() : null,
thumbnail: this.thumbnail,
image: this.image,
fields: this.fields,
url: this.url,
author: this.author
? {
name: this.author.name,
url: this.author.url,
iconUrl: this.author.icon_url || this.author.iconUrl,
}
: null,
footer: this.footer
? {
text: this.footer.text,
iconUrl: this.footer.icon_url || this.footer.iconUrl,
}
: null,
};
}
}
module.exports = Embed;

View File

@@ -0,0 +1,18 @@
const DestructObject = require("./DestructObject");
const RoleManager = require("../Managers/RoleManager");
const MemberManager = require("../Managers/MemberManager");
const ChannelManager = require("../Managers/ChannelManager");
class Guild extends DestructObject {
constructor(client, guild = {}) {
super(guild);
this.client = client;
//Managers:
this.roles = new RoleManager(client, {}, { guild: this });
this.members = new MemberManager(client, {}, { guild: this });
this.channels = new ChannelManager(client, {}, { guild: this });
}
}
module.exports = Guild;

View File

@@ -0,0 +1,116 @@
const DestructObject = require("./DestructObject");
const Guild = require("./Guild");
const Channel = require("./Channel");
const Constants = {
DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE: 5,
CHANNEL_MESSAGE_WITH_SOURCE: 4,
DEFERRED_UPDATE_MESSAGE: 6,
UPDATE_MESSAGE: 7,
APPLICATION_COMMAND_AUTOCOMPLETE_RESULT: 8,
MODAL: 9,
FLAGS: { EPHEMERAL: 64 },
INTERACTION_TYPES: {
CHAT_INPUT: 1,
APPLICATION_COMMAND: 2,
CONTEXT_MENU: 2,
MESSAGE_COMPONENT: 3,
APPLICATION_COMMAND_AUTOCOMPLETE: 4,
},
};
class Interaction extends DestructObject {
constructor(client, interaction = {}) {
super(interaction);
this.raw = interaction;
this.client = client;
this.guild = new Guild(client, { id: this.guild_id || this.guildId });
this.channel = new Channel(client, { id: this.channel_id || this.channelId }, {
internal: true,
guild: this.guild,
});
}
isCommand() {
return this.type === Constants.INTERACTION_TYPES.APPLICATION_COMMAND;
}
// @todo check Context Menu type and Component Type
isChatInputCommand() {
return this.type === Constants.INTERACTION_TYPES.CHAT_INPUT;
}
isContextMenuCommand() {
return this.isCommand();
}
isAutoComplete() {
return this.type === Constants.INTERACTION_TYPES.APPLICATION_COMMAND_AUTOCOMPLETE;
}
isMessageComponent() {
return this.type === Constants.INTERACTION_TYPES.MESSAGE_COMPONENT;
}
isSelectMenu() {
return this.type === Constants.INTERACTION_TYPES.MESSAGE_COMPONENT;
}
isButton() {
return this.type === Constants.INTERACTION_TYPES.MESSAGE_COMPONENT;
}
async deferReply(options = {}) {
if (this.deferred || this.replied) throw new Error("Interaction has been already replied");
const Payload = { data: {}, type: Constants.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE };
options.type = 5;
if (this.ephemeral) options.private = true;
this.ephemeral = options.ephemeral || false;
this.deferred = true;
return this.client.helpers.sendInteractionResponse(this.id, this.token, options);
}
async deferUpdate(options = {}) {
if (this.deferred || this.replied) throw new Error("Interaction has been already replied");
this.deferred = true;
const Payload = { data: options, type: Constants.DEFERRED_UPDATE_MESSAGE };
return this.client.helpers.sendInteractionResponse(this.id, this.token, Payload);
}
async reply(options = {}) {
if (this.deferred || this.replied) throw new Error("Interaction has been already replied");
this.ephemeral = options.ephemeral || false;
if (this.ephemeral) options.private = true;
this.replied = true;
const Payload = { data: options, type: Constants.CHANNEL_MESSAGE_WITH_SOURCE };
return this.client.helpers.sendInteractionResponse(this.id, this.token, Payload);
}
async popupModal(options = {}) {
if (this.deferred || this.replied) throw new Error("Interaction has been already replied");
const Payload = { data: options, type: Constants.MODAL };
this.replied = true;
return this.client.helpers.sendInteractionResponse(this.id, this.token, Payload);
}
async editReply(options = {}) {
if (!this.deferred && !this.replied) throw new Error("Interaction has not been replied");
this.replied = true;
const messageId = this.messageId ? this.messageId : options.messageId;
return this.client.helpers.editInteractionResponse(this.token, options);
}
async deleteReply(options = {}) {
if (this.ephemeral) throw new Error("Ephemeral messages cannot be deleted");
const messageId = this.messageId ? this.messageId : options.messageId;
return this.client.helpers.deleteInteractionResponse(this.token, messageId);
}
async followUp(options = {}) {
if (!this.replied || !this.deferred) throw new Error("Interaction has not been replied");
const Payload = { data: options, type: Constants.CHANNEL_MESSAGE_WITH_SOURCE };
return this.client.helpers.sendInteractionResponse(this.id, this.token, Payload);
}
async update(options = {}) {
if (this.deferred || this.replied) throw new Error("Interaction has been already replied");
const Payload = { data: options, type: Constants.UPDATE_MESSAGE };
this.replied = true;
return this.client.helpers.sendInteractionResponse(this.id, this.token, Payload);
}
}
module.exports = Interaction;

View File

@@ -0,0 +1,16 @@
const DestructObject = require("./DestructObject");
const Guild = require("./Guild");
const RoleManager = require("../Managers/RoleManager");
class Member extends DestructObject {
constructor(client, member = {}, options = {}) {
super(member);
this.client = client;
if (options.guild) this.guild = options.guild;
else if (member.guildId) this.guild = new Guild(client, { id: member.guildId });
this.roles = new RoleManager(client, {}, { guild: this.guild, member: this });
}
}
module.exports = Member;

Some files were not shown because too many files have changed in this diff Show More