diff --git a/src/bot.ts b/src/bot.ts index 1b9820fae..1e1aaccd1 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -127,7 +127,7 @@ type CacheOptions = export function createBot( options: CreateBotOptions ): Bot { - return { + const bot = { id: options.botId, applicationId: options.applicationId || options.botId, token: `Bot ${options.token}`, @@ -138,9 +138,12 @@ export function createBot( activeGuildIds: new Set(), constants: createBotConstants(), handlers: createBotGatewayHandlers({}), - // @ts-ignore b quiet - cache: createCache(options?.cache?.isAsync ?? false, options?.cache?.customTableCreator), - } as unknown as Bot; + }; + + // @ts-ignore itoh cache types plz + bot.cache = createCache(bot as Bot, options.cache); + + return bot as unknown as Bot; } export function createEventHandlers(events: Partial): EventHandlers { @@ -261,12 +264,18 @@ export function createRestManager(options: CreateRestManagerOptions) { }; } -export async function startBot(bot: Bot) { - // SETUP +export function setupBot(bot: Bot) { bot.utils = createUtils({}); bot.transformers = createTransformers(bot.transformers || {}); bot.helpers = createHelpers(bot); + return bot; +} + +export async function startBot(bot: Bot) { + // SETUP BOT + bot = setupBot(bot); + // START REST bot.rest = createRestManager({ token: bot.token, debug: bot.events.debug }); if (!bot.botGatewayData) bot.botGatewayData = await bot.helpers.getGatewayBot(); @@ -643,8 +652,8 @@ export interface Helpers { leaveThread: typeof helpers.leaveThread; lockThread: typeof helpers.lockThread; removeThreadMember: typeof helpers.removeThreadMember; - startPrivateThread: typeof helpers.startPrivateThread; - startThread: typeof helpers.startThread; + startThreadWithoutMessage: typeof helpers.startThreadWithoutMessage; + startThreadWithMessage: typeof helpers.startThreadWithMessage; unarchiveThread: typeof helpers.unarchiveThread; unlockThread: typeof helpers.unlockThread; suppressEmbeds: typeof helpers.suppressEmbeds; @@ -818,8 +827,8 @@ export function createBaseHelpers(options: Partial) { leaveThread: options.leaveThread || helpers.leaveThread, lockThread: options.lockThread || helpers.lockThread, removeThreadMember: options.removeThreadMember || helpers.removeThreadMember, - startPrivateThread: options.startPrivateThread || helpers.startPrivateThread, - startThread: options.startThread || helpers.startThread, + startThreadWithoutMessage: options.startThreadWithoutMessage || helpers.startThreadWithoutMessage, + startThreadWithMessage: options.startThreadWithMessage || helpers.startThreadWithMessage, unarchiveThread: options.unarchiveThread || helpers.unarchiveThread, unlockThread: options.unlockThread || helpers.unlockThread, suppressEmbeds: options.suppressEmbeds || helpers.suppressEmbeds, diff --git a/src/cache.ts b/src/cache.ts index 887292fc7..e10b234b1 100644 --- a/src/cache.ts +++ b/src/cache.ts @@ -48,36 +48,40 @@ function channelSweeper(bot: Bot, channel: DiscordenoChannel, key: bigint } export function createCache( - isAsync: true, - // deno-lint-ignore no-explicit-any - tableCreator: (tableName: TableNames) => AsyncCacheHandler + bot: Bot, + options: { + isAsync: true; + tableCreator: (bot: Bot, tableName: TableNames) => AsyncCacheHandler; + } ): AsyncCache; export function createCache( - isAsync: false, - // deno-lint-ignore no-explicit-any - tableCreator?: (tableName: TableNames) => CacheHandler + bot: Bot, + options: { + isAsync: false; + tableCreator?: (bot: Bot, tableName: TableNames) => CacheHandler; + } ): Cache; export function createCache( - isAsync: boolean, - tableCreator?: ( - tableName: TableNames - // deno-lint-ignore no-explicit-any - ) => CacheHandler | AsyncCacheHandler + bot: Bot, + options: { + isAsync: boolean; + tableCreator?: (bot: Bot, tableName: TableNames) => CacheHandler | AsyncCacheHandler; + } ): Omit | Omit { - if (isAsync) { - if (!tableCreator) { + if (options.isAsync) { + if (!options.tableCreator) { throw new Error("Async cache requires a tableCreator to be passed."); } const cache = { - guilds: tableCreator("guilds"), - users: tableCreator("users"), - members: tableCreator("members"), - channels: tableCreator("channels"), - messages: tableCreator("messages"), - presences: tableCreator("presences"), - // threads: tableCreator("threads"), - unavailableGuilds: tableCreator("unavailableGuilds"), + guilds: options.tableCreator(bot, "guilds"), + users: options.tableCreator(bot, "users"), + members: options.tableCreator(bot, "members"), + channels: options.tableCreator(bot, "channels"), + messages: options.tableCreator(bot, "messages"), + presences: options.tableCreator(bot, "presences"), + // threads: options.tableCreator(bot, "threads"), + unavailableGuilds: options.tableCreator(bot, "unavailableGuilds"), executedSlashCommands: new Set(), fetchAllMembersProcessingRequests: new Map(), } as AsyncCache; @@ -88,17 +92,17 @@ export function createCache( return cache; } - if (!tableCreator) tableCreator = createTable; + if (!options.tableCreator) options.tableCreator = createTable; const cache = { - guilds: tableCreator("guilds"), - users: tableCreator("users"), - members: tableCreator("members"), - channels: tableCreator("channels"), - messages: tableCreator("messages"), - presences: tableCreator("presences"), - // threads: tableCreator("threads"), - unavailableGuilds: tableCreator("unavailableGuilds"), + guilds: options.tableCreator(bot, "guilds"), + users: options.tableCreator(bot, "users"), + members: options.tableCreator(bot, "members"), + channels: options.tableCreator(bot, "channels"), + messages: options.tableCreator(bot, "messages"), + presences: options.tableCreator(bot, "presences"), + // threads: options.tableCreator(bot, "threads"), + unavailableGuilds: options.tableCreator(bot, "unavailableGuilds"), executedSlashCommands: new Set(), fetchAllMembersProcessingRequests: new Map(), } as Cache; @@ -149,18 +153,18 @@ export interface AsyncCache { execute: CacheExecutor; } -function createTable(_table: TableNames): CacheHandler { +function createTable(bot: Bot, _table: TableNames): CacheHandler { const table = new Collection(); // @ts-ignore TODO: fix type error itoh pwease - if (_table === "guilds") table.startSweeper({ filter: guildSweeper, interval: 3660000 }); + if (_table === "guilds") table.startSweeper({ filter: guildSweeper, interval: 3660000, bot }); // @ts-ignore TODO: fix type error itoh pwease - if (_table === "channels") table.startSweeper({ filter: channelSweeper, interval: 3660000 }); + if (_table === "channels") table.startSweeper({ filter: channelSweeper, interval: 3660000, bot }); // @ts-ignore TODO: fix type error itoh pwease - if (_table === "messages") table.startSweeper({ filter: messageSweeper, interval: 300000 }); + if (_table === "messages") table.startSweeper({ filter: messageSweeper, interval: 300000, bot }); // @ts-ignore TODO: fix type error itoh pwease - if (_table === "members") table.startSweeper({ filter: memberSweeper, interval: 300000 }); - if (_table === "presences") table.startSweeper({ filter: () => true, interval: 300000 }); + if (_table === "members") table.startSweeper({ filter: memberSweeper, interval: 300000, bot }); + if (_table === "presences") table.startSweeper({ filter: () => true, interval: 300000, bot }); return { clear: () => table.clear(), diff --git a/src/helpers/messages/edit_message.ts b/src/helpers/messages/edit_message.ts index fbe11a469..b15c93708 100644 --- a/src/helpers/messages/edit_message.ts +++ b/src/helpers/messages/edit_message.ts @@ -88,10 +88,20 @@ export async function editMessage(bot: Bot, channelId: bigint, messageId: bigint })), allowed_mentions: { parse: content.allowedMentions?.parse, - roles: content.allowedMentions?.roles, - users: content.allowedMentions?.users, + roles: content.allowedMentions?.roles?.map((id) => id.toString()), + users: content.allowedMentions?.users?.map((id) => id.toString()), replied_user: content.allowedMentions?.repliedUser, }, + attachments: content.attachments?.map((attachment) => ({ + id: attachment.id.toString(), + filename: attachment.filename, + content_type: attachment.contentType, + size: attachment.size, + url: attachment.url, + proxy_url: attachment.proxyUrl, + height: attachment.height, + width: attachment.width, + })), file: content.file, components: content.components?.map((component) => ({ type: component.type, diff --git a/src/helpers/messages/send_message.ts b/src/helpers/messages/send_message.ts index 66d799a75..d17f1efe4 100644 --- a/src/helpers/messages/send_message.ts +++ b/src/helpers/messages/send_message.ts @@ -132,8 +132,8 @@ export async function sendMessage(bot: Bot, channelId: bigint, content: string | allowed_mentions: content.allowedMentions ? { parse: content.allowedMentions?.parse, - roles: content.allowedMentions?.roles, - users: content.allowedMentions?.users, + roles: content.allowedMentions?.roles?.map((id) => id.toString()), + users: content.allowedMentions?.users?.map((id) => id.toString()), replied_user: content.allowedMentions?.repliedUser, } : undefined, @@ -183,9 +183,9 @@ export async function sendMessage(bot: Bot, channelId: bigint, content: string | ...(content.messageReference?.messageId ? { message_reference: { - message_id: content.messageReference.messageId, - channel_id: content.messageReference.channelId, - guild_id: content.messageReference.guildId, + message_id: content.messageReference.messageId.toString(), + channel_id: content.messageReference.channelId?.toString(), + guild_id: content.messageReference.guildId?.toString(), fail_if_not_exists: content.messageReference.failIfNotExists === true, }, } diff --git a/src/helpers/mod.ts b/src/helpers/mod.ts index 0b70e3f2d..dec183c71 100644 --- a/src/helpers/mod.ts +++ b/src/helpers/mod.ts @@ -149,8 +149,8 @@ import { joinThread } from "./channels/threads/join_thread.ts"; import { leaveThread } from "./channels/threads/leave_thread.ts"; import { lockThread } from "./channels/threads/lock_thread.ts"; import { removeThreadMember } from "./channels/threads/remove_thread_member.ts"; -import { startPrivateThread } from "./channels/threads/start_private_thread.ts"; -import { startThread } from "./channels/threads/start_thread.ts"; +import { startThreadWithMessage } from "./channels/threads/startThreadWithMessage.ts"; +import { startThreadWithoutMessage } from "./channels/threads/startThreadWithoutMessage.ts"; import { unarchiveThread } from "./channels/threads/unarchive_thread.ts"; import { unlockThread } from "./channels/threads/unlock_thread.ts"; import { cloneChannel } from "./channels/clone_channel.ts"; @@ -309,8 +309,8 @@ export { leaveThread, lockThread, removeThreadMember, - startPrivateThread, - startThread, + startThreadWithMessage, + startThreadWithoutMessage, unarchiveThread, unlockThread, suppressEmbeds, diff --git a/src/types/messages/create_message.ts b/src/types/messages/create_message.ts index 73eaded32..ae8f1a2a2 100644 --- a/src/types/messages/create_message.ts +++ b/src/types/messages/create_message.ts @@ -13,9 +13,26 @@ export interface CreateMessage { /** Embedded `rich` content (up to 6000 characters) */ embeds?: Embed[]; /** Allowed mentions for the message */ - allowedMentions?: AllowedMentions; + allowedMentions?: Omit & { + /** Array of role_ids to mention (Max size of 100) */ + roles?: bigint[]; + /** Array of user_ids to mention (Max size of 100) */ + users?: bigint[]; + }; /** Include to make your message a reply */ - messageReference?: MessageReference; + messageReference?: { + /** id of the originating message */ + messageId?: bigint; + /** + * id of the originating message's channel + * Note: `channel_id` is optional when creating a reply, but will always be present when receiving an event/response that includes this data model. + */ + channelId?: bigint; + /** id of the originating message's guild */ + guildId?: bigint; + /** When sending, whether to error if the referenced message doesn't exist instead of sending as a normal (non-reply) message, default true */ + failIfNotExists: boolean; + }; /** The contents of the file being sent */ file?: FileContent | FileContent[]; /** The components you would like to have sent in this message */ diff --git a/src/types/messages/edit_message.ts b/src/types/messages/edit_message.ts index ac76bf263..34e7f4b28 100644 --- a/src/types/messages/edit_message.ts +++ b/src/types/messages/edit_message.ts @@ -15,9 +15,16 @@ export interface EditMessage { /** The contents of the file being sent/edited */ file?: FileContent | FileContent[] | null; /** Allowed mentions for the message */ - allowedMentions?: AllowedMentions | null; + allowedMentions?: + | (Omit & { + /** Array of role_ids to mention (Max size of 100) */ + roles?: bigint[]; + /** Array of user_ids to mention (Max size of 100) */ + users?: bigint[]; + }) + | null; /** Attached files to keep */ - attachments?: Attachment | null; + attachments?: Attachment[]; /** The components you would like to have sent in this message */ components?: MessageComponents; } diff --git a/src/util/dispatch_requirements.ts b/src/util/dispatch_requirements.ts index 72b99bea6..0f99169b8 100644 --- a/src/util/dispatch_requirements.ts +++ b/src/util/dispatch_requirements.ts @@ -6,8 +6,6 @@ import { SnakeCasedPropertiesDeep } from "../types/util.ts"; const processing = new Set(); export async function dispatchRequirements(bot: Bot, data: DiscordGatewayPayload, shardId: number) { - if (!bot.isReady) return; - // DELETE MEANS WE DONT NEED TO FETCH. CREATE SHOULD HAVE DATA TO CACHE if (data.t && ["GUILD_CREATE", "GUILD_DELETE"].includes(data.t)) return; @@ -19,11 +17,11 @@ export async function dispatchRequirements(bot: Bot, data: DiscordGatewayPayload (data.d as any)?.guild_id) ?? "" ); - if (!id || bot.activeGuildIds.has(id)) return; + if (!id || bot.cache.activeGuildIds.has(id)) return; // If this guild is in cache, it has not been swept and we can cancel if (await bot.cache.guilds.has(id)) { - bot.activeGuildIds.add(id); + bot.cache.activeGuildIds.add(id); return; }