diff --git a/src/events/channels.ts b/src/events/channels.ts index 721a7ddb0..38db306da 100644 --- a/src/events/channels.ts +++ b/src/events/channels.ts @@ -1,10 +1,10 @@ import { cache } from "../utils/cache.ts"; import { ChannelCreatePayload, ChannelTypes } from "../types/channel.ts"; -import { createChannel } from "../structures/channel.ts"; import { eventHandlers } from "../module/client.ts"; +import { structures } from "../structures/mod.ts"; export const handleInternalChannelCreate = (data: ChannelCreatePayload) => { - const channel = createChannel(data); + const channel = structures.createChannel(data); cache.channels.set(channel.id, channel); if (channel.guildID) { const guild = cache.guilds.get(channel.guildID); @@ -15,7 +15,7 @@ export const handleInternalChannelCreate = (data: ChannelCreatePayload) => { export const handleInternalChannelUpdate = (data: ChannelCreatePayload) => { const cachedChannel = cache.channels.get(data.id); - const channel = createChannel(data); + const channel = structures.createChannel(data); cache.channels.set(channel.id, channel); if (!cachedChannel) return; diff --git a/src/handlers/channel.ts b/src/handlers/channel.ts index 162ebe207..0f7b1a62e 100644 --- a/src/handlers/channel.ts +++ b/src/handlers/channel.ts @@ -8,7 +8,6 @@ import { Errors } from "../types/errors.ts"; import { RequestManager } from "../module/requestManager.ts"; import { endpoints } from "../constants/discord.ts"; import { MessageCreateOptions } from "../types/message.ts"; -import { createMessage } from "../structures/message.ts"; import { GetMessagesAfter, GetMessagesBefore, @@ -20,6 +19,7 @@ import { FollowedChannelPayload, } from "../types/channel.ts"; import { logYellow } from "../utils/logger.ts"; +import { structures } from "../structures/mod.ts"; /** Checks if a user id or a role id has permission in this channel */ export function hasChannelPermission( @@ -63,7 +63,7 @@ export async function getMessage(channel: Channel, id: string) { const result = await RequestManager.get( endpoints.CHANNEL_MESSAGE(channel.id, id), ) as MessageCreateOptions; - return createMessage(result); + return structures.createMessage(result); } /** Fetches between 2-100 messages. Requires VIEW_CHANNEL and READ_MESSAGE_HISTORY */ @@ -97,7 +97,7 @@ export async function getMessages( endpoints.CHANNEL_MESSAGES(channel.id), options, )) as MessageCreateOptions[]; - return result.map((res) => createMessage(res)); + return result.map((res) => structures.createMessage(res)); } /** Get pinned messages in this channel. */ @@ -105,7 +105,7 @@ export async function getPins(channelID: string) { const result = (await RequestManager.get( endpoints.CHANNEL_PINS(channelID), )) as MessageCreateOptions[]; - return result.map((res) => createMessage(res)); + return result.map((res) => structures.createMessage(res)); } /** Send a message to the channel. Requires SEND_MESSAGES permission. */ @@ -177,7 +177,7 @@ export async function sendMessage( }, ); - return createMessage(result as MessageCreateOptions); + return structures.createMessage(result as MessageCreateOptions); } /** Delete messages from the channel. 2-100. Requires the MANAGE_MESSAGES permission */ diff --git a/src/handlers/guild.ts b/src/handlers/guild.ts index 99b9dc71e..26ac56f4b 100644 --- a/src/handlers/guild.ts +++ b/src/handlers/guild.ts @@ -1,13 +1,8 @@ import { Guild } from "../structures/guild.ts"; -import { createChannel } from "../structures/channel.ts"; - import { formatImageURL } from "../utils/cdn.ts"; import { botHasPermission } from "../utils/permissions.ts"; - import { RequestManager } from "../module/requestManager.ts"; - import { endpoints } from "../constants/discord.ts"; - import { Errors } from "../types/errors.ts"; import { Permissions, Permission } from "../types/permission.ts"; import { @@ -32,15 +27,15 @@ import { UserPayload, } from "../types/guild.ts"; import { RoleData } from "../types/role.ts"; -import { createRole } from "../structures/role.ts"; import { Intents } from "../types/options.ts"; import { identifyPayload } from "../module/client.ts"; import { requestAllMembers } from "../module/shardingManager.ts"; import { MemberCreatePayload } from "../types/member.ts"; import { cache } from "../utils/cache.ts"; -import { createMember, Member } from "../structures/member.ts"; +import { Member } from "../structures/member.ts"; import { urlToBase64 } from "../utils/utils.ts"; import { Collection } from "../utils/collection.ts"; +import { structures } from "../structures/mod.ts"; /** Gets an array of all the channels ids that are the children of this category. */ export function categoryChildrenIDs(guild: Guild, id: string) { @@ -120,7 +115,7 @@ export async function createGuildChannel( type: options?.type || ChannelTypes.GUILD_TEXT, })) as ChannelCreatePayload; - const channel = createChannel(result); + const channel = structures.createChannel(result); guild.channels.set(result.id, channel); return channel; } @@ -147,7 +142,7 @@ export async function getChannels(guildID: string, addToCache = true) { endpoints.GUILD_CHANNELS(guildID), ) as ChannelCreatePayload[]; return result.map((res) => { - const channel = createChannel(res, guildID); + const channel = structures.createChannel(res, guildID); if (addToCache) { cache.channels.set(channel.id, channel); } @@ -163,7 +158,7 @@ export async function getChannel(channelID: string, addToCache = true) { const result = await RequestManager.get( endpoints.GUILD_CHANNEL(channelID), ) as ChannelCreatePayload; - const channel = createChannel(result, result.guild_id); + const channel = structures.createChannel(result, result.guild_id); if (addToCache) cache.channels.set(channel.id, channel); return channel; } @@ -194,7 +189,7 @@ export async function getMember(guildID: string, id: string) { endpoints.GUILD_MEMBER(guildID, id), ) as MemberCreatePayload; - const member = createMember(data, guild); + const member = structures.createMember(data, guild); guild.members.set(id, member); return member; } @@ -300,7 +295,7 @@ export async function createGuildRole( ); const roleData = result as RoleData; - const role = createRole(roleData); + const role = structures.createRole(roleData); const guild = cache.guilds.get(guildID); guild?.roles.set(role.id, role); return role; diff --git a/src/handlers/member.ts b/src/handlers/member.ts index b1b3bf6ac..93707e598 100644 --- a/src/handlers/member.ts +++ b/src/handlers/member.ts @@ -13,9 +13,9 @@ import { Errors } from "../types/errors.ts"; import { RequestManager } from "../module/requestManager.ts"; import { MessageContent, DMChannelCreatePayload } from "../types/channel.ts"; import { cache } from "../utils/cache.ts"; -import { createChannel } from "../structures/channel.ts"; import { EditMemberOptions } from "../types/member.ts"; import { sendMessage } from "./channel.ts"; +import { structures } from "../structures/mod.ts"; /** The users custom avatar or the default avatar if you don't have a member object. */ export function rawAvatarURL( @@ -108,7 +108,7 @@ export async function sendDirectMessage( ) as DMChannelCreatePayload; // Channel create event will have added this channel to the cache cache.channels.delete(dmChannelData.id); - const channel = createChannel(dmChannelData); + const channel = structures.createChannel(dmChannelData); // Recreate the channel and add it undert he users id cache.channels.set(memberID, channel); dmChannel = channel; diff --git a/src/handlers/message.ts b/src/handlers/message.ts index dcc34b664..811ec3703 100644 --- a/src/handlers/message.ts +++ b/src/handlers/message.ts @@ -1,4 +1,4 @@ -import { Message, createMessage } from "../structures/message.ts"; +import { Message } from "../structures/message.ts"; import { delay } from "https://deno.land/std@0.67.0/async/delay.ts"; import { botID } from "../module/client.ts"; import { Permissions } from "../types/permission.ts"; @@ -9,6 +9,7 @@ import { botHasChannelPermissions } from "../utils/permissions.ts"; import { MessageContent } from "../types/channel.ts"; import { UserPayload } from "../types/guild.ts"; import { MessageCreateOptions } from "../types/message.ts"; +import { structures } from "../structures/mod.ts"; /** Delete a message */ export async function deleteMessage( @@ -221,7 +222,7 @@ export async function editMessage( endpoints.CHANNEL_MESSAGE(message.channelID, message.id), content, ); - return createMessage(result as MessageCreateOptions); + return structures.createMessage(result as MessageCreateOptions); } export async function publishMessage(channelID: string, messageID: string) { @@ -229,5 +230,5 @@ export async function publishMessage(channelID: string, messageID: string) { endpoints.CHANNEL_MESSAGE_CROSSPOST(channelID, messageID), ) as MessageCreateOptions; - return createMessage(data); + return structures.createMessage(data); } diff --git a/src/handlers/webhook.ts b/src/handlers/webhook.ts index e7e57517f..4cfab57b0 100644 --- a/src/handlers/webhook.ts +++ b/src/handlers/webhook.ts @@ -8,9 +8,9 @@ import { Permissions } from "../types/permission.ts"; import { Errors } from "../types/errors.ts"; import { RequestManager } from "../module/requestManager.ts"; import { endpoints } from "../constants/discord.ts"; -import { createMessage } from "../structures/message.ts"; import { MessageCreateOptions } from "../types/message.ts"; import { urlToBase64 } from "../utils/utils.ts"; +import { structures } from "../structures/mod.ts"; /** Create a new webhook. Requires the MANAGE_WEBHOOKS permission. Returns a webhook object on success. Webhook names follow our naming restrictions that can be found in our Usernames and Nicknames documentation, with the following additional stipulations: * @@ -98,7 +98,7 @@ export async function executeWebhook( ); if (!options.wait) return; - return createMessage(result as MessageCreateOptions); + return structures.createMessage(result as MessageCreateOptions); } export function getWebhook(webhookID: string) { diff --git a/src/module/shardingManager.ts b/src/module/shardingManager.ts index b540e929a..879d73bbe 100644 --- a/src/module/shardingManager.ts +++ b/src/module/shardingManager.ts @@ -23,7 +23,7 @@ import { handleInternalChannelDelete, } from "../events/channels.ts"; import { ChannelCreatePayload } from "../types/channel.ts"; -import { createGuild, Guild } from "../structures/guild.ts"; +import { Guild } from "../structures/guild.ts"; import { CreateGuildPayload, GuildDeletePayload, @@ -43,8 +43,6 @@ import { handleInternalGuildDelete, } from "../events/guilds.ts"; import { cache } from "../utils/cache.ts"; -import { createMember } from "../structures/member.ts"; -import { createRole } from "../structures/role.ts"; import { MessageCreateOptions, MessageDeletePayload, @@ -53,7 +51,6 @@ import { BaseMessageReactionPayload, MessageReactionRemoveEmojiPayload, } from "../types/message.ts"; -import { createMessage } from "../structures/message.ts"; import { GuildUpdateChange } from "../types/options.ts"; import { createBasicShard, @@ -61,6 +58,7 @@ import { botGatewayStatusRequest, } from "./basicShard.ts"; import { BotStatusRequest } from "../utils/utils.ts"; +import { structures } from "../structures/mod.ts"; let shardCounter = 0; let basicSharding = false; @@ -176,7 +174,10 @@ export async function handleDiscordPayload( return; } - const guild = createGuild(data.d as CreateGuildPayload, shardID); + const guild = structures.createGuild( + data.d as CreateGuildPayload, + shardID, + ); handleInternalGuildCreate(guild); if (cache.unavailableGuilds.get(options.id)) { cache.unavailableGuilds.delete(options.id); @@ -278,7 +279,7 @@ export async function handleDiscordPayload( const memberCount = guild.memberCount + 1; guild.memberCount = memberCount; - const member = createMember( + const member = structures.createMember( options, guild, ); @@ -318,7 +319,7 @@ export async function handleDiscordPayload( deaf: cachedMember?.deaf || false, mute: cachedMember?.mute || false, }; - const member = createMember( + const member = structures.createMember( newMemberData, guild, ); @@ -357,7 +358,7 @@ export async function handleDiscordPayload( options.members.forEach((member) => { guild.members.set( member.user.id, - createMember( + structures.createMember( member, guild, ), @@ -398,7 +399,7 @@ export async function handleDiscordPayload( if (!guild) return; if (data.t === "GUILD_ROLE_CREATE") { - const role = createRole(options.role); + const role = structures.createRole(options.role); const roles = guild.roles.set(options.role.id, role); guild.roles = roles; return eventHandlers.roleCreate?.(guild, role); @@ -408,7 +409,7 @@ export async function handleDiscordPayload( if (!cachedRole) return; if (data.t === "GUILD_ROLE_UPDATE") { - const role = createRole(options.role); + const role = structures.createRole(options.role); return eventHandlers.roleUpdate?.(guild, role, cachedRole); } } @@ -418,7 +419,7 @@ export async function handleDiscordPayload( const channel = cache.channels.get(options.channel_id); if (channel) channel.lastMessageID = options.id; - const message = createMessage(options); + const message = structures.createMessage(options); // Cache the message cache.messages.set(options.id, message); const guild = options.guild_id @@ -429,7 +430,7 @@ export async function handleDiscordPayload( // If in a guild cache the author as a member guild?.members.set( options.author.id, - createMember( + structures.createMember( { ...options.member, user: options.author }, guild, ), @@ -441,7 +442,10 @@ export async function handleDiscordPayload( if (mention.member) { guild?.members.set( mention.id, - createMember({ ...mention.member, user: mention }, guild), + structures.createMember( + { ...mention.member, user: mention }, + guild, + ), ); } }); @@ -533,7 +537,7 @@ export async function handleDiscordPayload( const guild = cache.guilds.get(options.guild_id); guild?.members.set( options.member.user.id, - createMember( + structures.createMember( options.member, guild, ), @@ -608,7 +612,9 @@ export async function handleDiscordPayload( if (!guild) return; const member = guild.members.get(payload.user_id) || - (payload.member ? createMember(payload.member, guild) : undefined); + (payload.member + ? structures.createMember(payload.member, guild) + : undefined); if (!member) return; // No cached state before so lets make one for em diff --git a/src/structures/guild.ts b/src/structures/guild.ts index 765537faa..1abee8ad0 100644 --- a/src/structures/guild.ts +++ b/src/structures/guild.ts @@ -1,10 +1,9 @@ import { CreateGuildPayload } from "../types/guild.ts"; import { Collection } from "../utils/collection.ts"; -import { createRole } from "./role.ts"; -import { createMember, Member } from "./member.ts"; -import { createChannel } from "./channel.ts"; +import { structures } from "./mod.ts"; +import { Member } from "./member.ts"; -export const createGuild = (data: CreateGuildPayload, shardID: number) => { +export function createGuild(data: CreateGuildPayload, shardID: number) { const { owner_id: ownerID, afk_channel_id: afkChannelID, @@ -60,14 +59,16 @@ export const createGuild = (data: CreateGuildPayload, shardID: number) => { preferredLocale, /** The roles in the guild */ - roles: new Collection(data.roles.map((r) => [r.id, createRole(r)])), + roles: new Collection( + data.roles.map((r) => [r.id, structures.createRole(r)]), + ), /** When this guild was joined at. */ joinedAt: Date.parse(joinedAt), /** The users in this guild. */ members: new Collection(), /** The channels in the guild */ channels: new Collection( - data.channels.map((c) => [c.id, createChannel(c, data.id)]), + data.channels.map((c) => [c.id, structures.createChannel(c, data.id)]), ), /** The presences of all the users in the guild. */ presences: new Collection(data.presences.map((p) => [p.user.id, p])), @@ -87,10 +88,10 @@ export const createGuild = (data: CreateGuildPayload, shardID: number) => { }; data.members.forEach((m) => - guild.members.set(m.user.id, createMember(m, guild)) + guild.members.set(m.user.id, structures.createMember(m, guild)) ); return guild; -}; +} export interface Guild extends ReturnType {} diff --git a/src/structures/member.ts b/src/structures/member.ts index 4fea2a48d..c781262a2 100644 --- a/src/structures/member.ts +++ b/src/structures/member.ts @@ -1,16 +1,27 @@ import { MemberCreatePayload } from "../types/member.ts"; import { Guild } from "./guild.ts"; -import { cache } from "../utils/cache.ts"; -export const createMember = (data: MemberCreatePayload, guild: Guild) => { +export function createMember(data: MemberCreatePayload, guild: Guild) { + const { + joined_at: joinedAt, + premium_since: premiumSince, + ...rest + } = data; + + const { + mfa_enabled: mfaEnabled, + premium_type: premiumType, + ...user + } = data.user; + const member = { - ...data, + ...rest, + // Only use those that we have not removed above + user: user, /** When the user joined the guild */ - joinedAt: Date.parse(data.joined_at), + joinedAt: Date.parse(joinedAt), /** When the user used their nitro boost on the server. */ - premiumSince: data.premium_since - ? Date.parse(data.premium_since) - : undefined, + premiumSince: premiumSince ? Date.parse(premiumSince) : undefined, /** The full username#discriminator */ tag: `${data.user.username}#${data.user.discriminator}`, /** The user mention with nickname if possible */ @@ -18,20 +29,11 @@ export const createMember = (data: MemberCreatePayload, guild: Guild) => { /** The guild id where this member exists */ guildID: guild.id, /** Whether or not this user has 2FA enabled. */ - mfaEnabled: data.user.mfa_enabled, + mfaEnabled, /** The premium type for this user */ - premiumType: data.user.premium_type, - - /** Gets the guild object from cache for this member. This is a method instead of a prop to preserve memory. */ - guild: () => cache.guilds.get(guild.id)!, + premiumType, }; - // Remove excess properties to preserve cache. - // delete member.joined_at; - // delete member.premium_since; - // delete member.user.mfa_enabled; - // delete member.user.premium_type; - return member; }; diff --git a/src/structures/mod.ts b/src/structures/mod.ts new file mode 100644 index 000000000..d7c60460f --- /dev/null +++ b/src/structures/mod.ts @@ -0,0 +1,27 @@ +import { createChannel } from "./channel.ts"; +import { createGuild } from "./guild.ts"; +import { createMember } from "./member.ts"; +import { createMessage } from "./message.ts"; +import { createRole } from "./role.ts"; + +/** This is the placeholder where the structure creation functions are kept. */ +export let structures = { + createChannel, + createGuild, + createMember, + createMessage, + createRole, +}; + +export type Structures = typeof structures[keyof typeof structures]; + +/** This function is used to update/reload/customize the internal structure of Discordeno. + * + * ⚠️ **ADVANCED USE ONLY: If you customize this in a wrong way, you could potentially create many new errors/bugs. Please take caution when using this. +*/ +export function updateStructures(newStructures: Structures) { + structures = { + ...structures, + ...newStructures, + }; +} diff --git a/src/structures/role.ts b/src/structures/role.ts index e8e6a4574..550286534 100644 --- a/src/structures/role.ts +++ b/src/structures/role.ts @@ -1,9 +1,11 @@ import { RoleData } from "../types/role.ts"; -export const createRole = (data: RoleData) => ({ - ...data, - /** The @ mention of the role in a string. */ - mention: `<@&${data.id}>`, -}); +export function createRole(data: RoleData) { + return { + ...data, + /** The @ mention of the role in a string. */ + mention: `<@&${data.id}>`, + }; +} export interface Role extends ReturnType {}