Merge branch 'master' of https://github.com/Skillz4Killz/Discordeno into inline-replies

This commit is contained in:
Skillz
2020-11-16 22:39:04 -05:00
14 changed files with 617 additions and 120 deletions
+5
View File
@@ -93,6 +93,11 @@ export let cacheHandlers = {
return cache[table].has(key); return cache[table].has(key);
}, },
/** Get the number of key-value pairs */
size: async (table: TableName) => {
return cache[table].size;
},
// Done differently to have overloads // Done differently to have overloads
/** Add a key value pair to the cache */ /** Add a key value pair to the cache */
set, set,
+1 -1
View File
@@ -1,4 +1,3 @@
import { endpoints } from "../constants/discord.ts";
import { cacheHandlers } from "../controllers/cache.ts"; import { cacheHandlers } from "../controllers/cache.ts";
import { RequestManager } from "../module/requestManager.ts"; import { RequestManager } from "../module/requestManager.ts";
import { structures } from "../structures/mod.ts"; import { structures } from "../structures/mod.ts";
@@ -17,6 +16,7 @@ import { Errors } from "../types/errors.ts";
import { RawOverwrite } from "../types/guild.ts"; import { RawOverwrite } from "../types/guild.ts";
import { MessageCreateOptions } from "../types/message.ts"; import { MessageCreateOptions } from "../types/message.ts";
import { Permissions } from "../types/permission.ts"; import { Permissions } from "../types/permission.ts";
import { endpoints } from "../utils/constants.ts";
import { botHasChannelPermissions } from "../utils/permissions.ts"; import { botHasChannelPermissions } from "../utils/permissions.ts";
/** Checks if a channel overwrite for a user id or a role id has permission in this channel */ /** Checks if a channel overwrite for a user id or a role id has permission in this channel */
+252 -91
View File
@@ -1,4 +1,3 @@
import { endpoints } from "../constants/discord.ts";
import { cacheHandlers } from "../controllers/cache.ts"; import { cacheHandlers } from "../controllers/cache.ts";
import { identifyPayload } from "../module/client.ts"; import { identifyPayload } from "../module/client.ts";
import { RequestManager } from "../module/requestManager.ts"; import { RequestManager } from "../module/requestManager.ts";
@@ -6,6 +5,7 @@ import { requestAllMembers } from "../module/shardingManager.ts";
import { Guild } from "../structures/guild.ts"; import { Guild } from "../structures/guild.ts";
import { Member } from "../structures/member.ts"; import { Member } from "../structures/member.ts";
import { structures } from "../structures/mod.ts"; import { structures } from "../structures/mod.ts";
import { Template } from "../structures/template.ts";
import { ImageFormats, ImageSize } from "../types/cdn.ts"; import { ImageFormats, ImageSize } from "../types/cdn.ts";
import { ChannelCreatePayload, ChannelTypes } from "../types/channel.ts"; import { ChannelCreatePayload, ChannelTypes } from "../types/channel.ts";
import { Errors } from "../types/errors.ts"; import { Errors } from "../types/errors.ts";
@@ -14,13 +14,18 @@ import {
BanOptions, BanOptions,
ChannelCreateOptions, ChannelCreateOptions,
CreateEmojisOptions, CreateEmojisOptions,
CreateGuildFromTemplate,
CreateGuildPayload,
CreateGuildTemplate,
CreateRoleOptions, CreateRoleOptions,
CreateServerOptions, CreateServerOptions,
EditEmojisOptions, EditEmojisOptions,
EditGuildTemplate,
EditIntegrationOptions, EditIntegrationOptions,
FetchMembersOptions, FetchMembersOptions,
GetAuditLogsOptions, GetAuditLogsOptions,
GuildEditOptions, GuildEditOptions,
GuildTemplate,
PositionSwap, PositionSwap,
PruneOptions, PruneOptions,
PrunePayload, PrunePayload,
@@ -33,6 +38,7 @@ import { Permissions } from "../types/permission.ts";
import { RoleData } from "../types/role.ts"; import { RoleData } from "../types/role.ts";
import { formatImageURL } from "../utils/cdn.ts"; import { formatImageURL } from "../utils/cdn.ts";
import { Collection } from "../utils/collection.ts"; import { Collection } from "../utils/collection.ts";
import { endpoints } from "../utils/constants.ts";
import { botHasPermission, calculateBits } from "../utils/permissions.ts"; import { botHasPermission, calculateBits } from "../utils/permissions.ts";
import { urlToBase64 } from "../utils/utils.ts"; import { urlToBase64 } from "../utils/utils.ts";
@@ -98,7 +104,11 @@ export async function createGuildChannel(
name: string, name: string,
options?: ChannelCreateOptions, options?: ChannelCreateOptions,
) { ) {
if (!botHasPermission(guild.id, [Permissions.MANAGE_CHANNELS])) { const hasPerm = await botHasPermission(
guild.id,
[Permissions.MANAGE_CHANNELS],
);
if (!hasPerm) {
throw new Error(Errors.MISSING_MANAGE_CHANNELS); throw new Error(Errors.MISSING_MANAGE_CHANNELS);
} }
@@ -127,12 +137,16 @@ export async function createGuildChannel(
} }
/** Delete a channel in your server. Bot needs MANAGE_CHANNEL permissions in the server. */ /** Delete a channel in your server. Bot needs MANAGE_CHANNEL permissions in the server. */
export function deleteChannel( export async function deleteChannel(
guildID: string, guildID: string,
channelID: string, channelID: string,
reason?: string, reason?: string,
) { ) {
if (!botHasPermission(guildID, [Permissions.MANAGE_CHANNELS])) { const hasPerm = await botHasPermission(
guildID,
[Permissions.MANAGE_CHANNELS],
);
if (!hasPerm) {
throw new Error(Errors.MISSING_MANAGE_CHANNELS); throw new Error(Errors.MISSING_MANAGE_CHANNELS);
} }
@@ -224,9 +238,8 @@ export async function createEmoji(
image: string, image: string,
options: CreateEmojisOptions, options: CreateEmojisOptions,
) { ) {
if ( const hasPerm = await botHasPermission(guildID, [Permissions.MANAGE_EMOJIS]);
!botHasPermission(guildID, [Permissions.MANAGE_EMOJIS]) if (!hasPerm) {
) {
throw new Error(Errors.MISSING_MANAGE_EMOJIS); throw new Error(Errors.MISSING_MANAGE_EMOJIS);
} }
@@ -242,16 +255,16 @@ export async function createEmoji(
} }
/** Modify the given emoji. Requires the MANAGE_EMOJIS permission. */ /** Modify the given emoji. Requires the MANAGE_EMOJIS permission. */
export function editEmoji( export async function editEmoji(
guildID: string, guildID: string,
id: string, id: string,
options: EditEmojisOptions, options: EditEmojisOptions,
) { ) {
if ( const hasPerm = await botHasPermission(guildID, [Permissions.MANAGE_EMOJIS]);
!botHasPermission(guildID, [Permissions.MANAGE_EMOJIS]) if (!hasPerm) {
) {
throw new Error(Errors.MISSING_MANAGE_EMOJIS); throw new Error(Errors.MISSING_MANAGE_EMOJIS);
} }
return RequestManager.patch(endpoints.GUILD_EMOJI(guildID, id), { return RequestManager.patch(endpoints.GUILD_EMOJI(guildID, id), {
name: options.name, name: options.name,
roles: options.roles, roles: options.roles,
@@ -259,12 +272,16 @@ export function editEmoji(
} }
/** Delete the given emoji. Requires the MANAGE_EMOJIS permission. Returns 204 No Content on success. */ /** Delete the given emoji. Requires the MANAGE_EMOJIS permission. Returns 204 No Content on success. */
export function deleteEmoji(guildID: string, id: string, reason?: string) { export async function deleteEmoji(
if ( guildID: string,
!botHasPermission(guildID, [Permissions.MANAGE_EMOJIS]) id: string,
) { reason?: string,
) {
const hasPerm = await botHasPermission(guildID, [Permissions.MANAGE_EMOJIS]);
if (!hasPerm) {
throw new Error(Errors.MISSING_MANAGE_EMOJIS); throw new Error(Errors.MISSING_MANAGE_EMOJIS);
} }
return RequestManager.delete( return RequestManager.delete(
endpoints.GUILD_EMOJI(guildID, id), endpoints.GUILD_EMOJI(guildID, id),
{ reason }, { reason },
@@ -282,11 +299,11 @@ export async function createGuildRole(
options: CreateRoleOptions, options: CreateRoleOptions,
reason?: string, reason?: string,
) { ) {
if ( const hasPerm = await botHasPermission(guildID, [Permissions.MANAGE_ROLES]);
!botHasPermission(guildID, [Permissions.MANAGE_ROLES]) if (!hasPerm) {
) {
throw new Error(Errors.MISSING_MANAGE_ROLES); throw new Error(Errors.MISSING_MANAGE_ROLES);
} }
const result = await RequestManager.post( const result = await RequestManager.post(
endpoints.GUILD_ROLES(guildID), endpoints.GUILD_ROLES(guildID),
{ {
@@ -308,16 +325,16 @@ export async function createGuildRole(
} }
/** Edit a guild role. Requires the MANAGE_ROLES permission. */ /** Edit a guild role. Requires the MANAGE_ROLES permission. */
export function editRole( export async function editRole(
guildID: string, guildID: string,
id: string, id: string,
options: CreateRoleOptions, options: CreateRoleOptions,
) { ) {
if ( const hasPerm = await botHasPermission(guildID, [Permissions.MANAGE_ROLES]);
!botHasPermission(guildID, [Permissions.MANAGE_ROLES]) if (!hasPerm) {
) {
throw new Error(Errors.MISSING_MANAGE_ROLES); throw new Error(Errors.MISSING_MANAGE_ROLES);
} }
return RequestManager.patch(endpoints.GUILD_ROLE(guildID, id), { return RequestManager.patch(endpoints.GUILD_ROLE(guildID, id), {
...options, ...options,
permissions: options.permissions permissions: options.permissions
@@ -327,12 +344,12 @@ export function editRole(
} }
/** Delete a guild role. Requires the MANAGE_ROLES permission. */ /** Delete a guild role. Requires the MANAGE_ROLES permission. */
export function deleteRole(guildID: string, id: string) { export async function deleteRole(guildID: string, id: string) {
if ( const hasPerm = await botHasPermission(guildID, [Permissions.MANAGE_ROLES]);
!botHasPermission(guildID, [Permissions.MANAGE_ROLES]) if (!hasPerm) {
) {
throw new Error(Errors.MISSING_MANAGE_ROLES); throw new Error(Errors.MISSING_MANAGE_ROLES);
} }
return RequestManager.delete(endpoints.GUILD_ROLE(guildID, id)); return RequestManager.delete(endpoints.GUILD_ROLE(guildID, id));
} }
@@ -340,22 +357,22 @@ export function deleteRole(guildID: string, id: string) {
* *
* ⚠️ **If you need this, you are probably doing something wrong. This is not intended for use. Your roles will be cached in your guild.** * ⚠️ **If you need this, you are probably doing something wrong. This is not intended for use. Your roles will be cached in your guild.**
*/ */
export function getRoles(guildID: string) { export async function getRoles(guildID: string) {
if ( const hasPerm = await botHasPermission(guildID, [Permissions.MANAGE_ROLES]);
!botHasPermission(guildID, [Permissions.MANAGE_ROLES]) if (!hasPerm) {
) {
throw new Error(Errors.MISSING_MANAGE_ROLES); throw new Error(Errors.MISSING_MANAGE_ROLES);
} }
return RequestManager.get(endpoints.GUILD_ROLES(guildID)); return RequestManager.get(endpoints.GUILD_ROLES(guildID));
} }
/** Modify the positions of a set of role objects for the guild. Requires the MANAGE_ROLES permission. */ /** Modify the positions of a set of role objects for the guild. Requires the MANAGE_ROLES permission. */
export function swapRoles(guildID: string, rolePositons: PositionSwap) { export async function swapRoles(guildID: string, rolePositons: PositionSwap) {
if ( const hasPerm = await botHasPermission(guildID, [Permissions.MANAGE_ROLES]);
!botHasPermission(guildID, [Permissions.MANAGE_ROLES]) if (!hasPerm) {
) {
throw new Error(Errors.MISSING_MANAGE_ROLES); throw new Error(Errors.MISSING_MANAGE_ROLES);
} }
return RequestManager.patch(endpoints.GUILD_ROLES(guildID), rolePositons); return RequestManager.patch(endpoints.GUILD_ROLES(guildID), rolePositons);
} }
@@ -364,9 +381,9 @@ export async function getPruneCount(guildID: string, options: PruneOptions) {
if (options.days < 1) { if (options.days < 1) {
throw new Error(Errors.PRUNE_MIN_DAYS); throw new Error(Errors.PRUNE_MIN_DAYS);
} }
if (
!botHasPermission(guildID, [Permissions.KICK_MEMBERS]) const hasPerm = await botHasPermission(guildID, [Permissions.KICK_MEMBERS]);
) { if (!hasPerm) {
throw new Error(Errors.MISSING_KICK_MEMBERS); throw new Error(Errors.MISSING_KICK_MEMBERS);
} }
@@ -379,13 +396,13 @@ export async function getPruneCount(guildID: string, options: PruneOptions) {
} }
/** Begin pruning all members in the given time period */ /** Begin pruning all members in the given time period */
export function pruneMembers(guildID: string, options: PruneOptions) { export async function pruneMembers(guildID: string, options: PruneOptions) {
if (options.days < 1) { if (options.days < 1) {
throw new Error(Errors.PRUNE_MIN_DAYS); throw new Error(Errors.PRUNE_MIN_DAYS);
} }
if (
!botHasPermission(guildID, [Permissions.KICK_MEMBERS]) const hasPerm = await botHasPermission(guildID, [Permissions.KICK_MEMBERS]);
) { if (!hasPerm) {
throw new Error(Errors.MISSING_KICK_MEMBERS); throw new Error(Errors.MISSING_KICK_MEMBERS);
} }
@@ -406,8 +423,12 @@ export function fetchMembers(guild: Guild, options?: FetchMembersOptions) {
} }
/** Returns the audit logs for the guild. Requires VIEW AUDIT LOGS permission */ /** Returns the audit logs for the guild. Requires VIEW AUDIT LOGS permission */
export function getAuditLogs(guildID: string, options: GetAuditLogsOptions) { export async function getAuditLogs(
if (!botHasPermission(guildID, [Permissions.VIEW_AUDIT_LOG])) { guildID: string,
options: GetAuditLogsOptions,
) {
const hasPerm = await botHasPermission(guildID, [Permissions.VIEW_AUDIT_LOG]);
if (!hasPerm) {
throw new Error(Errors.MISSING_VIEW_AUDIT_LOG); throw new Error(Errors.MISSING_VIEW_AUDIT_LOG);
} }
@@ -420,26 +441,26 @@ export function getAuditLogs(guildID: string, options: GetAuditLogsOptions) {
} }
/** Returns the guild embed object. Requires the MANAGE_GUILD permission. */ /** Returns the guild embed object. Requires the MANAGE_GUILD permission. */
export function getEmbed(guildID: string) { export async function getEmbed(guildID: string) {
if ( const hasPerm = await botHasPermission(guildID, [Permissions.MANAGE_GUILD]);
!botHasPermission(guildID, [Permissions.MANAGE_GUILD]) if (!hasPerm) {
) {
throw new Error(Errors.MISSING_MANAGE_GUILD); throw new Error(Errors.MISSING_MANAGE_GUILD);
} }
return RequestManager.get(endpoints.GUILD_EMBED(guildID)); return RequestManager.get(endpoints.GUILD_EMBED(guildID));
} }
/** Modify a guild embed object for the guild. Requires the MANAGE_GUILD permission. */ /** Modify a guild embed object for the guild. Requires the MANAGE_GUILD permission. */
export function editEmbed( export async function editEmbed(
guildID: string, guildID: string,
enabled: boolean, enabled: boolean,
channelID?: string | null, channelID?: string | null,
) { ) {
if ( const hasPerm = await botHasPermission(guildID, [Permissions.MANAGE_GUILD]);
!botHasPermission(guildID, [Permissions.MANAGE_GUILD]) if (!hasPerm) {
) {
throw new Error(Errors.MISSING_MANAGE_GUILD); throw new Error(Errors.MISSING_MANAGE_GUILD);
} }
return RequestManager.patch( return RequestManager.patch(
endpoints.GUILD_EMBED(guildID), endpoints.GUILD_EMBED(guildID),
{ enabled, channel_id: channelID }, { enabled, channel_id: channelID },
@@ -452,26 +473,26 @@ export function getVanityURL(guildID: string) {
} }
/** Returns a list of integrations for the guild. Requires the MANAGE_GUILD permission. */ /** Returns a list of integrations for the guild. Requires the MANAGE_GUILD permission. */
export function getIntegrations(guildID: string) { export async function getIntegrations(guildID: string) {
if ( const hasPerm = await botHasPermission(guildID, [Permissions.MANAGE_GUILD]);
!botHasPermission(guildID, [Permissions.MANAGE_GUILD]) if (!hasPerm) {
) {
throw new Error(Errors.MISSING_MANAGE_GUILD); throw new Error(Errors.MISSING_MANAGE_GUILD);
} }
return RequestManager.get(endpoints.GUILD_INTEGRATIONS(guildID)); return RequestManager.get(endpoints.GUILD_INTEGRATIONS(guildID));
} }
/** Modify the behavior and settings of an integration object for the guild. Requires the MANAGE_GUILD permission. */ /** Modify the behavior and settings of an integration object for the guild. Requires the MANAGE_GUILD permission. */
export function editIntegration( export async function editIntegration(
guildID: string, guildID: string,
id: string, id: string,
options: EditIntegrationOptions, options: EditIntegrationOptions,
) { ) {
if ( const hasPerm = await botHasPermission(guildID, [Permissions.MANAGE_GUILD]);
!botHasPermission(guildID, [Permissions.MANAGE_GUILD]) if (!hasPerm) {
) {
throw new Error(Errors.MISSING_MANAGE_GUILD); throw new Error(Errors.MISSING_MANAGE_GUILD);
} }
return RequestManager.patch( return RequestManager.patch(
endpoints.GUILD_INTEGRATION(guildID, id), endpoints.GUILD_INTEGRATION(guildID, id),
options, options,
@@ -479,30 +500,29 @@ export function editIntegration(
} }
/** Delete the attached integration object for the guild with this id. Requires MANAGE_GUILD permission. */ /** Delete the attached integration object for the guild with this id. Requires MANAGE_GUILD permission. */
export function deleteIntegration(guildID: string, id: string) { export async function deleteIntegration(guildID: string, id: string) {
if ( const hasPerm = await botHasPermission(guildID, [Permissions.MANAGE_GUILD]);
!botHasPermission(guildID, [Permissions.MANAGE_GUILD]) if (!hasPerm) {
) {
throw new Error(Errors.MISSING_MANAGE_GUILD); throw new Error(Errors.MISSING_MANAGE_GUILD);
} }
return RequestManager.delete(endpoints.GUILD_INTEGRATION(guildID, id)); return RequestManager.delete(endpoints.GUILD_INTEGRATION(guildID, id));
} }
/** Sync an integration. Requires the MANAGE_GUILD permission. */ /** Sync an integration. Requires the MANAGE_GUILD permission. */
export function syncIntegration(guildID: string, id: string) { export async function syncIntegration(guildID: string, id: string) {
if ( const hasPerm = await botHasPermission(guildID, [Permissions.MANAGE_GUILD]);
!botHasPermission(guildID, [Permissions.MANAGE_GUILD]) if (!hasPerm) {
) {
throw new Error(Errors.MISSING_MANAGE_GUILD); throw new Error(Errors.MISSING_MANAGE_GUILD);
} }
return RequestManager.post(endpoints.GUILD_INTEGRATION_SYNC(guildID, id)); return RequestManager.post(endpoints.GUILD_INTEGRATION_SYNC(guildID, id));
} }
/** Returns a list of ban objects for the users banned from this guild. Requires the BAN_MEMBERS permission. */ /** Returns a list of ban objects for the users banned from this guild. Requires the BAN_MEMBERS permission. */
export async function getBans(guildID: string) { export async function getBans(guildID: string) {
if ( const hasPerm = await botHasPermission(guildID, [Permissions.BAN_MEMBERS]);
!botHasPermission(guildID, [Permissions.BAN_MEMBERS]) if (!hasPerm) {
) {
throw new Error(Errors.MISSING_BAN_MEMBERS); throw new Error(Errors.MISSING_BAN_MEMBERS);
} }
@@ -516,10 +536,9 @@ export async function getBans(guildID: string) {
} }
/** Returns a ban object for the given user or a 404 not found if the ban cannot be found. Requires the BAN_MEMBERS permission. */ /** Returns a ban object for the given user or a 404 not found if the ban cannot be found. Requires the BAN_MEMBERS permission. */
export function getBan(guildID: string, memberID: string) { export async function getBan(guildID: string, memberID: string) {
if ( const hasPerm = await botHasPermission(guildID, [Permissions.BAN_MEMBERS]);
!botHasPermission(guildID, [Permissions.BAN_MEMBERS]) if (!hasPerm) {
) {
throw new Error(Errors.MISSING_BAN_MEMBERS); throw new Error(Errors.MISSING_BAN_MEMBERS);
} }
@@ -529,10 +548,9 @@ export function getBan(guildID: string, memberID: string) {
} }
/** Ban a user from the guild and optionally delete previous messages sent by the user. Requires the BAN_MEMBERS permission. */ /** Ban a user from the guild and optionally delete previous messages sent by the user. Requires the BAN_MEMBERS permission. */
export function ban(guildID: string, id: string, options: BanOptions) { export async function ban(guildID: string, id: string, options: BanOptions) {
if ( const hasPerm = await botHasPermission(guildID, [Permissions.BAN_MEMBERS]);
!botHasPermission(guildID, [Permissions.BAN_MEMBERS]) if (!hasPerm) {
) {
throw new Error(Errors.MISSING_BAN_MEMBERS); throw new Error(Errors.MISSING_BAN_MEMBERS);
} }
@@ -543,10 +561,9 @@ export function ban(guildID: string, id: string, options: BanOptions) {
} }
/** Remove the ban for a user. REquires BAN_MEMBERS permission */ /** Remove the ban for a user. REquires BAN_MEMBERS permission */
export function unban(guildID: string, id: string) { export async function unban(guildID: string, id: string) {
if ( const hasPerm = await botHasPermission(guildID, [Permissions.BAN_MEMBERS]);
!botHasPermission(guildID, [Permissions.BAN_MEMBERS]) if (!hasPerm) {
) {
throw new Error(Errors.MISSING_BAN_MEMBERS); throw new Error(Errors.MISSING_BAN_MEMBERS);
} }
return RequestManager.delete(endpoints.GUILD_BAN(guildID, id)); return RequestManager.delete(endpoints.GUILD_BAN(guildID, id));
@@ -554,9 +571,8 @@ export function unban(guildID: string, id: string) {
/** Modify a guilds settings. Requires the MANAGE_GUILD permission. */ /** Modify a guilds settings. Requires the MANAGE_GUILD permission. */
export async function editGuild(guildID: string, options: GuildEditOptions) { export async function editGuild(guildID: string, options: GuildEditOptions) {
if ( const hasPerm = await botHasPermission(guildID, [Permissions.MANAGE_GUILD]);
!botHasPermission(guildID, [Permissions.MANAGE_GUILD]) if (!hasPerm) {
) {
throw new Error(Errors.MISSING_MANAGE_GUILD); throw new Error(Errors.MISSING_MANAGE_GUILD);
} }
@@ -576,12 +592,12 @@ export async function editGuild(guildID: string, options: GuildEditOptions) {
} }
/** Get all the invites for this guild. Requires MANAGE_GUILD permission */ /** Get all the invites for this guild. Requires MANAGE_GUILD permission */
export function getInvites(guildID: string) { export async function getInvites(guildID: string) {
if ( const hasPerm = await botHasPermission(guildID, [Permissions.MANAGE_GUILD]);
!botHasPermission(guildID, [Permissions.MANAGE_GUILD]) if (!hasPerm) {
) {
throw new Error(Errors.MISSING_MANAGE_GUILD); throw new Error(Errors.MISSING_MANAGE_GUILD);
} }
return RequestManager.get(endpoints.GUILD_INVITES(guildID)); return RequestManager.get(endpoints.GUILD_INVITES(guildID));
} }
@@ -596,8 +612,12 @@ export function getVoiceRegions(guildID: string) {
} }
/** Returns a list of guild webhooks objects. Requires the MANAGE_WEBHOOKs permission. */ /** Returns a list of guild webhooks objects. Requires the MANAGE_WEBHOOKs permission. */
export function getWebhooks(guildID: string) { export async function getWebhooks(guildID: string) {
if (!botHasPermission(guildID, [Permissions.MANAGE_WEBHOOKS])) { const hasPerm = await botHasPermission(
guildID,
[Permissions.MANAGE_WEBHOOKS],
);
if (!hasPerm) {
throw new Error(Errors.MISSING_MANAGE_WEBHOOKS); throw new Error(Errors.MISSING_MANAGE_WEBHOOKS);
} }
@@ -622,3 +642,144 @@ export function getGuild(guildID: string, counts = true) {
{ with_counts: counts }, { with_counts: counts },
) as Promise<UpdateGuildPayload>; ) as Promise<UpdateGuildPayload>;
} }
/** Returns the guild template if it exists */
export function getGuildTemplate(
guildID: string,
templateCode: string,
) {
return RequestManager.get(
`${endpoints.GUILD_TEMPLATES(guildID)}/${templateCode}`,
) as Promise<Template>;
}
/**
* Create a new guild based on a template
* NOTE: This endpoint can be used only by bots in less than 10 guilds.
*/
export async function createGuildFromTemplate(
templateCode: string,
data: CreateGuildFromTemplate,
) {
if (await cacheHandlers.size("guilds") >= 10) {
throw new Error(
"This function can only be used by bots in less than 10 guilds.",
);
}
if (data.icon) {
data.icon = await urlToBase64(data.icon);
}
const guild = await RequestManager.post(
endpoints.GUILD_TEMPLATE(templateCode),
data,
) as Promise<CreateGuildPayload>;
return guild;
}
/**
* Returns an array of templates.
* Requires the `MANAGE_GUILD` permission.
*/
export async function getGuildTemplates(guildID: string) {
const hasPerm = await botHasPermission(guildID, [Permissions.MANAGE_GUILD]);
if (!hasPerm) throw new Error(Errors.MISSING_MANAGE_GUILD);
const templates = await RequestManager.get(
endpoints.GUILD_TEMPLATES(guildID),
) as GuildTemplate[];
return templates.map((template) => structures.createTemplate(template));
}
/**
* Deletes a template from a guild.
* Requires the `MANAGE_GUILD` permission.
*/
export async function deleteGuildTemplate(
guildID: string,
templateCode: string,
) {
const hasPerm = await botHasPermission(guildID, [Permissions.MANAGE_GUILD]);
if (!hasPerm) throw new Error(Errors.MISSING_MANAGE_GUILD);
const deletedTemplate = await RequestManager.delete(
`${endpoints.GUILD_TEMPLATES(guildID)}/${templateCode}`,
) as GuildTemplate;
return structures.createTemplate(deletedTemplate);
}
/**
* Creates a template for the guild.
* Requires the `MANAGE_GUILD` permission.
* @param name name of the template (1-100 characters)
* @param description description for the template (0-120 characters
*/
export async function createGuildTemplate(
guildID: string,
data: CreateGuildTemplate,
) {
const hasPerm = await botHasPermission(guildID, [Permissions.MANAGE_GUILD]);
if (!hasPerm) throw new Error(Errors.MISSING_MANAGE_GUILD);
if (data.name.length < 1 || data.name.length > 100) {
throw new Error("The name can only be in between 1-100 characters.");
}
if (
data.description?.length &&
data.description.length > 120
) {
throw new Error("The description can only be in between 0-120 characters.");
}
const template = await RequestManager.post(
endpoints.GUILD_TEMPLATES(guildID),
data,
) as GuildTemplate;
return structures.createTemplate(template);
}
/**
* Syncs the template to the guild's current state.
* Requires the `MANAGE_GUILD` permission.
*/
export async function syncGuildTemplate(guildID: string, templateCode: string) {
const hasPerm = await botHasPermission(guildID, [Permissions.MANAGE_GUILD]);
if (!hasPerm) throw new Error(Errors.MISSING_MANAGE_GUILD);
const template = await RequestManager.put(
`${endpoints.GUILD_TEMPLATES(guildID)}/${templateCode}`,
) as GuildTemplate;
return structures.createTemplate(template);
}
/**
* Edit a template's metadata.
* Requires the `MANAGE_GUILD` permission.
*/
export async function editGuildTemplate(
guildID: string,
templateCode: string,
data: EditGuildTemplate,
) {
const hasPerm = await botHasPermission(guildID, [Permissions.MANAGE_GUILD]);
if (!hasPerm) throw new Error(Errors.MISSING_MANAGE_GUILD);
if (data.name?.length && (data.name.length < 1 || data.name.length > 100)) {
throw new Error("The name can only be in between 1-100 characters.");
}
if (
data.description?.length &&
data.description.length > 120
) {
throw new Error("The description can only be in between 0-120 characters.");
}
const template = await RequestManager.patch(
`${endpoints.GUILD_TEMPLATES(guildID)}/${templateCode}`,
data,
) as GuildTemplate;
return structures.createTemplate(template);
}
+50 -19
View File
@@ -1,4 +1,3 @@
import { endpoints } from "../constants/discord.ts";
import { cacheHandlers } from "../controllers/cache.ts"; import { cacheHandlers } from "../controllers/cache.ts";
import { botID } from "../module/client.ts"; import { botID } from "../module/client.ts";
import { RequestManager } from "../module/requestManager.ts"; import { RequestManager } from "../module/requestManager.ts";
@@ -10,6 +9,7 @@ import { Errors } from "../types/errors.ts";
import { EditMemberOptions } from "../types/member.ts"; import { EditMemberOptions } from "../types/member.ts";
import { Permissions } from "../types/permission.ts"; import { Permissions } from "../types/permission.ts";
import { formatImageURL } from "../utils/cdn.ts"; import { formatImageURL } from "../utils/cdn.ts";
import { endpoints } from "../utils/constants.ts";
import { import {
botHasPermission, botHasPermission,
higherRolePosition, higherRolePosition,
@@ -54,14 +54,19 @@ export async function addRole(
reason?: string, reason?: string,
) { ) {
const botsHighestRole = await highestRole(guildID, botID); const botsHighestRole = await highestRole(guildID, botID);
if ( if (botsHighestRole) {
botsHighestRole && const hasHigherRolePosition = await higherRolePosition(
!higherRolePosition(guildID, botsHighestRole.id, roleID) guildID,
) { botsHighestRole.id,
throw new Error(Errors.BOTS_HIGHEST_ROLE_TOO_LOW); roleID,
);
if (!hasHigherRolePosition) {
throw new Error(Errors.BOTS_HIGHEST_ROLE_TOO_LOW);
}
} }
if (!botHasPermission(guildID, [Permissions.MANAGE_ROLES])) { const hasPerm = await botHasPermission(guildID, [Permissions.MANAGE_ROLES]);
if (!hasPerm) {
throw new Error(Errors.MISSING_MANAGE_ROLES); throw new Error(Errors.MISSING_MANAGE_ROLES);
} }
@@ -79,16 +84,23 @@ export async function removeRole(
reason?: string, reason?: string,
) { ) {
const botsHighestRole = await highestRole(guildID, botID); const botsHighestRole = await highestRole(guildID, botID);
if (
botsHighestRole && if (botsHighestRole) {
!higherRolePosition(guildID, botsHighestRole.id, roleID) const hasHigherRolePosition = await higherRolePosition(
) { guildID,
throw new Error(Errors.BOTS_HIGHEST_ROLE_TOO_LOW); botsHighestRole.id,
roleID,
);
if (!hasHigherRolePosition) {
throw new Error(Errors.BOTS_HIGHEST_ROLE_TOO_LOW);
}
} }
if (!botHasPermission(guildID, [Permissions.MANAGE_ROLES])) { const hasPerm = await botHasPermission(guildID, [Permissions.MANAGE_ROLES]);
if (!hasPerm) {
throw new Error(Errors.MISSING_MANAGE_ROLES); throw new Error(Errors.MISSING_MANAGE_ROLES);
} }
return RequestManager.delete( return RequestManager.delete(
endpoints.GUILD_MEMBER_ROLE(guildID, memberID, roleID), endpoints.GUILD_MEMBER_ROLE(guildID, memberID, roleID),
{ reason }, { reason },
@@ -130,9 +142,11 @@ export async function kick(guildID: string, memberID: string, reason?: string) {
throw new Error(Errors.BOTS_HIGHEST_ROLE_TOO_LOW); throw new Error(Errors.BOTS_HIGHEST_ROLE_TOO_LOW);
} }
if (!botHasPermission(guildID, [Permissions.KICK_MEMBERS])) { const hasPerm = await botHasPermission(guildID, [Permissions.KICK_MEMBERS]);
if (!hasPerm) {
throw new Error(Errors.MISSING_KICK_MEMBERS); throw new Error(Errors.MISSING_KICK_MEMBERS);
} }
return RequestManager.delete( return RequestManager.delete(
endpoints.GUILD_MEMBER(guildID, memberID), endpoints.GUILD_MEMBER(guildID, memberID),
{ reason }, { reason },
@@ -140,7 +154,7 @@ export async function kick(guildID: string, memberID: string, reason?: string) {
} }
/** Edit the member */ /** Edit the member */
export function editMember( export async function editMember(
guildID: string, guildID: string,
memberID: string, memberID: string,
options: EditMemberOptions, options: EditMemberOptions,
@@ -149,30 +163,47 @@ export function editMember(
if (options.nick.length > 32) { if (options.nick.length > 32) {
throw new Error(Errors.NICKNAMES_MAX_LENGTH); throw new Error(Errors.NICKNAMES_MAX_LENGTH);
} }
if (!botHasPermission(guildID, [Permissions.MANAGE_NICKNAMES])) {
const hasManageNickPerm = await botHasPermission(
guildID,
[Permissions.MANAGE_NICKNAMES],
);
if (!hasManageNickPerm) {
throw new Error(Errors.MISSING_MANAGE_NICKNAMES); throw new Error(Errors.MISSING_MANAGE_NICKNAMES);
} }
} }
const hasManageRolesPerm = await botHasPermission(
guildID,
[Permissions.MANAGE_ROLES],
);
if ( if (
options.roles && options.roles &&
!botHasPermission(guildID, [Permissions.MANAGE_ROLES]) !hasManageRolesPerm
) { ) {
throw new Error(Errors.MISSING_MANAGE_ROLES); throw new Error(Errors.MISSING_MANAGE_ROLES);
} }
if (options.mute) { if (options.mute) {
const hasMuteMembersPerm = await botHasPermission(
guildID,
[Permissions.MUTE_MEMBERS],
);
// TODO: This should check if the member is in a voice channel // TODO: This should check if the member is in a voice channel
if ( if (
!botHasPermission(guildID, [Permissions.MUTE_MEMBERS]) !hasMuteMembersPerm
) { ) {
throw new Error(Errors.MISSING_MUTE_MEMBERS); throw new Error(Errors.MISSING_MUTE_MEMBERS);
} }
} }
const hasDeafenMembersPerm = await botHasPermission(
guildID,
[Permissions.DEAFEN_MEMBERS],
);
if ( if (
options.deaf && options.deaf &&
!botHasPermission(guildID, [Permissions.DEAFEN_MEMBERS]) !hasDeafenMembersPerm
) { ) {
throw new Error(Errors.MISSING_DEAFEN_MEMBERS); throw new Error(Errors.MISSING_DEAFEN_MEMBERS);
} }
+1 -1
View File
@@ -1,5 +1,4 @@
import { delay } from "../../deps.ts"; import { delay } from "../../deps.ts";
import { endpoints } from "../constants/discord.ts";
import { cacheHandlers } from "../controllers/cache.ts"; import { cacheHandlers } from "../controllers/cache.ts";
import { botID } from "../module/client.ts"; import { botID } from "../module/client.ts";
import { RequestManager } from "../module/requestManager.ts"; import { RequestManager } from "../module/requestManager.ts";
@@ -10,6 +9,7 @@ import { Errors } from "../types/errors.ts";
import { UserPayload } from "../types/guild.ts"; import { UserPayload } from "../types/guild.ts";
import { MessageCreateOptions } from "../types/message.ts"; import { MessageCreateOptions } from "../types/message.ts";
import { Permissions } from "../types/permission.ts"; import { Permissions } from "../types/permission.ts";
import { endpoints } from "../utils/constants.ts";
import { botHasChannelPermissions } from "../utils/permissions.ts"; import { botHasChannelPermissions } from "../utils/permissions.ts";
/** Delete a message with the channel id and message id only. */ /** Delete a message with the channel id and message id only. */
+203
View File
@@ -0,0 +1,203 @@
import {
channelOverwriteHasPermission,
createInvite,
deleteMessages,
editChannel,
followChannel,
getChannelInvites,
getChannelWebhooks,
getMessage,
getMessages,
getPins,
isChannelSynced,
sendMessage,
} from "./channel.ts";
import {
ban,
categoryChildrenIDs,
createEmoji,
createGuildChannel,
createGuildFromTemplate,
createGuildRole,
createGuildTemplate,
createServer,
deleteChannel,
deleteEmoji,
deleteGuildTemplate,
deleteIntegration,
deleteRole,
deleteServer,
editEmbed,
editEmoji,
editGuild,
editGuildTemplate,
editIntegration,
editRole,
emojiURL,
fetchMembers,
getAuditLogs,
getBan,
getBans,
getChannel,
getChannels,
getEmbed,
getGuild,
getGuildTemplate,
getGuildTemplates,
getIntegrations,
getInvites,
getMember,
getMembersByQuery,
getPruneCount,
getRoles,
getUser,
getVanityURL,
getVoiceRegions,
getWebhooks,
guildBannerURL,
guildIconURL,
guildSplashURL,
leaveGuild,
pruneMembers,
swapChannels,
swapRoles,
syncGuildTemplate,
syncIntegration,
unban,
} from "./guild.ts";
import {
addRole,
avatarURL,
editBotProfile,
editMember,
kick,
moveMember,
rawAvatarURL,
removeRole,
sendDirectMessage,
} from "./member.ts";
import {
addReaction,
addReactions,
deleteMessage,
deleteMessageByID,
editMessage,
getReactions,
pin,
publishMessage,
removeAllReactions,
removeReaction,
removeReactionEmoji,
removeUserReaction,
unpin,
} from "./message.ts";
import { createWebhook, executeWebhook, getWebhook } from "./webhook.ts";
export let handlers = {
// Channel handler
channelOverwriteHasPermission,
createInvite,
deleteMessages,
editChannel,
followChannel,
getChannelInvites,
getChannelWebhooks,
getMessage,
getMessages,
getPins,
isChannelSynced,
sendMessage,
// Guild handler
ban,
categoryChildrenIDs,
createEmoji,
createGuildChannel,
createGuildFromTemplate,
createGuildRole,
createGuildTemplate,
createServer,
deleteChannel,
deleteEmoji,
deleteGuildTemplate,
deleteIntegration,
deleteRole,
deleteServer,
editEmbed,
editEmoji,
editGuild,
editGuildTemplate,
editIntegration,
editRole,
emojiURL,
fetchMembers,
getAuditLogs,
getBan,
getBans,
getChannel,
getChannels,
getEmbed,
getGuild,
getGuildTemplate,
getGuildTemplates,
getIntegrations,
getInvites,
getMember,
getMembersByQuery,
getPruneCount,
getRoles,
getUser,
getVanityURL,
getVoiceRegions,
getWebhooks,
guildBannerURL,
guildIconURL,
guildSplashURL,
leaveGuild,
pruneMembers,
swapChannels,
swapRoles,
syncGuildTemplate,
syncIntegration,
unban,
// Member handler
addRole,
avatarURL,
editBotProfile,
editMember,
kick,
moveMember,
rawAvatarURL,
removeRole,
sendDirectMessage,
// Message handler
addReaction,
addReactions,
deleteMessage,
deleteMessageByID,
editMessage,
getReactions,
pin,
publishMessage,
removeAllReactions,
removeReaction,
removeReactionEmoji,
removeUserReaction,
unpin,
// Webhook handler
createWebhook,
executeWebhook,
getWebhook,
};
export type Handlers = typeof handlers;
export function updateHandlers(newHandlers: Partial<Handlers>) {
handlers = {
...handlers,
...newHandlers,
};
}
+1 -1
View File
@@ -1,4 +1,3 @@
import { endpoints } from "../constants/discord.ts";
import { RequestManager } from "../module/requestManager.ts"; import { RequestManager } from "../module/requestManager.ts";
import { structures } from "../structures/mod.ts"; import { structures } from "../structures/mod.ts";
import { Errors } from "../types/errors.ts"; import { Errors } from "../types/errors.ts";
@@ -9,6 +8,7 @@ import {
WebhookCreateOptions, WebhookCreateOptions,
WebhookPayload, WebhookPayload,
} from "../types/webhook.ts"; } from "../types/webhook.ts";
import { endpoints } from "../utils/constants.ts";
import { botHasChannelPermissions } from "../utils/permissions.ts"; import { botHasChannelPermissions } from "../utils/permissions.ts";
import { urlToBase64 } from "../utils/utils.ts"; import { urlToBase64 } from "../utils/utils.ts";
+1 -1
View File
@@ -1,6 +1,6 @@
import { endpoints } from "../constants/discord.ts";
import { DiscordBotGatewayData } from "../types/discord.ts"; import { DiscordBotGatewayData } from "../types/discord.ts";
import { ClientOptions, EventHandlers } from "../types/options.ts"; import { ClientOptions, EventHandlers } from "../types/options.ts";
import { endpoints } from "../utils/constants.ts";
import { RequestManager } from "./requestManager.ts"; import { RequestManager } from "./requestManager.ts";
import { spawnShards } from "./shardingManager.ts"; import { spawnShards } from "./shardingManager.ts";
+17 -5
View File
@@ -1,8 +1,8 @@
import { delay } from "../../deps.ts"; import { delay } from "../../deps.ts";
import { baseEndpoints } from "../constants/discord.ts";
import { HttpResponseCode } from "../types/discord.ts"; import { HttpResponseCode } from "../types/discord.ts";
import { Errors } from "../types/errors.ts"; import { Errors } from "../types/errors.ts";
import { RequestMethods } from "../types/fetch.ts"; import { RequestMethods } from "../types/fetch.ts";
import { baseEndpoints } from "../utils/constants.ts";
import { authorization, eventHandlers } from "./client.ts"; import { authorization, eventHandlers } from "./client.ts";
const pathQueues: { [key: string]: QueuedRequest[] } = {}; const pathQueues: { [key: string]: QueuedRequest[] } = {};
@@ -200,7 +200,7 @@ async function runMethod(
}, },
); );
const errorStack = new Error("Location In Your Files:"); const errorStack = new Error("Location:");
Error.captureStackTrace(errorStack); Error.captureStackTrace(errorStack);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@@ -321,13 +321,25 @@ function handleStatusCode(response: Response, errorStack?: unknown) {
switch (status) { switch (status) {
case HttpResponseCode.BadRequest: case HttpResponseCode.BadRequest:
throw new Error(
"The request was improperly formatted, or the server couldn't understand it.",
);
case HttpResponseCode.Unauthorized: case HttpResponseCode.Unauthorized:
throw new Error("The Authorization header was missing or invalid.");
case HttpResponseCode.Forbidden: case HttpResponseCode.Forbidden:
throw new Error(
"The Authorization token you passed did not have permission to the resource.",
);
case HttpResponseCode.NotFound: case HttpResponseCode.NotFound:
throw new Error("The resource at the location specified doesn't exist.");
case HttpResponseCode.MethodNotAllowed: case HttpResponseCode.MethodNotAllowed:
throw new Error(Errors.REQUEST_CLIENT_ERROR); throw new Error(
"The HTTP method used is not valid for the location specified.",
);
case HttpResponseCode.GatewayUnavailable: case HttpResponseCode.GatewayUnavailable:
throw new Error(Errors.REQUEST_SERVER_ERROR); throw new Error(
"There was not a gateway available to process your request. Wait a bit and retry.",
);
} }
// left are all unknown // left are all unknown
@@ -365,7 +377,7 @@ function processHeaders(url: string, headers: Headers) {
// If there is no remaining global limit, we save it in cache // If there is no remaining global limit, we save it in cache
if (global) { if (global) {
const reset = Date.now() + Number(retryAfter); const reset = Date.now() + (Number(retryAfter) * 1000);
eventHandlers.debug?.( eventHandlers.debug?.(
{ type: "globallyRateLimited", data: { url, reset } }, { type: "globallyRateLimited", data: { url, reset } },
); );
+2
View File
@@ -3,6 +3,7 @@ import { createGuild } from "./guild.ts";
import { createMember } from "./member.ts"; import { createMember } from "./member.ts";
import { createMessage } from "./message.ts"; import { createMessage } from "./message.ts";
import { createRole } from "./role.ts"; import { createRole } from "./role.ts";
import { createTemplate } from "./template.ts";
/** This is the placeholder where the structure creation functions are kept. */ /** This is the placeholder where the structure creation functions are kept. */
export let structures = { export let structures = {
@@ -11,6 +12,7 @@ export let structures = {
createMember, createMember,
createMessage, createMessage,
createRole, createRole,
createTemplate,
}; };
export type Structures = typeof structures; export type Structures = typeof structures;
+31
View File
@@ -0,0 +1,31 @@
import { GuildTemplate } from "../types/guild.ts";
export function createTemplate(
data: GuildTemplate,
) {
const {
usage_count: usageCount,
creator_id: creatorID,
created_at: createdAt,
updated_at: updatedAt,
source_guild_id: sourceGuildID,
serialized_source_guild: serializedSourceGuild,
is_dirty: isDirty,
...rest
} = data;
const template = {
...rest,
usageCount,
creatorID,
createdAt,
updatedAt,
sourceGuildID,
serializedSourceGuild,
isDirty,
};
return template;
}
export interface Template extends ReturnType<typeof createTemplate> {}
+48
View File
@@ -1,3 +1,4 @@
import { Guild } from "../structures/guild.ts";
import { ChannelCreatePayload, ChannelTypes } from "./channel.ts"; import { ChannelCreatePayload, ChannelTypes } from "./channel.ts";
import { Emoji, StatusType } from "./discord.ts"; import { Emoji, StatusType } from "./discord.ts";
import { MemberCreatePayload } from "./member.ts"; import { MemberCreatePayload } from "./member.ts";
@@ -606,3 +607,50 @@ export interface CreateServerOptions {
/** the id of the channel where guild notices such as welcome messages and boost events are posted */ /** the id of the channel where guild notices such as welcome messages and boost events are posted */
system_channel_id?: string; system_channel_id?: string;
} }
// https://discord.com/developers/docs/resources/template#template-object
export interface GuildTemplate {
/** the template code (unique ID) */
code: string;
/** template name */
name: string;
/** the description for the template */
description: string | null;
/** number of times this template has been used */
usage_count: number;
/** the ID of the user who created the template */
creator_id: string;
/** the user who created the template */
user: UserPayload;
/** when this template was created */
created_at: string;
/** when this template was last synced to the source guild */
updated_at: string;
/** the ID of the guild this template is based on */
source_guild_id: string;
/** the guild snapshot this template contains */
serialized_source_guild: Guild;
/** whether the template has unsynced changes */
is_dirty: boolean | null;
}
export interface CreateGuildFromTemplate {
/** name of the guild (2-100 characters) */
name: string;
/** base64 128x128 image for the guild icon */
icon?: string;
}
export interface CreateGuildTemplate {
/** name of the template (1-100 characters) */
name: string;
/** description for the template (0-120 characters) */
description?: string;
}
export interface EditGuildTemplate {
/** name of the template (1-100 characters) */
name?: string;
/** description for the template (0-120 characters) */
description?: string | null;
}
@@ -89,6 +89,9 @@ export const endpoints = {
`${baseEndpoints.CDN_URL}/splashes/${id}/${icon}`, `${baseEndpoints.CDN_URL}/splashes/${id}/${icon}`,
GUILD_VANITY_URL: (id: string) => `${GUILDS_BASE(id)}/vanity-url`, GUILD_VANITY_URL: (id: string) => `${GUILDS_BASE(id)}/vanity-url`,
GUILD_WEBHOOKS: (id: string) => `${GUILDS_BASE(id)}/webhooks`, GUILD_WEBHOOKS: (id: string) => `${GUILDS_BASE(id)}/webhooks`,
GUILD_TEMPLATE: (code: string) =>
`${baseEndpoints.BASE_URL}/guilds/templates/${code}`,
GUILD_TEMPLATES: (id: string) => `${GUILDS_BASE(id)}/templates`,
WEBHOOK: (id: string, token: string) => WEBHOOK: (id: string, token: string) =>
`${baseEndpoints.BASE_URL}/webhooks/${id}/${token}`, `${baseEndpoints.BASE_URL}/webhooks/${id}/${token}`,
+2 -1
View File
@@ -175,7 +175,8 @@ export async function hasChannelPermissions(
if (permissions.every((perm) => allowedPermissions.has(perm))) return true; if (permissions.every((perm) => allowedPermissions.has(perm))) return true;
// Some permission was not explicitly allowed so we default to checking role perms directly // Some permission was not explicitly allowed so we default to checking role perms directly
return botHasPermission(guild.id, permissions); const hasPerms = await botHasPermission(guild.id, permissions);
return hasPerms;
} }
/** This function converts a bitwise string to permission strings */ /** This function converts a bitwise string to permission strings */