diff --git a/src/bot.ts b/src/bot.ts index b548fd107..4d677671f 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -128,7 +128,7 @@ type CacheOptions = export function createBot( options: CreateBotOptions ): Bot { - return { + const bot = { id: options.botId, applicationId: options.applicationId || options.botId, token: `Bot ${options.token}`, @@ -139,9 +139,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 { @@ -226,6 +229,7 @@ export function createRestManager(options: CreateRestManagerOptions) { token: `${options.token.startsWith("Bot ") ? "" : "Bot "}${options.token}`, maxRetryCount: options.maxRetryCount || 10, secretKey: options.secretKey || "discordeno_best_lib_ever", + customUrl: options.customUrl || "", pathQueues: new Map< string, { @@ -261,12 +265,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 +653,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 +828,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, @@ -849,7 +859,7 @@ export interface Transformers { thread: typeof transformThread; webhook: typeof transformWebhook; auditlogEntry: typeof transformAuditlogEntry; - applicationCommandPermission: typeof transformApplicationCommandPermission + applicationCommandPermission: typeof transformApplicationCommandPermission; } export function createTransformers(options: Partial) { @@ -876,7 +886,7 @@ export function createTransformers(options: Partial) { snowflake: options.snowflake || snowflakeToBigint, webhook: options.webhook || transformWebhook, auditlogEntry: options.auditlogEntry || transformAuditlogEntry, - applicationCommandPermission: transformApplicationCommandPermission + applicationCommandPermission: transformApplicationCommandPermission, }; } diff --git a/src/cache.ts b/src/cache.ts index a801c086f..a2d576b4c 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/channels/clone_channel.ts b/src/helpers/channels/clone_channel.ts index 27f770a76..2e2da197e 100644 --- a/src/helpers/channels/clone_channel.ts +++ b/src/helpers/channels/clone_channel.ts @@ -29,8 +29,6 @@ export async function cloneChannel(bot: Bot, channelId: bigint, reason?: string) }), }; - - //Create the channel (also handles permissions) return await bot.helpers.createChannel(channelToClone.guildId!, createChannelOptions, reason); } diff --git a/src/helpers/channels/threads/get_active_threads.ts b/src/helpers/channels/threads/get_active_threads.ts index a484a6b1e..ca6335099 100644 --- a/src/helpers/channels/threads/get_active_threads.ts +++ b/src/helpers/channels/threads/get_active_threads.ts @@ -4,7 +4,7 @@ import { Collection } from "../../../util/collection.ts"; // import { channelToThread } from "../../../util/transformers/channel_to_thread.ts"; /** Returns all active threads in the guild, including public and private threads. Threads are ordered by their `id`, in descending order. */ -export async function getActiveThreads(bot: Bot, guildId: bigint) { +export async function getActiveThreads(bot: Bot, guildId: bigint) { // const result = (await bot.rest.runMethod( // bot.rest, // "get", diff --git a/src/helpers/channels/threads/startThreadWithMessage.ts b/src/helpers/channels/threads/startThreadWithMessage.ts index 73bc0a1c7..7acba11e5 100644 --- a/src/helpers/channels/threads/startThreadWithMessage.ts +++ b/src/helpers/channels/threads/startThreadWithMessage.ts @@ -3,7 +3,12 @@ import type { StartThreadWithMessage } from "../../../types/channels/threads/sta import type { Bot } from "../../../bot.ts"; /** Creates a new public thread from an existing message. Returns a thread channel. */ -export async function startThreadWithMessage(bot: Bot, channelId: bigint, messageId: bigint, options: StartThreadWithMessage) { +export async function startThreadWithMessage( + bot: Bot, + channelId: bigint, + messageId: bigint, + options: StartThreadWithMessage +) { // const channel = await bot.cache.channels.get(channelId); // if (channel) { // if (!channel.isGuildTextBasedChannel) { 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/rest/simplify_url.ts b/src/rest/simplify_url.ts index 4e3078f40..aee44d102 100644 --- a/src/rest/simplify_url.ts +++ b/src/rest/simplify_url.ts @@ -9,7 +9,7 @@ export function simplifyUrl(url: string, method: string) { .replace(/\/([a-z-]+)\/(?:[0-9]{17,19})/g, function (match, p) { return ["channels", "guilds"].includes(p) ? match : `/${p}/skillzPrefersID`; }) - .replace(/\/reactions\/[^/]+/g, "/reactions/skillzPrefersID") + .replace(/\/reactions\/[^/]+/g, "/reactions/skillzPrefersID"); // GENERAL /reactions and /reactions/emoji/@me share the buckets if (route.includes("/reactions")) { diff --git a/src/transformers/auditlogEntry.ts b/src/transformers/auditlogEntry.ts index f2dab6df5..8530b3419 100644 --- a/src/transformers/auditlogEntry.ts +++ b/src/transformers/auditlogEntry.ts @@ -21,11 +21,11 @@ export function transformAuditlogEntry( key: change.key, new: { id: bot.transformers.snowflake(change.new_value.id!), - name: change.new_value.name + name: change.new_value.name, }, old: { id: bot.transformers.snowflake(change.old_value.id!), - name: change.old_value.name + name: change.old_value.name, }, }; case "discovery_splash_hash": diff --git a/src/transformers/channel.ts b/src/transformers/channel.ts index 812731a77..1696487b5 100644 --- a/src/transformers/channel.ts +++ b/src/transformers/channel.ts @@ -26,9 +26,9 @@ function unpack64(v: bigint, shift: number) { return (v >> BigInt(shift * 64)) & Mask; } function pack64(v: string | number, shift: number) { - const b = BigInt(v); - if(b < 0 || b > Mask) throw new Error("should have been a 64 bit unsigned integer: " + v); - return b << BigInt(shift * 64) + const b = BigInt(v); + if (b < 0 || b > Mask) throw new Error("should have been a 64 bit unsigned integer: " + v); + return b << BigInt(shift * 64); } export function separate(v: bigint) { return [Number(unpack64(v, 3)), unpack64(v, 2), unpack64(v, 0), unpack64(v, 1)] as [number, bigint, bigint, bigint]; diff --git a/src/types/audit_log/audit_log_change.ts b/src/types/audit_log/audit_log_change.ts index 176a986a3..c5f321410 100644 --- a/src/types/audit_log/audit_log_change.ts +++ b/src/types/audit_log/audit_log_change.ts @@ -66,7 +66,17 @@ export type AuditLogChange = | { newValue: boolean; oldValue: boolean; - key: "widget_enabled" | "nsfw" | "hoist" | "mentionable" | "temporary" | "deaf" | "mute" | "enable_emoticons" | "archived" | "locked"; + key: + | "widget_enabled" + | "nsfw" + | "hoist" + | "mentionable" + | "temporary" + | "deaf" + | "mute" + | "enable_emoticons" + | "archived" + | "locked"; } | { newValue: Overwrite[]; diff --git a/src/types/channels/threads/start_thread.ts b/src/types/channels/threads/start_thread.ts index e68e66280..807ea7b51 100644 --- a/src/types/channels/threads/start_thread.ts +++ b/src/types/channels/threads/start_thread.ts @@ -17,7 +17,10 @@ export interface StartThreadWithMessage extends StartThreadBase { export interface StartThreadWithoutMessage extends StartThreadBase { /** the type of thread to create */ - type: DiscordChannelTypes.GuildNewsThread | DiscordChannelTypes.GuildPublicThread | DiscordChannelTypes.GuildPrivateThread; + type: + | DiscordChannelTypes.GuildNewsThread + | DiscordChannelTypes.GuildPublicThread + | DiscordChannelTypes.GuildPrivateThread; /** whether non-moderators can add other non-moderators to a thread; only available when creating a private thread */ invitable?: boolean; -} \ No newline at end of file +} diff --git a/src/types/channels/threads/thread_members_update.ts b/src/types/channels/threads/thread_members_update.ts index 1a01fd2cc..eafe9c275 100644 --- a/src/types/channels/threads/thread_members_update.ts +++ b/src/types/channels/threads/thread_members_update.ts @@ -29,4 +29,3 @@ export interface ThreadMembersUpdateModified extends ThreadMembersUpdateBase { // TODO: verify this // \* In this gateway event, the thread member objects will also include the [guild member](#DOCS_RESOURCES_GUILD/guild-member-object) and [presence](#DOCS_TOPICS_GATEWAY/presence) objects for each added thread member. } - 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/tests/helpers/channels/categoryChannels.ts b/tests/helpers/channels/categoryChannels.ts index 9e80cd3d7..28db31648 100644 --- a/tests/helpers/channels/categoryChannels.ts +++ b/tests/helpers/channels/categoryChannels.ts @@ -35,8 +35,12 @@ export async function categoryChildrenTest(bot: Bot, guildId: bigint, t: Deno.Te const ids = await bot.helpers.categoryChildren(category.id); if (ids.size !== channels.length || !channels.every((c) => ids.has(c.id))) { - console.log('cccc 1', ids.size, channels.length); - console.log('cccc 2', channels.every((c) => ids.has(c.id)), ids); + console.log("cccc 1", ids.size, channels.length); + console.log( + "cccc 2", + channels.every((c) => ids.has(c.id)), + ids + ); throw new Error("The category channel ids did not match with the category channels."); } } diff --git a/tests/mod.ts b/tests/mod.ts index ad6f99956..49d5f9288 100644 --- a/tests/mod.ts +++ b/tests/mod.ts @@ -575,18 +575,18 @@ Deno.test({ name: "[channel] delete a channel overwrite", async fn() { await deleteChannelOverwriteTests(bot, guild.id, t); - } + }, }), t.step({ name: "[channel] edit a channel w/o a reason", async fn() { await editChannelTests(bot, guild.id, {}, t); - } + }, }), t.step({ name: "[channel] edit a channel w/ a reason", async fn() { - await editChannelTests(bot, guild.id, { reason: "Blame wolf"}, t); + await editChannelTests(bot, guild.id, { reason: "Blame wolf" }, t); }, }), ]);