aboutsummaryrefslogtreecommitdiff
path: root/src/lib/extensions
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/extensions')
-rw-r--r--src/lib/extensions/discord-akairo/BushClient.ts195
-rw-r--r--src/lib/extensions/discord-akairo/BushClientUtil.ts102
-rw-r--r--src/lib/extensions/discord-akairo/BushCommand.ts188
-rw-r--r--src/lib/extensions/discord-akairo/BushInhibitor.ts7
-rw-r--r--src/lib/extensions/discord-akairo/BushSlashMessage.ts2
-rw-r--r--src/lib/extensions/discord.js/BushActivity.ts3
-rw-r--r--src/lib/extensions/discord.js/BushApplicationCommand.ts3
-rw-r--r--src/lib/extensions/discord.js/BushApplicationCommandManager.d.ts101
-rw-r--r--src/lib/extensions/discord.js/BushApplicationCommandPermissionsManager.d.ts123
-rw-r--r--src/lib/extensions/discord.js/BushBaseGuildEmojiManager.d.ts8
-rw-r--r--src/lib/extensions/discord.js/BushBaseGuildTextChannel.ts3
-rw-r--r--src/lib/extensions/discord.js/BushBaseGuildVoiceChannel.d.ts13
-rw-r--r--src/lib/extensions/discord.js/BushButtonInteraction.ts7
-rw-r--r--src/lib/extensions/discord.js/BushCategoryChannel.ts7
-rw-r--r--src/lib/extensions/discord.js/BushChannel.d.ts14
-rw-r--r--src/lib/extensions/discord.js/BushChannelManager.d.ts20
-rw-r--r--src/lib/extensions/discord.js/BushClientEvents.d.ts29
-rw-r--r--src/lib/extensions/discord.js/BushClientUser.d.ts78
-rw-r--r--src/lib/extensions/discord.js/BushCommandInteraction.ts31
-rw-r--r--src/lib/extensions/discord.js/BushDMChannel.ts3
-rw-r--r--src/lib/extensions/discord.js/BushEmoji.ts3
-rw-r--r--src/lib/extensions/discord.js/BushGuild.ts109
-rw-r--r--src/lib/extensions/discord.js/BushGuildApplicationCommandManager.d.ts89
-rw-r--r--src/lib/extensions/discord.js/BushGuildBan.d.ts3
-rw-r--r--src/lib/extensions/discord.js/BushGuildChannel.ts9
-rw-r--r--src/lib/extensions/discord.js/BushGuildEmoji.ts3
-rw-r--r--src/lib/extensions/discord.js/BushGuildEmojiRoleManager.d.ts36
-rw-r--r--src/lib/extensions/discord.js/BushGuildManager.d.ts16
-rw-r--r--src/lib/extensions/discord.js/BushGuildMember.ts289
-rw-r--r--src/lib/extensions/discord.js/BushGuildMemberManager.d.ts131
-rw-r--r--src/lib/extensions/discord.js/BushMessage.ts10
-rw-r--r--src/lib/extensions/discord.js/BushMessageManager.d.ts84
-rw-r--r--src/lib/extensions/discord.js/BushMessageReaction.ts3
-rw-r--r--src/lib/extensions/discord.js/BushNewsChannel.ts3
-rw-r--r--src/lib/extensions/discord.js/BushPresence.ts3
-rw-r--r--src/lib/extensions/discord.js/BushReactionEmoji.ts5
-rw-r--r--src/lib/extensions/discord.js/BushRole.ts3
-rw-r--r--src/lib/extensions/discord.js/BushSelectMenuInteraction.ts7
-rw-r--r--src/lib/extensions/discord.js/BushStageChannel.ts5
-rw-r--r--src/lib/extensions/discord.js/BushStageInstance.ts3
-rw-r--r--src/lib/extensions/discord.js/BushStoreChannel.ts4
-rw-r--r--src/lib/extensions/discord.js/BushTextChannel.ts3
-rw-r--r--src/lib/extensions/discord.js/BushThreadChannel.ts3
-rw-r--r--src/lib/extensions/discord.js/BushThreadManager.d.ts57
-rw-r--r--src/lib/extensions/discord.js/BushThreadMember.ts3
-rw-r--r--src/lib/extensions/discord.js/BushThreadMemberManager.d.ts31
-rw-r--r--src/lib/extensions/discord.js/BushUser.ts9
-rw-r--r--src/lib/extensions/discord.js/BushUserManager.d.ts59
-rw-r--r--src/lib/extensions/discord.js/BushVoiceChannel.ts3
-rw-r--r--src/lib/extensions/discord.js/BushVoiceState.ts9
-rw-r--r--src/lib/extensions/global.d.ts7
51 files changed, 1636 insertions, 303 deletions
diff --git a/src/lib/extensions/discord-akairo/BushClient.ts b/src/lib/extensions/discord-akairo/BushClient.ts
index a9e172a..d7c8b60 100644
--- a/src/lib/extensions/discord-akairo/BushClient.ts
+++ b/src/lib/extensions/discord-akairo/BushClient.ts
@@ -1,26 +1,25 @@
import type {
BushApplicationCommand,
BushBaseGuildEmojiManager,
- BushChannel,
BushChannelManager,
BushClientEvents,
BushClientUser,
BushGuildManager,
BushReactionEmoji,
+ BushStageChannel,
BushUserManager,
Config
} from '#lib';
-import { patch, type PatchedElements } from '@notenoughupdates/events-intercept';
+import { patch, PatchedElements } from '@notenoughupdates/events-intercept';
import * as Sentry from '@sentry/node';
import { AkairoClient, ContextMenuCommandHandler, version as akairoVersion } from 'discord-akairo';
import {
+ Awaitable,
Intents,
Options,
Structures,
version as discordJsVersion,
- type Awaitable,
type Collection,
- type DMChannel,
type InteractionReplyOptions,
type Message,
type MessageEditOptions,
@@ -31,6 +30,7 @@ import {
type Snowflake,
type WebhookEditMessageOptions
} from 'discord.js';
+import EventEmitter from 'events';
import path from 'path';
import readline from 'readline';
import type { Sequelize as SequelizeType } from 'sequelize';
@@ -100,9 +100,28 @@ export type BushEmojiIdentifierResolvable = string | BushEmojiResolvable;
export type BushThreadChannelResolvable = BushThreadChannel | Snowflake;
export type BushApplicationCommandResolvable = BushApplicationCommand | Snowflake;
export type BushGuildTextChannelResolvable = BushTextChannel | BushNewsChannel | Snowflake;
-export type BushChannelResolvable = BushChannel | Snowflake;
-export type BushTextBasedChannels = PartialDMChannel | BushDMChannel | BushTextChannel | BushNewsChannel | BushThreadChannel;
-export type BushGuildTextBasedChannel = Exclude<BushTextBasedChannels, PartialDMChannel | BushDMChannel | DMChannel>;
+export type BushChannelResolvable = BushAnyChannel | Snowflake;
+export type BushGuildChannelResolvable = Snowflake | BushGuildBasedChannel;
+export type BushAnyChannel =
+ | BushCategoryChannel
+ | BushDMChannel
+ | PartialDMChannel
+ | BushNewsChannel
+ | BushStageChannel
+ // eslint-disable-next-line deprecation/deprecation
+ | BushStoreChannel
+ | BushTextChannel
+ | BushThreadChannel
+ | BushVoiceChannel;
+export type BushTextBasedChannel = PartialDMChannel | BushThreadChannel | BushDMChannel | BushNewsChannel | BushTextChannel;
+export type BushTextBasedChannelTypes = BushTextBasedChannel['type'];
+export type BushVoiceBasedChannel = Extract<BushAnyChannel, { bitrate: number }>;
+export type BushGuildBasedChannel = Extract<BushAnyChannel, { guild: BushGuild }>;
+export type BushNonThreadGuildBasedChannel = Exclude<BushGuildBasedChannel, BushThreadChannel>;
+export type BushGuildTextBasedChannel = Extract<BushGuildBasedChannel, BushTextBasedChannel>;
+export type BushTextChannelResolvable = Snowflake | BushTextChannel;
+export type BushGuildVoiceChannelResolvable = BushVoiceBasedChannel | Snowflake;
+
export interface BushFetchedThreads {
threads: Collection<Snowflake, BushThreadChannel>;
hasMore?: boolean;
@@ -118,29 +137,86 @@ type If<T extends boolean, A, B = null> = T extends true ? A : T extends false ?
const __dirname = path.dirname(fileURLToPath(import.meta.url));
+/**
+ * The main hub for interacting with the Discord API.
+ */
export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Ready> {
public declare channels: BushChannelManager;
public declare readonly emojis: BushBaseGuildEmojiManager;
public declare guilds: BushGuildManager;
public declare user: If<Ready, BushClientUser>;
public declare users: BushUserManager;
+ public declare util: BushClientUtil;
+ public declare ownerID: Snowflake[];
+ /**
+ * Whether or not the client is ready.
+ */
public customReady = false;
- public stats: { cpu: number | undefined; commandsUsed: bigint } = { cpu: undefined, commandsUsed: 0n };
+
+ /**
+ * Stats for the client.
+ */
+ public stats: BushStats = { cpu: undefined, commandsUsed: 0n };
+
+ /**
+ * The configuration for the client.
+ */
public config: Config;
+
+ /**
+ * The handler for the bot's listeners.
+ */
public listenerHandler: BushListenerHandler;
+
+ /**
+ * The handler for the bot's command inhibitors.
+ */
public inhibitorHandler: BushInhibitorHandler;
+
+ /**
+ * The handler for the bot's commands.
+ */
public commandHandler: BushCommandHandler;
+
+ /**
+ * The handler for the bot's tasks.
+ */
public taskHandler: BushTaskHandler;
+
+ /**
+ * The handler for the bot's context menu commands.
+ */
public contextMenuCommandHandler: ContextMenuCommandHandler;
- public declare util: BushClientUtil;
- public declare ownerID: Snowflake[];
+
+ /**
+ * The database connection for the bot.
+ */
public db: SequelizeType;
+
+ /**
+ * A custom logging system for the bot.
+ */
public logger = BushLogger;
+
+ /**
+ * Constants for the bot.
+ */
public constants = BushConstants;
+
+ /**
+ * Cached global and guild database data.
+ */
public cache = new BushCache();
+
+ /**
+ * Sentry error reporting for the bot.
+ */
public sentry!: typeof Sentry;
+ /**
+ * @param config The configuration for the bot.
+ */
public constructor(config: Config) {
super({
ownerID: config.owners,
@@ -163,25 +239,18 @@ export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Re
this.token = config.token as If<Ready, string, string | null>;
this.config = config;
- // Create listener handler
this.listenerHandler = new BushListenerHandler(this, {
directory: path.join(__dirname, '..', '..', '..', 'listeners'),
automateCategories: true
});
-
- // Create inhibitor handler
this.inhibitorHandler = new BushInhibitorHandler(this, {
directory: path.join(__dirname, '..', '..', '..', 'inhibitors'),
automateCategories: true
});
-
- // Create task handler
this.taskHandler = new BushTaskHandler(this, {
directory: path.join(__dirname, '..', '..', '..', 'tasks'),
automateCategories: true
});
-
- // Create command handler
this.commandHandler = new BushCommandHandler(this, {
directory: path.join(__dirname, '..', '..', '..', 'commands'),
prefix: async ({ guild }: Message) => {
@@ -215,12 +284,10 @@ export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Re
useSlashPermissions: true,
aliasReplacement: /-/g
});
-
this.contextMenuCommandHandler = new ContextMenuCommandHandler(this, {
directory: path.join(__dirname, '..', '..', '..', 'context-menu-commands'),
automateCategories: true
});
-
this.util = new BushClientUtil(this);
this.db = new Sequelize({
database: this.config.isDevelopment ? 'bushbot-dev' : this.config.isBeta ? 'bushbot-beta' : 'bushbot',
@@ -234,15 +301,24 @@ export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Re
});
}
- get console(): typeof BushLogger {
+ /**
+ * A custom logging system for the bot.
+ */
+ public get console(): typeof BushLogger {
return this.logger;
}
- get consts(): typeof BushConstants {
+ /**
+ * Constants for the bot.
+ */
+ public get consts(): typeof BushConstants {
return this.constants;
}
- public static init(): void {
+ /**
+ * Extends discord.js structures before the client is instantiated.
+ */
+ public static extendStructures(): void {
Structures.extend('GuildEmoji', () => BushGuildEmoji);
Structures.extend('DMChannel', () => BushDMChannel);
Structures.extend('TextChannel', () => BushTextChannel);
@@ -265,18 +341,28 @@ export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Re
Structures.extend('SelectMenuInteraction', () => BushSelectMenuInteraction);
}
- // Initialize everything
- async #init() {
- this.commandHandler.useListenerHandler(this.listenerHandler);
+ /**
+ * Initializes the bot.
+ */
+ async init() {
+ if (!process.version.startsWith('v17.')) {
+ void (await this.console.error('version', `Please use node <<v17.x.x>>, not <<${process.version}>>.`, false));
+ process.exit(2);
+ }
+
this.commandHandler.useInhibitorHandler(this.inhibitorHandler);
+ this.commandHandler.useListenerHandler(this.listenerHandler);
+ this.commandHandler.useTaskHandler(this.taskHandler);
+ this.commandHandler.useContextMenuCommandHandler(this.contextMenuCommandHandler);
this.commandHandler.ignorePermissions = this.config.owners;
this.commandHandler.ignoreCooldown = [...new Set([...this.config.owners, ...this.cache.global.superUsers])];
this.listenerHandler.setEmitters({
client: this,
commandHandler: this.commandHandler,
- listenerHandler: this.listenerHandler,
inhibitorHandler: this.inhibitorHandler,
+ listenerHandler: this.listenerHandler,
taskHandler: this.taskHandler,
+ contextMenuCommandHandler: this.contextMenuCommandHandler,
process,
stdin: rl,
gateway: this.ws
@@ -301,28 +387,31 @@ export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Re
void this.logger.success('startup', `Successfully connected to <<Sentry>>.`, false);
// loads all the handlers
- const loaders = {
+ const handlers = {
commands: this.commandHandler,
- contextMenuCommand: this.contextMenuCommandHandler,
+ contextMenuCommands: this.contextMenuCommandHandler,
listeners: this.listenerHandler,
inhibitors: this.inhibitorHandler,
tasks: this.taskHandler
};
- for (const loader in loaders) {
- try {
- await loaders[loader as keyof typeof loaders].loadAll();
- void this.logger.success('startup', `Successfully loaded <<${loader}>>.`, false);
- } catch (e) {
- void this.logger.error('startup', `Unable to load loader <<${loader}>> with error:\n${e?.stack || e}`, false);
- }
- }
- await this.dbPreInit();
- await UpdateCacheTask.init(this);
- void this.console.success('startup', `Successfully created <<cache>>.`, false);
- this.stats.commandsUsed = await UpdateStatsTask.init();
+ const handlerPromises = Object.entries(handlers).map(([handlerName, handler]) =>
+ handler
+ .loadAll()
+ .then(() => {
+ void this.logger.success('startup', `Successfully loaded <<${handlerName}>>.`, false);
+ })
+ .catch((e) => {
+ void this.logger.error('startup', `Unable to load loader <<${handlerName}>> with error:\n${e?.stack || e}`, false);
+ if (process.argv.includes('dry')) process.exit(1);
+ })
+ );
+ await Promise.allSettled(handlerPromises);
}
- public async dbPreInit() {
+ /**
+ * Connects to the database, initializes models, and creates tables if they do not exist.
+ */
+ private async dbPreInit() {
try {
await this.db.authenticate();
Global.initModel(this.db);
@@ -348,10 +437,6 @@ export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Re
* Starts the bot
*/
public async start() {
- if (!process.version.startsWith('v17.')) {
- void (await this.console.error('version', `Please use node <<v17.x.x>>, not <<${process.version}>>.`, false));
- process.exit(2);
- }
this.intercept('ready', async (arg, done) => {
await this.guilds.fetch();
const promises = this.guilds.cache.map((guild) => {
@@ -368,7 +453,10 @@ export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Re
global.util = this.util;
try {
- await this.#init();
+ await this.dbPreInit();
+ await UpdateCacheTask.init(this);
+ void this.console.success('startup', `Successfully created <<cache>>.`, false);
+ this.stats.commandsUsed = await UpdateStatsTask.init();
await this.login(this.token!);
} catch (e) {
await this.console.error('start', util.inspect(e, { colors: true, depth: 1 }), false);
@@ -389,13 +477,14 @@ export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Re
public override isOwner(user: BushUserResolvable): boolean {
return this.config.owners.includes(this.users.resolveId(user!)!);
}
+
public override isSuperUser(user: BushUserResolvable): boolean {
const userID = this.users.resolveId(user)!;
return !!client.cache?.global?.superUsers?.includes(userID) || this.config.owners.includes(userID);
}
}
-export interface BushClient extends PatchedElements {
+export interface BushClient extends EventEmitter, PatchedElements {
on<K extends keyof BushClientEvents>(event: K, listener: (...args: BushClientEvents[K]) => Awaitable<void>): this;
on<S extends string | symbol>(event: Exclude<S, keyof BushClientEvents>, listener: (...args: any[]) => Awaitable<void>): this;
@@ -411,3 +500,15 @@ export interface BushClient extends PatchedElements {
removeAllListeners<K extends keyof BushClientEvents>(event?: K): this;
removeAllListeners<S extends string | symbol>(event?: Exclude<S, keyof BushClientEvents>): this;
}
+
+export interface BushStats {
+ /**
+ * The average cpu usage of the bot from the past 60 seconds.
+ */
+ cpu: number | undefined;
+
+ /**
+ * The total number of times any command has been used.
+ */
+ commandsUsed: bigint;
+}
diff --git a/src/lib/extensions/discord-akairo/BushClientUtil.ts b/src/lib/extensions/discord-akairo/BushClientUtil.ts
index ab1f3ed..5ae2ac0 100644
--- a/src/lib/extensions/discord-akairo/BushClientUtil.ts
+++ b/src/lib/extensions/discord-akairo/BushClientUtil.ts
@@ -2,6 +2,7 @@ import {
Arg,
BushConstants,
Global,
+ GlobalCache,
type BushClient,
type BushInspectOptions,
type BushMessage,
@@ -438,6 +439,12 @@ export class BushClientUtil extends ClientUtil {
return array.join(', ');
}
+ public getGlobal(): GlobalCache;
+ public getGlobal<K extends keyof GlobalCache>(key: K): GlobalCache[K];
+ public getGlobal(key?: keyof GlobalCache) {
+ return key ? client.cache.global[key] : client.cache.global;
+ }
+
/**
* Add or remove an element from an array stored in the Globals database.
* @param action Either `add` or `remove` an element.
@@ -610,11 +617,11 @@ export class BushClientUtil extends ClientUtil {
/**
* Wait an amount in seconds.
- * @param s The number of seconds to wait
+ * @param seconds The number of seconds to wait
* @returns A promise that resolves after the specified amount of seconds
*/
- public async sleep(s: number) {
- return new Promise((resolve) => setTimeout(resolve, s * 1000));
+ public async sleep(seconds: number) {
+ return new Promise((resolve) => setTimeout(resolve, seconds * 1000));
}
/**
@@ -629,8 +636,13 @@ export class BushClientUtil extends ClientUtil {
});
}
+ /**
+ * Fetches a user from discord.
+ * @param user The user to fetch
+ * @returns Undefined if the user is not found, otherwise the user.
+ */
public async resolveNonCachedUser(user: UserResolvable | undefined | null): Promise<BushUser | undefined> {
- if (!user) return undefined;
+ if (user == null) return undefined;
const id =
user instanceof User || user instanceof GuildMember || user instanceof ThreadMember
? user.id
@@ -643,6 +655,11 @@ export class BushClientUtil extends ClientUtil {
else return await client.users.fetch(id).catch(() => undefined);
}
+ /**
+ * Get the pronouns of a discord user from pronoundb.org
+ * @param user The user to retrieve the promises of.
+ * @returns The human readable pronouns of the user, or undefined if they do not have any.
+ */
public async getPronounsOf(user: User | Snowflake): Promise<Pronoun | undefined> {
const _user = await this.resolveNonCachedUser(user);
if (!_user) throw new Error(`Cannot find user ${user}`);
@@ -657,6 +674,11 @@ export class BushClientUtil extends ClientUtil {
return client.constants.pronounMapping[apiRes.pronouns!]!;
}
+ /**
+ * List the methods of an object.
+ * @param obj The object to get the methods of.
+ * @returns A string with each method on a new line.
+ */
public getMethods(obj: Record<string, any>): string {
// modified from https://stackoverflow.com/questions/31054910/get-functions-methods-of-a-class
// answer by Bruno Grieder
@@ -700,13 +722,17 @@ export class BushClientUtil extends ClientUtil {
return props.join('\n');
}
+ /**
+ * Uploads an image to imgur.
+ * @param image The image to upload.
+ * @returns The url of the imgur.
+ */
public async uploadImageToImgur(image: string) {
const clientId = this.client.config.credentials.imgurClientId;
const resp = (await got
.post('https://api.imgur.com/3/upload', {
headers: {
- // Authorization: `Bearer ${token}`,
Authorization: `Client-ID ${clientId}`,
Accept: 'application/json'
},
@@ -721,18 +747,38 @@ export class BushClientUtil extends ClientUtil {
return resp.data.link;
}
+ /**
+ * Checks if a user has a certain guild permission (doesn't check channel permissions).
+ * @param message The message to check the user from.
+ * @param permissions The permissions to check for.
+ * @returns The missing permissions or null if none are missing.
+ */
public userGuildPermCheck(message: BushMessage | BushSlashMessage, permissions: PermissionResolvable) {
const missing = message.member?.permissions.missing(permissions) ?? [];
return missing.length ? missing : null;
}
+ /**
+ * Check if the client has certain permissions in the guild (doesn't check channel permissions).
+ * @param message The message to check the client user from.
+ * @param permissions The permissions to check for.
+ * @returns The missing permissions or null if none are missing.
+ */
public clientGuildPermCheck(message: BushMessage | BushSlashMessage, permissions: PermissionResolvable) {
const missing = message.guild?.me?.permissions.missing(permissions) ?? [];
return missing.length ? missing : null;
}
+ /**
+ * Check if the client has permission to send messages in the channel as well as check if they have other permissions
+ * in the guild (or the channel if `checkChannel` is `true`).
+ * @param message The message to check the client user from.
+ * @param permissions The permissions to check for.
+ * @param checkChannel Whether to check the channel permissions instead of the guild permissions.
+ * @returns The missing permissions or null if none are missing.
+ */
public clientSendAndPermCheck(
message: BushMessage | BushSlashMessage,
permissions: PermissionResolvable = [],
@@ -752,6 +798,11 @@ export class BushClientUtil extends ClientUtil {
return missing.length ? missing : null;
}
+ /**
+ * Gets the prefix based off of the message.
+ * @param message The message to get the prefix from.
+ * @returns The prefix.
+ */
public prefix(message: BushMessage | BushSlashMessage): string {
return message.util.isSlash
? '/'
@@ -760,14 +811,55 @@ export class BushClientUtil extends ClientUtil {
: message.util.parsed?.prefix ?? client.config.prefix;
}
+ /**
+ * Recursively apply provided options operations on object
+ * and all of the object properties that are either object or function.
+ *
+ * By default freezes object.
+ *
+ * @param obj - The object to which will be applied `freeze`, `seal` or `preventExtensions`
+ * @param options default `{ action: 'freeze' }`
+ * @param options.action
+ * ```
+ * | action | Add | Modify | Delete | Reconfigure |
+ * | ----------------- | --- | ------ | ------ | ----------- |
+ * | preventExtensions | - | + | + | + |
+ * | seal | - | + | - | - |
+ * | freeze | - | - | - | - |
+ * ```
+ *
+ * @returns Initial object with applied options action
+ */
public get deepFreeze() {
return deepLock;
}
+ /**
+ * Recursively apply provided options operations on object
+ * and all of the object properties that are either object or function.
+ *
+ * By default freezes object.
+ *
+ * @param obj - The object to which will be applied `freeze`, `seal` or `preventExtensions`
+ * @param options default `{ action: 'freeze' }`
+ * @param options.action
+ * ```
+ * | action | Add | Modify | Delete | Reconfigure |
+ * | ----------------- | --- | ------ | ------ | ----------- |
+ * | preventExtensions | - | + | + | + |
+ * | seal | - | + | - | - |
+ * | freeze | - | - | - | - |
+ * ```
+ *
+ * @returns Initial object with applied options action
+ */
public static get deepFreeze() {
return deepLock;
}
+ /**
+ * A wrapper for the Argument class that adds custom typings.
+ */
public get arg() {
return Arg;
}
diff --git a/src/lib/extensions/discord-akairo/BushCommand.ts b/src/lib/extensions/discord-akairo/BushCommand.ts
index ae3dcb2..6b54e20 100644
--- a/src/lib/extensions/discord-akairo/BushCommand.ts
+++ b/src/lib/extensions/discord-akairo/BushCommand.ts
@@ -174,7 +174,7 @@ export interface CustomBushArgumentOptions extends BaseBushArgumentOptions {
export type BushMissingPermissionSupplier = (message: BushMessage | BushSlashMessage) => Promise<any> | any;
-export interface BaseBushCommandOptions extends Omit<CommandOptions, 'userPermissions' | 'clientPermissions' | 'args'> {
+interface ExtendedCommandOptions {
/**
* Whether the command is hidden from the help command.
*/
@@ -191,11 +191,6 @@ export interface BaseBushCommandOptions extends Omit<CommandOptions, 'userPermis
restrictedGuilds?: Snowflake[];
/**
- * The description of the command.
- */
- description: string;
-
- /**
* Show how to use the command.
*/
usage: string[];
@@ -206,13 +201,6 @@ export interface BaseBushCommandOptions extends Omit<CommandOptions, 'userPermis
examples: string[];
/**
- * The arguments for the command.
- */
- args?: BushArgumentOptions[] & CustomBushArgumentOptions[];
-
- category: string;
-
- /**
* A fake command, completely hidden from the help command.
*/
pseudo?: boolean;
@@ -223,6 +211,27 @@ export interface BaseBushCommandOptions extends Omit<CommandOptions, 'userPermis
bypassChannelBlacklist?: boolean;
/**
+ * Use instead of {@link BaseBushCommandOptions.args} when using argument generators or custom slashOptions
+ */
+ helpArgs?: BushArgumentOptions[];
+}
+
+export interface BaseBushCommandOptions
+ extends Omit<CommandOptions, 'userPermissions' | 'clientPermissions' | 'args'>,
+ ExtendedCommandOptions {
+ /**
+ * The description of the command.
+ */
+ description: string;
+
+ /**
+ * The arguments for the command.
+ */
+ args?: BushArgumentOptions[] & CustomBushArgumentOptions[];
+
+ category: string;
+
+ /**
* Permissions required by the client to run this command.
*/
clientPermissions: PermissionResolvable | PermissionResolvable[] | BushMissingPermissionSupplier;
@@ -241,11 +250,6 @@ export interface BaseBushCommandOptions extends Omit<CommandOptions, 'userPermis
* Restrict this argument to super users.
*/
superUserOnly?: boolean;
-
- /**
- * Use instead of {@link BaseBushCommandOptions.args} when using argument generators or custom slashOptions
- */
- helpArgs?: BushArgumentOptions[];
}
export type BushCommandOptions = Omit<BaseBushCommandOptions, 'helpArgs'> | Omit<BaseBushCommandOptions, 'args'>;
@@ -329,90 +333,67 @@ export class BushCommand extends Command {
});
}
- const newOptions: CommandOptions = {};
- if ('aliases' in options_) newOptions.aliases = options_.aliases;
- if ('args' in options_ && typeof options_.args === 'object') {
- const newTextArgs: ArgumentOptions[] = [];
- const newSlashArgs: SlashOption[] = [];
- for (const arg of options_.args) {
- if (arg.only !== 'slash' && !options_.slashOnly) {
- const newArg: ArgumentOptions = {};
- if ('default' in arg) newArg.default = arg.default;
- if ('description' in arg) newArg.description = arg.description;
- if ('flag' in arg) newArg.flag = arg.flag;
- if ('id' in arg) newArg.id = arg.id;
- if ('index' in arg) newArg.index = arg.index;
- if ('limit' in arg) newArg.limit = arg.limit;
- if ('match' in arg) newArg.match = arg.match;
- if ('modifyOtherwise' in arg) newArg.modifyOtherwise = arg.modifyOtherwise;
- if ('multipleFlags' in arg) newArg.multipleFlags = arg.multipleFlags;
- if ('otherwise' in arg) newArg.otherwise = arg.otherwise;
- if ('prompt' in arg || 'retry' in arg || 'optional' in arg) {
- newArg.prompt = {};
- if ('prompt' in arg) newArg.prompt.start = arg.prompt;
- if ('retry' in arg) newArg.prompt.retry = arg.retry;
- if ('optional' in arg) newArg.prompt.optional = arg.optional;
+ const newOptions: Partial<CommandOptions & ExtendedCommandOptions> = {};
+ for (const _key in options_) {
+ const key = _key as keyof typeof options_; // you got to love typescript
+ if (key === 'args' && 'args' in options_ && typeof options_.args === 'object') {
+ const newTextArgs: ArgumentOptions[] = [];
+ const newSlashArgs: SlashOption[] = [];
+ for (const arg of options_.args) {
+ if (arg.only !== 'slash' && !options_.slashOnly) {
+ const newArg: ArgumentOptions = {};
+ if ('default' in arg) newArg.default = arg.default;
+ if ('description' in arg) newArg.description = arg.description;
+ if ('flag' in arg) newArg.flag = arg.flag;
+ if ('id' in arg) newArg.id = arg.id;
+ if ('index' in arg) newArg.index = arg.index;
+ if ('limit' in arg) newArg.limit = arg.limit;
+ if ('match' in arg) newArg.match = arg.match;
+ if ('modifyOtherwise' in arg) newArg.modifyOtherwise = arg.modifyOtherwise;
+ if ('multipleFlags' in arg) newArg.multipleFlags = arg.multipleFlags;
+ if ('otherwise' in arg) newArg.otherwise = arg.otherwise;
+ if ('prompt' in arg || 'retry' in arg || 'optional' in arg) {
+ newArg.prompt = {};
+ if ('prompt' in arg) newArg.prompt.start = arg.prompt;
+ if ('retry' in arg) newArg.prompt.retry = arg.retry;
+ if ('optional' in arg) newArg.prompt.optional = arg.optional;
+ }
+ if ('type' in arg) newArg.type = arg.type as ArgumentType | ArgumentTypeCaster;
+ if ('unordered' in arg) newArg.unordered = arg.unordered;
+ newTextArgs.push(newArg);
+ }
+ if (
+ arg.only !== 'text' &&
+ !('slashOptions' in options_) &&
+ (options_.slash || options_.slashOnly) &&
+ arg.slashType !== false
+ ) {
+ const newArg: {
+ [key in SlashOptionKeys]?: any;
+ } = {
+ name: arg.id,
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
+ description: arg.prompt || arg.description || 'No description provided.',
+ type: arg.slashType
+ };
+ if ('slashResolve' in arg) newArg.resolve = arg.slashResolve;
+ if ('autocomplete' in arg) newArg.autocomplete = arg.autocomplete;
+ if ('channelTypes' in arg) newArg.channelTypes = arg.channelTypes;
+ if ('choices' in arg) newArg.choices = arg.choices;
+ if ('minValue' in arg) newArg.minValue = arg.minValue;
+ if ('maxValue' in arg) newArg.maxValue = arg.maxValue;
+ newArg.required = 'optional' in arg ? !arg.optional : true;
+ newSlashArgs.push(newArg as SlashOption);
}
- if ('type' in arg) newArg.type = arg.type as ArgumentType | ArgumentTypeCaster;
- if ('unordered' in arg) newArg.unordered = arg.unordered;
- newTextArgs.push(newArg);
- }
- if (
- arg.only !== 'text' &&
- !('slashOptions' in options_) &&
- (options_.slash || options_.slashOnly) &&
- arg.slashType !== false
- ) {
- const newArg: {
- [key in SlashOptionKeys]?: any;
- } = {
- name: arg.id,
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
- description: arg.prompt || arg.description || 'No description provided.',
- type: arg.slashType
- };
- if ('slashResolve' in arg) newArg.resolve = arg.slashResolve;
- if ('autocomplete' in arg) newArg.autocomplete = arg.autocomplete;
- if ('channelTypes' in arg) newArg.channelTypes = arg.channelTypes;
- if ('choices' in arg) newArg.choices = arg.choices;
- if ('minValue' in arg) newArg.minValue = arg.minValue;
- if ('maxValue' in arg) newArg.maxValue = arg.maxValue;
- newArg.required = 'optional' in arg ? !arg.optional : true;
- newSlashArgs.push(newArg as SlashOption);
}
+ if (newTextArgs.length > 0) newOptions.args = newTextArgs;
+ if (newSlashArgs.length > 0) newOptions.slashOptions = options_.slashOptions ?? newSlashArgs;
+ } else if (key === 'clientPermissions' || key === 'userPermissions') {
+ newOptions[key] = options_[key] as PermissionResolvable | PermissionResolvable[] | MissingPermissionSupplier;
+ } else {
+ newOptions[key] = options_[key];
}
- if (newTextArgs.length > 0) newOptions.args = newTextArgs;
- if (newSlashArgs.length > 0) newOptions.slashOptions = options_.slashOptions ?? newSlashArgs;
}
- type perm = PermissionResolvable | PermissionResolvable[] | MissingPermissionSupplier;
-
- if ('argumentDefaults' in options_) newOptions.argumentDefaults = options_.argumentDefaults;
- if ('before' in options_) newOptions.before = options_.before;
- if ('channel' in options_) newOptions.channel = options_.channel;
- if ('clientPermissions' in options_) newOptions.clientPermissions = options_.clientPermissions as perm;
- if ('condition' in options_) newOptions.condition = options_.condition;
- if ('cooldown' in options_) newOptions.cooldown = options_.cooldown;
- if ('description' in options_) newOptions.description = options_.description;
- if ('editable' in options_) newOptions.editable = options_.editable;
- if ('flags' in options_) newOptions.flags = options_.flags;
- if ('ignoreCooldown' in options_) newOptions.ignoreCooldown = options_.ignoreCooldown;
- if ('ignorePermissions' in options_) newOptions.ignorePermissions = options_.ignorePermissions;
- if ('lock' in options_) newOptions.lock = options_.lock;
- if ('onlyNsfw' in options_) newOptions.onlyNsfw = options_.onlyNsfw;
- if ('optionFlags' in options_) newOptions.optionFlags = options_.optionFlags;
- if ('ownerOnly' in options_) newOptions.ownerOnly = options_.ownerOnly;
- if ('prefix' in options_) newOptions.prefix = options_.prefix;
- if ('quoted' in options_) newOptions.quoted = options_.quoted;
- if ('ratelimit' in options_) newOptions.ratelimit = options_.ratelimit;
- if ('regex' in options_) newOptions.regex = options_.regex;
- if ('separator' in options_) newOptions.separator = options_.separator;
- if ('slash' in options_) newOptions.slash = options_.slash;
- if ('slashEphemeral' in options_) newOptions.slashEphemeral = options_.slashEphemeral;
- if ('slashGuilds' in options_) newOptions.slashGuilds = options_.slashGuilds;
- if ('slashOptions' in options_) newOptions.slashOptions = options_.slashOptions;
- if ('superUserOnly' in options_) newOptions.superUserOnly = options_.superUserOnly;
- if ('typing' in options_) newOptions.typing = options_.typing;
- if ('userPermissions' in options_) newOptions.userPermissions = options_.userPermissions as perm;
super(id, newOptions);
@@ -447,9 +428,14 @@ export class BushCommand extends Command {
}
}
-export interface BushCommand {
- exec(message: BushMessage, args: any): any;
- exec(message: BushMessage | BushSlashMessage, args: any): any;
+export interface BushCommand extends Command {
+ /**
+ * Executes the command.
+ * @param message - Message that triggered the command.
+ * @param args - Evaluated arguments.
+ */
+ exec<R, A>(message: BushMessage, args: A): R;
+ exec<R, A>(message: BushMessage | BushSlashMessage, args: A): R;
}
type SlashOptionKeys =
diff --git a/src/lib/extensions/discord-akairo/BushInhibitor.ts b/src/lib/extensions/discord-akairo/BushInhibitor.ts
index c3f9994..7f13594 100644
--- a/src/lib/extensions/discord-akairo/BushInhibitor.ts
+++ b/src/lib/extensions/discord-akairo/BushInhibitor.ts
@@ -6,6 +6,13 @@ export class BushInhibitor extends Inhibitor {
}
export interface BushInhibitor {
+ /**
+ * Checks if message should be blocked.
+ * A return value of true will block the message.
+ * If returning a Promise, a resolved value of true will block the message.
+ * @param message - Message being handled.
+ * @param command - Command to check.
+ */
exec(message: BushMessage, command: BushCommand): any;
exec(message: BushMessage | BushSlashMessage, command: BushCommand): any;
}
diff --git a/src/lib/extensions/discord-akairo/BushSlashMessage.ts b/src/lib/extensions/discord-akairo/BushSlashMessage.ts
index c0a4a60..448963b 100644
--- a/src/lib/extensions/discord-akairo/BushSlashMessage.ts
+++ b/src/lib/extensions/discord-akairo/BushSlashMessage.ts
@@ -12,6 +12,6 @@ export class BushSlashMessage extends AkairoMessage {
}
}
-export interface BushSlashMessage {
+export interface BushSlashMessage extends AkairoMessage {
get guild(): BushGuild | null;
}
diff --git a/src/lib/extensions/discord.js/BushActivity.ts b/src/lib/extensions/discord.js/BushActivity.ts
index e438918..3f19232 100644
--- a/src/lib/extensions/discord.js/BushActivity.ts
+++ b/src/lib/extensions/discord.js/BushActivity.ts
@@ -2,6 +2,9 @@ import type { BushEmoji, BushPresence } from '#lib';
import { Activity } from 'discord.js';
import type { RawActivityData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Represents an activity that is part of a user's presence.
+ */
export class BushActivity extends Activity {
public declare emoji: BushEmoji | null;
diff --git a/src/lib/extensions/discord.js/BushApplicationCommand.ts b/src/lib/extensions/discord.js/BushApplicationCommand.ts
index 35d598d..8298830 100644
--- a/src/lib/extensions/discord.js/BushApplicationCommand.ts
+++ b/src/lib/extensions/discord.js/BushApplicationCommand.ts
@@ -3,6 +3,9 @@ import type { BushClient, BushGuild } from '#lib';
import { ApplicationCommand, type Snowflake } from 'discord.js';
import type { RawApplicationCommandData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Represents an application command.
+ */
export class BushApplicationCommand<PermissionsFetchType = {}> extends ApplicationCommand<PermissionsFetchType> {
public declare readonly client: BushClient;
public declare guild: BushGuild | null;
diff --git a/src/lib/extensions/discord.js/BushApplicationCommandManager.d.ts b/src/lib/extensions/discord.js/BushApplicationCommandManager.d.ts
index 7947acd..2aa366d 100644
--- a/src/lib/extensions/discord.js/BushApplicationCommandManager.d.ts
+++ b/src/lib/extensions/discord.js/BushApplicationCommandManager.d.ts
@@ -14,12 +14,19 @@ import {
type Snowflake
} from 'discord.js';
+/**
+ * Manages API methods for application commands and stores their cache.
+ */
export class BushApplicationCommandManager<
ApplicationCommandScope = BushApplicationCommand<{ guild: BushGuildResolvable }>,
PermissionsOptionsExtras = { guild: BushGuildResolvable },
PermissionsGuildType = null
> extends CachedManager<Snowflake, ApplicationCommandScope, BushApplicationCommandResolvable> {
public constructor(client: BushClient, iterable?: Iterable<unknown>);
+
+ /**
+ * The manager for permissions of arbitrary commands on arbitrary guilds
+ */
public permissions: BushApplicationCommandPermissionsManager<
{ command?: BushApplicationCommandResolvable } & PermissionsOptionsExtras,
{ command: BushApplicationCommandResolvable } & PermissionsOptionsExtras,
@@ -27,22 +34,112 @@ export class BushApplicationCommandManager<
PermissionsGuildType,
null
>;
+
+ /**
+ * The APIRouter path to the commands
+ * @param id The application command's id
+ * @param guildId The guild's id to use in the path,
+ * ignored when using a {@link GuildApplicationCommandManager}
+ */
private commandPath({ id, guildId }: { id?: Snowflake; guildId?: Snowflake }): unknown;
- public create(command: ApplicationCommandData): Promise<ApplicationCommandScope>;
- public create(command: ApplicationCommandData, guildId: Snowflake): Promise<BushApplicationCommand>;
+
+ /**
+ * Creates an application command.
+ * @param command The command
+ * @param guildId The guild's id to create this command in, ignored when using a {@link GuildApplicationCommandManager}
+ * @example
+ * // Create a new command
+ * client.application.commands.create({
+ * name: 'test',
+ * description: 'A test command',
+ * })
+ * .then(console.log)
+ * .catch(console.error);
+ */
+ public create(command: BushApplicationCommandResolvable, guildId?: Snowflake): Promise<ApplicationCommandScope>;
+
+ /**
+ * Deletes an application command.
+ * @param command The command to delete
+ * @param guildId The guild's id where the command is registered,
+ * ignored when using a {@link GuildApplicationCommandManager}
+ * @example
+ * // Delete a command
+ * guild.commands.delete('123456789012345678')
+ * .then(console.log)
+ * .catch(console.error);
+ */
public delete(command: BushApplicationCommandResolvable, guildId?: Snowflake): Promise<ApplicationCommandScope | null>;
+
+ /**
+ * Edits an application command.
+ * @param command The command to edit
+ * @param data The data to update the command with
+ * @param guildId The guild's id where the command registered,
+ * ignored when using a {@link GuildApplicationCommandManager}
+ * @example
+ * // Edit an existing command
+ * client.application.commands.edit('123456789012345678', {
+ * description: 'New description',
+ * })
+ * .then(console.log)
+ * .catch(console.error);
+ */
public edit(command: BushApplicationCommandResolvable, data: ApplicationCommandData): Promise<ApplicationCommandScope>;
public edit(
command: BushApplicationCommandResolvable,
data: ApplicationCommandData,
guildId: Snowflake
): Promise<BushApplicationCommand>;
+
+ /**
+ * Obtains one or multiple application commands from Discord, or the cache if it's already available.
+ * @param id The application command's id
+ * @param options Additional options for this fetch
+ * @example
+ * // Fetch a single command
+ * client.application.commands.fetch('123456789012345678')
+ * .then(command => console.log(`Fetched command ${command.name}`))
+ * .catch(console.error);
+ * @example
+ * // Fetch all commands
+ * guild.commands.fetch()
+ * .then(commands => console.log(`Fetched ${commands.size} commands`))
+ * .catch(console.error);
+ */
public fetch(id: Snowflake, options: FetchApplicationCommandOptions & { guildId: Snowflake }): Promise<BushApplicationCommand>;
public fetch(options: FetchApplicationCommandOptions): Promise<Collection<string, ApplicationCommandScope>>;
public fetch(id: Snowflake, options?: FetchApplicationCommandOptions): Promise<ApplicationCommandScope>;
public fetch(id?: Snowflake, options?: FetchApplicationCommandOptions): Promise<Collection<Snowflake, ApplicationCommandScope>>;
+
+ /**
+ * Sets all the commands for this application or guild.
+ * @param commands The commands
+ * @param guildId The guild's id to create the commands in,
+ * ignored when using a {@link GuildApplicationCommandManager}
+ * @example
+ * // Set all commands to just this one
+ * client.application.commands.set([
+ * {
+ * name: 'test',
+ * description: 'A test command',
+ * },
+ * ])
+ * .then(console.log)
+ * .catch(console.error);
+ * @example
+ * // Remove all commands
+ * guild.commands.set([])
+ * .then(console.log)
+ * .catch(console.error);
+ */
public set(commands: ApplicationCommandData[]): Promise<Collection<Snowflake, ApplicationCommandScope>>;
public set(commands: ApplicationCommandData[], guildId: Snowflake): Promise<Collection<Snowflake, BushApplicationCommand>>;
+
+ /**
+ * Transforms an {@link ApplicationCommandData} object into something that can be used with the API.
+ * @param command The command to transform
+ */
private static transformCommand(
command: ApplicationCommandData
): Omit<APIApplicationCommand, 'id' | 'application_id' | 'guild_id'>;
diff --git a/src/lib/extensions/discord.js/BushApplicationCommandPermissionsManager.d.ts b/src/lib/extensions/discord.js/BushApplicationCommandPermissionsManager.d.ts
index 5f2e4da..ff32be4 100644
--- a/src/lib/extensions/discord.js/BushApplicationCommandPermissionsManager.d.ts
+++ b/src/lib/extensions/discord.js/BushApplicationCommandPermissionsManager.d.ts
@@ -13,6 +13,9 @@ import {
} from 'discord.js';
import type { ApplicationCommandPermissionTypes } from 'discord.js/typings/enums';
+/**
+ * Manages API methods for permissions of Application Commands.
+ */
export class BushApplicationCommandPermissionsManager<
BaseOptions,
FetchSingleOptions,
@@ -21,18 +24,95 @@ export class BushApplicationCommandPermissionsManager<
CommandIdType
> extends BaseManager {
public constructor(manager: ApplicationCommandManager | GuildApplicationCommandManager | ApplicationCommand);
+
+ /**
+ * The manager or command that this manager belongs to
+ */
private manager: ApplicationCommandManager | GuildApplicationCommandManager | ApplicationCommand;
+ /**
+ * The client that instantiated this Manager
+ */
public client: BushClient;
+
+ /**
+ * The id of the command this manager acts on
+ */
public commandId: CommandIdType;
+
+ /**
+ * The guild that this manager acts on
+ */
public guild: GuildType;
+
+ /**
+ * The id of the guild that this manager acts on
+ */
public guildId: Snowflake | null;
+
+ /**
+ * Add permissions to a command.
+ * @param options Options used to add permissions
+ * @example
+ * // Block a role from the command permissions
+ * guild.commands.permissions.add({ command: '123456789012345678', permissions: [
+ * {
+ * id: '876543211234567890',
+ * type: 'ROLE',
+ * permission: false
+ * },
+ * ]})
+ * .then(console.log)
+ * .catch(console.error);
+ */
public add(
options: FetchSingleOptions & { permissions: ApplicationCommandPermissionData[] }
): Promise<ApplicationCommandPermissions[]>;
+
+ /**
+ * Check whether a permission exists for a user or role
+ * @param options Options used to check permissions
+ * @example
+ * // Check whether a user has permission to use a command
+ * guild.commands.permissions.has({ command: '123456789012345678', permissionId: '876543210123456789' })
+ * .then(console.log)
+ * .catch(console.error);
+ */
public has(options: FetchSingleOptions & { permissionId: BushUserResolvable | BushRoleResolvable }): Promise<boolean>;
+
+ /**
+ * Fetches the permissions for one or multiple commands.
+ * @param options Options used to fetch permissions
+ * @example
+ * // Fetch permissions for one command
+ * guild.commands.permissions.fetch({ command: '123456789012345678' })
+ * .then(perms => console.log(`Fetched permissions for ${perms.length} users`))
+ * .catch(console.error);
+ * @example
+ * // Fetch permissions for all commands in a guild
+ * client.application.commands.permissions.fetch({ guild: '123456789012345678' })
+ * .then(perms => console.log(`Fetched permissions for ${perms.size} commands`))
+ * .catch(console.error);
+ */
public fetch(options: FetchSingleOptions): Promise<ApplicationCommandPermissions[]>;
public fetch(options: BaseOptions): Promise<Collection<Snowflake, ApplicationCommandPermissions[]>>;
+
+ /**
+ * Remove permissions from a command.
+ * @param options Options used to remove permissions
+ * @example
+ * // Remove a user permission from this command
+ * guild.commands.permissions.remove({ command: '123456789012345678', users: '876543210123456789' })
+ * .then(console.log)
+ * .catch(console.error);
+ * @example
+ * // Remove multiple roles from this command
+ * guild.commands.permissions.remove({
+ * command: '123456789012345678', roles: ['876543210123456789', '765432101234567890']
+ * })
+ * .then(console.log)
+ * .catch(console.error);
+ */
public remove(
options:
| (FetchSingleOptions & {
@@ -44,6 +124,37 @@ export class BushApplicationCommandPermissionsManager<
roles: BushRoleResolvable | BushRoleResolvable[];
})
): Promise<ApplicationCommandPermissions[]>;
+
+ /**
+ * Sets the permissions for one or more commands.
+ * @param options Options used to set permissions
+ * @example
+ * // Set the permissions for one command
+ * client.application.commands.permissions.set({ guild: '892455839386304532', command: '123456789012345678',
+ * permissions: [
+ * {
+ * id: '876543210987654321',
+ * type: 'USER',
+ * permission: false,
+ * },
+ * ]})
+ * .then(console.log)
+ * .catch(console.error);
+ * @example
+ * // Set the permissions for all commands
+ * guild.commands.permissions.set({ fullPermissions: [
+ * {
+ * id: '123456789012345678',
+ * permissions: [{
+ * id: '876543210987654321',
+ * type: 'USER',
+ * permission: false,
+ * }],
+ * },
+ * ]})
+ * .then(console.log)
+ * .catch(console.error);
+ */
public set(
options: FetchSingleOptions & { permissions: ApplicationCommandPermissionData[] }
): Promise<ApplicationCommandPermissions[]>;
@@ -52,7 +163,19 @@ export class BushApplicationCommandPermissionsManager<
fullPermissions: GuildApplicationCommandPermissionData[];
}
): Promise<Collection<Snowflake, ApplicationCommandPermissions[]>>;
+
+ /**
+ * The APIRouter path to the commands
+ * @param guildId The guild's id to use in the path,
+ * @param commandId The application command's id
+ */
private permissionsPath(guildId: Snowflake, commandId?: Snowflake): unknown;
+
+ /**
+ * Transforms an {@link ApplicationCommandPermissionData} object into something that can be used with the API.
+ * @param permissions The permissions to transform
+ * @param received Whether these permissions have been received from Discord
+ */
private static transformPermissions(
permissions: ApplicationCommandPermissionData,
received: true
diff --git a/src/lib/extensions/discord.js/BushBaseGuildEmojiManager.d.ts b/src/lib/extensions/discord.js/BushBaseGuildEmojiManager.d.ts
index 7c913a9..347ff65 100644
--- a/src/lib/extensions/discord.js/BushBaseGuildEmojiManager.d.ts
+++ b/src/lib/extensions/discord.js/BushBaseGuildEmojiManager.d.ts
@@ -2,7 +2,15 @@ import type { BushClient, BushEmojiIdentifierResolvable, BushEmojiResolvable, Bu
import { CachedManager, type Snowflake } from 'discord.js';
import { type RawGuildEmojiData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Holds methods to resolve GuildEmojis and stores their cache.
+ */
export class BushBaseGuildEmojiManager extends CachedManager<Snowflake, BushGuildEmoji, BushEmojiResolvable> {
public constructor(client: BushClient, iterable?: Iterable<RawGuildEmojiData>);
+
+ /**
+ * Resolves an EmojiResolvable to an emoji identifier.
+ * @param emoji The emoji resolvable to resolve
+ */
public resolveIdentifier(emoji: BushEmojiIdentifierResolvable): string | null;
}
diff --git a/src/lib/extensions/discord.js/BushBaseGuildTextChannel.ts b/src/lib/extensions/discord.js/BushBaseGuildTextChannel.ts
index 742ea76..9b260dc 100644
--- a/src/lib/extensions/discord.js/BushBaseGuildTextChannel.ts
+++ b/src/lib/extensions/discord.js/BushBaseGuildTextChannel.ts
@@ -8,6 +8,9 @@ import {
} from 'discord.js';
import type { RawGuildChannelData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Represents a text-based guild channel on Discord.
+ */
export class BushBaseGuildTextChannel extends BaseGuildTextChannel {
public declare messages: BushMessageManager;
public declare threads: BushThreadManager<AllowedThreadTypeForTextChannel | AllowedThreadTypeForNewsChannel>;
diff --git a/src/lib/extensions/discord.js/BushBaseGuildVoiceChannel.d.ts b/src/lib/extensions/discord.js/BushBaseGuildVoiceChannel.d.ts
new file mode 100644
index 0000000..21be206
--- /dev/null
+++ b/src/lib/extensions/discord.js/BushBaseGuildVoiceChannel.d.ts
@@ -0,0 +1,13 @@
+import { BaseGuildVoiceChannel, Collection, Snowflake } from 'discord.js';
+import { BushCategoryChannel } from './BushCategoryChannel';
+import { BushGuild } from './BushGuild';
+import { BushGuildMember } from './BushGuildMember';
+
+/**
+ * Represents a voice-based guild channel on Discord.
+ */
+export class BushBaseGuildVoiceChannel extends BaseGuildVoiceChannel {
+ public readonly members: Collection<Snowflake, BushGuildMember>;
+ public guild: BushGuild;
+ public readonly parent: BushCategoryChannel | null;
+}
diff --git a/src/lib/extensions/discord.js/BushButtonInteraction.ts b/src/lib/extensions/discord.js/BushButtonInteraction.ts
index 18d6b35..2bc1c25 100644
--- a/src/lib/extensions/discord.js/BushButtonInteraction.ts
+++ b/src/lib/extensions/discord.js/BushButtonInteraction.ts
@@ -1,15 +1,18 @@
-import type { BushClient, BushGuild, BushGuildMember, BushGuildTextBasedChannel, BushTextBasedChannels, BushUser } from '#lib';
+import type { BushClient, BushGuild, BushGuildMember, BushGuildTextBasedChannel, BushTextBasedChannel, BushUser } from '#lib';
import type { APIInteractionGuildMember } from 'discord-api-types/v9';
import { ButtonInteraction, type CacheType, type CacheTypeReducer } from 'discord.js';
import type { RawMessageButtonInteractionData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Represents a button interaction.
+ */
export class BushButtonInteraction<Cached extends CacheType = CacheType> extends ButtonInteraction<Cached> {
public declare readonly channel: CacheTypeReducer<
Cached,
BushGuildTextBasedChannel | null,
BushGuildTextBasedChannel | null,
BushGuildTextBasedChannel | null,
- BushTextBasedChannels | null
+ BushTextBasedChannel | null
>;
public declare readonly guild: CacheTypeReducer<Cached, BushGuild, null>;
public declare member: CacheTypeReducer<Cached, BushGuildMember, APIInteractionGuildMember>;
diff --git a/src/lib/extensions/discord.js/BushCategoryChannel.ts b/src/lib/extensions/discord.js/BushCategoryChannel.ts
index c30a761..b711a54 100644
--- a/src/lib/extensions/discord.js/BushCategoryChannel.ts
+++ b/src/lib/extensions/discord.js/BushCategoryChannel.ts
@@ -1,10 +1,13 @@
-import { type BushClient, type BushGuild, type BushGuildChannel, type BushGuildMember } from '#lib';
+import { BushNonThreadGuildBasedChannel, type BushClient, type BushGuild, type BushGuildMember } from '#lib';
import { CategoryChannel, type Collection, type Snowflake } from 'discord.js';
import { type RawGuildChannelData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Represents a guild category channel on Discord.
+ */
export class BushCategoryChannel extends CategoryChannel {
public declare readonly client: BushClient;
- public declare readonly children: Collection<Snowflake, BushGuildChannel>;
+ public declare readonly children: Collection<Snowflake, Exclude<BushNonThreadGuildBasedChannel, BushCategoryChannel>>;
public declare guild: BushGuild;
public declare readonly members: Collection<Snowflake, BushGuildMember>;
public declare readonly parent: CategoryChannel | null;
diff --git a/src/lib/extensions/discord.js/BushChannel.d.ts b/src/lib/extensions/discord.js/BushChannel.d.ts
index 9a78b9a..42443ba 100644
--- a/src/lib/extensions/discord.js/BushChannel.d.ts
+++ b/src/lib/extensions/discord.js/BushChannel.d.ts
@@ -1,8 +1,12 @@
-import type { BushClient, BushStageChannel, BushTextBasedChannels, BushThreadChannel, BushVoiceChannel } from '#lib';
+import type { BushClient, BushTextBasedChannel, BushThreadChannel } from '#lib';
import { Channel, type ChannelMention, type Snowflake } from 'discord.js';
import type { ChannelTypes } from 'discord.js/typings/enums';
import type { RawChannelData } from 'discord.js/typings/rawDataTypes';
+import { BushBaseGuildVoiceChannel } from './BushBaseGuildVoiceChannel';
+/**
+ * Represents any channel on Discord.
+ */
export class BushChannel extends Channel {
public constructor(client: BushClient, data?: RawChannelData, immediatePatch?: boolean);
public readonly createdAt: Date;
@@ -11,10 +15,10 @@ export class BushChannel extends Channel {
public id: Snowflake;
public readonly partial: false;
public type: keyof typeof ChannelTypes;
- public delete(): Promise<BushChannel>;
- public fetch(force?: boolean): Promise<BushChannel>;
- public isText(): this is BushTextBasedChannels;
- public isVoice(): this is BushVoiceChannel | BushStageChannel;
+ public delete(): Promise<this>;
+ public fetch(force?: boolean): Promise<this>;
+ public isText(): this is BushTextBasedChannel;
+ public isVoice(): this is BushBaseGuildVoiceChannel;
public isThread(): this is BushThreadChannel;
public toString(): ChannelMention;
}
diff --git a/src/lib/extensions/discord.js/BushChannelManager.d.ts b/src/lib/extensions/discord.js/BushChannelManager.d.ts
index 843b956..514cdd3 100644
--- a/src/lib/extensions/discord.js/BushChannelManager.d.ts
+++ b/src/lib/extensions/discord.js/BushChannelManager.d.ts
@@ -1,8 +1,22 @@
-import type { BushChannel, BushChannelResolvable } from '#lib';
+import type { BushAnyChannel, BushChannelResolvable } from '#lib';
import { CachedManager, type Client, type FetchChannelOptions, type Snowflake } from 'discord.js';
import type { RawChannelData } from 'discord.js/typings/rawDataTypes';
-export class BushChannelManager extends CachedManager<Snowflake, BushChannel, BushChannelResolvable> {
+/**
+ * A manager of channels belonging to a client
+ */
+export class BushChannelManager extends CachedManager<Snowflake, BushAnyChannel, BushChannelResolvable> {
public constructor(client: Client, iterable: Iterable<RawChannelData>);
- public fetch(id: Snowflake, options?: FetchChannelOptions): Promise<BushChannel | null>;
+
+ /**
+ * Obtains a channel from Discord, or the channel cache if it's already available.
+ * @param id The channel's id
+ * @param options Additional options for this fetch
+ * @example
+ * // Fetch a channel by its id
+ * client.channels.fetch('222109930545610754')
+ * .then(channel => console.log(channel.name))
+ * .catch(console.error);
+ */
+ public fetch(id: Snowflake, options?: FetchChannelOptions): Promise<BushAnyChannel | null>;
}
diff --git a/src/lib/extensions/discord.js/BushClientEvents.d.ts b/src/lib/extensions/discord.js/BushClientEvents.d.ts
index 91096bd..10d70f9 100644
--- a/src/lib/extensions/discord.js/BushClientEvents.d.ts
+++ b/src/lib/extensions/discord.js/BushClientEvents.d.ts
@@ -4,16 +4,16 @@ import type {
BushDMChannel,
BushGuild,
BushGuildBan,
- BushGuildChannel,
BushGuildEmoji,
BushGuildMember,
BushMessage,
BushMessageReaction,
BushNewsChannel,
+ BushNonThreadGuildBasedChannel,
BushPresence,
BushRole,
BushStageInstance,
- BushTextBasedChannels,
+ BushTextBasedChannel,
BushTextChannel,
BushThreadChannel,
BushThreadMember,
@@ -29,6 +29,7 @@ import type {
import type { AkairoClientEvents } from 'discord-akairo';
import type {
Collection,
+ GuildScheduledEvent,
Interaction,
InvalidRequestWarningData,
Invite,
@@ -45,12 +46,12 @@ export interface BushClientEvents extends AkairoClientEvents {
oldCommand: BushApplicationCommand | null,
newCommand: BushApplicationCommand
];
- channelCreate: [channel: BushGuildChannel];
- channelDelete: [channel: BushDMChannel | BushGuildChannel];
- channelPinsUpdate: [channel: BushTextBasedChannels, date: Date];
+ channelCreate: [channel: BushNonThreadGuildBasedChannel];
+ channelDelete: [channel: BushDMChannel | BushNonThreadGuildBasedChannel];
+ channelPinsUpdate: [channel: BushTextBasedChannel, date: Date];
channelUpdate: [
- oldChannel: BushDMChannel | BushGuildChannel,
- newChannel: BushDMChannel | BushGuildChannel
+ oldChannel: BushDMChannel | BushNonThreadGuildBasedChannel,
+ newChannel: BushDMChannel | BushNonThreadGuildBasedChannel
];
debug: [message: string];
warn: [message: string];
@@ -145,6 +146,20 @@ export interface BushClientEvents extends AkairoClientEvents {
stickerCreate: [sticker: Sticker];
stickerDelete: [sticker: Sticker];
stickerUpdate: [oldSticker: Sticker, newSticker: Sticker];
+ guildScheduledEventCreate: [guildScheduledEvent: GuildScheduledEvent];
+ guildScheduledEventUpdate: [
+ oldGuildScheduledEvent: GuildScheduledEvent,
+ newGuildScheduledEvent: GuildScheduledEvent
+ ];
+ guildScheduledEventDelete: [guildScheduledEvent: GuildScheduledEvent];
+ guildScheduledEventUserAdd: [
+ guildScheduledEvent: GuildScheduledEvent,
+ user: BushUser
+ ];
+ guildScheduledEventUserRemove: [
+ guildScheduledEvent: GuildScheduledEvent,
+ user: BushUser
+ ];
/* Custom */
bushBan: [
victim: BushGuildMember | BushUser,
diff --git a/src/lib/extensions/discord.js/BushClientUser.d.ts b/src/lib/extensions/discord.js/BushClientUser.d.ts
index c307553..503413b 100644
--- a/src/lib/extensions/discord.js/BushClientUser.d.ts
+++ b/src/lib/extensions/discord.js/BushClientUser.d.ts
@@ -3,22 +3,96 @@ import type {
Base64Resolvable,
BufferResolvable,
ClientPresence,
+ ClientUser,
ClientUserEditData,
PresenceData,
PresenceStatusData
} from 'discord.js';
import { BushUser } from './BushUser';
-export class BushClientUser extends BushUser {
+/**
+ * Represents the logged in client's Discord user.
+ */
+export class BushClientUser extends BushUser implements ClientUser {
+ /**
+ * If the bot's {@link ClientApplication.owner Owner} has MFA enabled on their account
+ */
public mfaEnabled: boolean;
+
+ /**
+ * Represents the client user's presence
+ */
public readonly presence: ClientPresence;
+
+ /**
+ * Whether or not this account has been verified
+ */
public verified: boolean;
+
+ /**
+ * Edits the logged in client.
+ * @param data The new data
+ */
public edit(data: ClientUserEditData): Promise<this>;
+
+ /**
+ * Sets the activity the client user is playing.
+ * @param name Activity being played, or options for setting the activity
+ * @param options Options for setting the activity
+ * @example
+ * // Set the client user's activity
+ * client.user.setActivity('discord.js', { type: 'WATCHING' });
+ */
public setActivity(options?: ActivityOptions): ClientPresence;
public setActivity(name: string, options?: ActivityOptions): ClientPresence;
+
+ /**
+ * Sets/removes the AFK flag for the client user.
+ * @param afk Whether or not the user is AFK
+ * @param shardId Shard Id(s) to have the AFK flag set on
+ */
public setAFK(afk: boolean, shardId?: number | number[]): ClientPresence;
- public setAvatar(avatar: BufferResolvable | Base64Resolvable): Promise<this>;
+
+ /**
+ * Sets the avatar of the logged in client.
+ * @param avatar The new avatar
+ * @example
+ * // Set avatar
+ * client.user.setAvatar('./avatar.png')
+ * .then(user => console.log(`New avatar set!`))
+ * .catch(console.error);
+ */
+ public setAvatar(avatar: BufferResolvable | Base64Resolvable | null): Promise<this>;
+
+ /**
+ * Sets the full presence of the client user.
+ * @param data Data for the presence
+ * @example
+ * // Set the client user's presence
+ * client.user.setPresence({ activities: [{ name: 'with discord.js' }], status: 'idle' });
+ */
public setPresence(data: PresenceData): ClientPresence;
+
+ /**
+ * Sets the status of the client user.
+ * @param status Status to change to
+ * @param shardId Shard id(s) to have the activity set on
+ * @example
+ * // Set the client user's status
+ * client.user.setStatus('idle');
+ */
public setStatus(status: PresenceStatusData, shardId?: number | number[]): ClientPresence;
+
+ /**
+ * Sets the username of the logged in client.
+ * <info>Changing usernames in Discord is heavily rate limited, with only 2 requests
+ * every hour. Use this sparingly!</info>
+ * @param username The new username
+ * @example
+ * // Set username
+ * client.user.setUsername('discordjs')
+ * .then(user => console.log(`My new username is ${user.username}`))
+ * .catch(console.error);
+ */
public setUsername(username: string): Promise<this>;
}
diff --git a/src/lib/extensions/discord.js/BushCommandInteraction.ts b/src/lib/extensions/discord.js/BushCommandInteraction.ts
index 174fd9c..e6643f0 100644
--- a/src/lib/extensions/discord.js/BushCommandInteraction.ts
+++ b/src/lib/extensions/discord.js/BushCommandInteraction.ts
@@ -1,19 +1,26 @@
-import type {
- BushApplicationCommand,
- BushGuild,
- BushGuildChannel,
- BushGuildEmoji,
- BushGuildMember,
- BushRole,
- BushUser
-} from '#lib';
+import type { BushApplicationCommand, BushGuild, BushGuildEmoji, BushGuildMember, BushRole, BushUser } from '#lib';
import type { APIInteractionGuildMember } from 'discord-api-types/v9';
import { CommandInteraction, type CacheType, type CacheTypeReducer, type Invite, type Snowflake } from 'discord.js';
import type { RawCommandInteractionData } from 'discord.js/typings/rawDataTypes';
-import { BushGuildTextBasedChannel, BushTextBasedChannels, type BushClient } from '../discord-akairo/BushClient';
+import {
+ BushGuildTextBasedChannel,
+ BushNonThreadGuildBasedChannel,
+ BushTextBasedChannel,
+ type BushClient
+} from '../discord-akairo/BushClient';
-export type BushGuildResolvable = BushGuild | BushGuildChannel | BushGuildMember | BushGuildEmoji | Invite | BushRole | Snowflake;
+export type BushGuildResolvable =
+ | BushGuild
+ | BushNonThreadGuildBasedChannel
+ | BushGuildMember
+ | BushGuildEmoji
+ | Invite
+ | BushRole
+ | Snowflake;
+/**
+ * Represents a command interaction.
+ */
export class BushCommandInteraction<Cached extends CacheType = CacheType> extends CommandInteraction<Cached> {
public declare readonly client: BushClient;
public declare readonly command: BushApplicationCommand | BushApplicationCommand<{ guild: BushGuildResolvable }> | null;
@@ -22,7 +29,7 @@ export class BushCommandInteraction<Cached extends CacheType = CacheType> extend
BushGuildTextBasedChannel | null,
BushGuildTextBasedChannel | null,
BushGuildTextBasedChannel | null,
- BushTextBasedChannels | null
+ BushTextBasedChannel | null
>;
public declare readonly guild: CacheTypeReducer<Cached, BushGuild, null>;
public declare member: CacheTypeReducer<Cached, BushGuildMember, APIInteractionGuildMember>;
diff --git a/src/lib/extensions/discord.js/BushDMChannel.ts b/src/lib/extensions/discord.js/BushDMChannel.ts
index ca08d7e..9df9275 100644
--- a/src/lib/extensions/discord.js/BushDMChannel.ts
+++ b/src/lib/extensions/discord.js/BushDMChannel.ts
@@ -2,6 +2,9 @@ import type { BushClient, BushMessageManager, BushUser } from '#lib';
import { DMChannel } from 'discord.js';
import type { RawDMChannelData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Represents a direct message channel between two users.
+ */
export class BushDMChannel extends DMChannel {
public declare readonly client: BushClient;
public declare messages: BushMessageManager;
diff --git a/src/lib/extensions/discord.js/BushEmoji.ts b/src/lib/extensions/discord.js/BushEmoji.ts
index 5cdf5ac..9e42e5d 100644
--- a/src/lib/extensions/discord.js/BushEmoji.ts
+++ b/src/lib/extensions/discord.js/BushEmoji.ts
@@ -2,6 +2,9 @@ import type { BushClient } from '#lib';
import { Emoji } from 'discord.js';
import type { RawEmojiData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Represents an emoji, see {@link GuildEmoji} and {@link ReactionEmoji}.
+ */
export class BushEmoji extends Emoji {
public declare readonly client: BushClient;
diff --git a/src/lib/extensions/discord.js/BushGuild.ts b/src/lib/extensions/discord.js/BushGuild.ts
index 9c272ff..e12053e 100644
--- a/src/lib/extensions/discord.js/BushGuild.ts
+++ b/src/lib/extensions/discord.js/BushGuild.ts
@@ -16,6 +16,11 @@ import { Moderation } from '../../common/Moderation.js';
import { Guild as GuildDB } from '../../models/Guild.js';
import { ModLogType } from '../../models/ModLog.js';
+/**
+ * Represents a guild (or a server) on Discord.
+ * <info>It's recommended to see if a guild is available before performing operations or reading data from it. You can
+ * check this with {@link Guild.available}.</info>
+ */
export class BushGuild extends Guild {
public declare readonly client: BushClient;
public declare readonly me: BushGuildMember | null;
@@ -97,6 +102,11 @@ export class BushGuild extends Guild {
return await row.save();
}
+ /**
+ * Get a the log channel configured for a certain log type.
+ * @param logType The type of log channel to get.
+ * @returns Either the log channel or undefined if not configured.
+ */
public async getLogChannel(logType: GuildLogType): Promise<BushTextChannel | undefined> {
const channelId = (await this.getSetting('logChannels'))[logType];
if (!channelId) return undefined;
@@ -107,14 +117,12 @@ export class BushGuild extends Guild {
);
}
- public async bushBan(options: {
- user: BushUserResolvable | UserResolvable;
- reason?: string | null;
- moderator?: BushUserResolvable;
- duration?: number;
- deleteDays?: number;
- evidence?: string;
- }): Promise<'success' | 'missing permissions' | 'error banning' | 'error creating modlog entry' | 'error creating ban entry'> {
+ /**
+ * Bans a user, dms them, creates a mod log entry, and creates a punishment entry.
+ * @param options Options for banning the user.
+ * @returns A string status message of the ban.
+ */
+ public async bushBan(options: BushBanOptions): Promise<BanResponse> {
// checks
if (!this.me!.permissions.has('BAN_MEMBERS')) return 'missing permissions';
@@ -165,18 +173,12 @@ export class BushGuild extends Guild {
return ret;
}
- public async bushUnban(options: {
- user: BushUserResolvable | BushUser;
- reason?: string | null;
- moderator?: BushUserResolvable;
- }): Promise<
- | 'success'
- | 'missing permissions'
- | 'user not banned'
- | 'error unbanning'
- | 'error creating modlog entry'
- | 'error removing ban entry'
- > {
+ /**
+ * Unbans a user, dms them, creates a mod log entry, and destroys the punishment entry.
+ * @param options Options for unbanning the user.
+ * @returns A status message of the unban.
+ */
+ public async bushUnban(options: BushUnbanOptions): Promise<UnbanResponse> {
let caseID: string | undefined = undefined;
let dmSuccessEvent: boolean | undefined = undefined;
const user = (await util.resolveNonCachedUser(options.user))!;
@@ -260,3 +262,70 @@ export class BushGuild extends Guild {
void this.sendLogChannel('error', { embeds: [{ title: title, description: message, color: util.colors.error }] });
}
}
+
+/**
+ * Options for unbanning a user
+ */
+interface BushUnbanOptions {
+ /**
+ * The user to unban
+ */
+ user: BushUserResolvable | BushUser;
+
+ /**
+ * The reason for unbanning the user
+ */
+ reason?: string | null;
+
+ /**
+ * The moderator who unbanned the user
+ */
+ moderator?: BushUserResolvable;
+}
+
+/**
+ * Options for banning a user
+ */
+interface BushBanOptions {
+ /**
+ * The user to ban
+ */
+ user: BushUserResolvable | UserResolvable;
+
+ /**
+ * The reason to ban the user
+ */
+ reason?: string | null;
+
+ /**
+ * The moderator who banned the user
+ */
+ moderator?: BushUserResolvable;
+
+ /**
+ * The duration of the ban
+ */
+ duration?: number;
+
+ /**
+ * The number of days to delete the user's messages for
+ */
+ deleteDays?: number;
+
+ /**
+ * The evidence for the ban
+ */
+ evidence?: string;
+}
+
+type PunishmentResponse = 'success' | 'missing permissions' | 'error creating modlog entry';
+
+/**
+ * Response returned when banning a user
+ */
+type BanResponse = PunishmentResponse | 'error banning' | 'error creating ban entry';
+
+/**
+ * Response returned when unbanning a user
+ */
+type UnbanResponse = PunishmentResponse | 'user not banned' | 'error unbanning' | 'error removing ban entry';
diff --git a/src/lib/extensions/discord.js/BushGuildApplicationCommandManager.d.ts b/src/lib/extensions/discord.js/BushGuildApplicationCommandManager.d.ts
index f8e80ae..4d76b07 100644
--- a/src/lib/extensions/discord.js/BushGuildApplicationCommandManager.d.ts
+++ b/src/lib/extensions/discord.js/BushGuildApplicationCommandManager.d.ts
@@ -9,15 +9,102 @@ import {
import type { ApplicationCommandData, BaseFetchOptions, Collection, Snowflake } from 'discord.js';
import type { RawApplicationCommandData } from 'discord.js/typings/rawDataTypes';
+/**
+ * An extension for guild-specific application commands.
+ */
export class BushGuildApplicationCommandManager extends BushApplicationCommandManager<BushApplicationCommand, {}, BushGuild> {
public constructor(guild: BushGuild, iterable?: Iterable<RawApplicationCommandData>);
public declare readonly client: BushClient;
+
+ /**
+ * The guild that this manager belongs to
+ */
public guild: BushGuild;
- public create(command: ApplicationCommandData): Promise<BushApplicationCommand>;
+
+ /**
+ * Creates an application command.
+ * @param command The command
+ * @param guildId The guild's id to create this command in,
+ * ignored when using a {@link GuildApplicationCommandManager}
+ * @example
+ * // Create a new command
+ * client.application.commands.create({
+ * name: 'test',
+ * description: 'A test command',
+ * })
+ * .then(console.log)
+ * .catch(console.error);
+ */
+ public create(command: BushApplicationCommandResolvable): Promise<BushApplicationCommand>;
+
+ /**
+ * Deletes an application command.
+ * @param command The command to delete
+ * @param guildId The guild's id where the command is registered,
+ * ignored when using a {@link GuildApplicationCommandManager}
+ * @example
+ * // Delete a command
+ * guild.commands.delete('123456789012345678')
+ * .then(console.log)
+ * .catch(console.error);
+ */
public delete(command: BushApplicationCommandResolvable): Promise<BushApplicationCommand | null>;
+
+ /**
+ * Edits an application command.
+ * @param command The command to edit
+ * @param data The data to update the command with
+ * @param guildId The guild's id where the command registered,
+ * ignored when using a {@link GuildApplicationCommandManager}
+ * @example
+ * // Edit an existing command
+ * client.application.commands.edit('123456789012345678', {
+ * description: 'New description',
+ * })
+ * .then(console.log)
+ * .catch(console.error);
+ */
public edit(command: BushApplicationCommandResolvable, data: ApplicationCommandData): Promise<BushApplicationCommand>;
+
+ /**
+ * Obtains one or multiple application commands from Discord, or the cache if it's already available.
+ * @param id The application command's id
+ * @param options Additional options for this fetch
+ * @example
+ * // Fetch a single command
+ * client.application.commands.fetch('123456789012345678')
+ * .then(command => console.log(`Fetched command ${command.name}`))
+ * .catch(console.error);
+ * @example
+ * // Fetch all commands
+ * guild.commands.fetch()
+ * .then(commands => console.log(`Fetched ${commands.size} commands`))
+ * .catch(console.error);
+ */
public fetch(id: Snowflake, options?: BaseFetchOptions): Promise<BushApplicationCommand>;
public fetch(options: BaseFetchOptions): Promise<Collection<Snowflake, BushApplicationCommand>>;
public fetch(id?: undefined, options?: BaseFetchOptions): Promise<Collection<Snowflake, BushApplicationCommand>>;
+
+ /**
+ * Sets all the commands for this application or guild.
+ * @param commands The commands
+ * @param guildId The guild's id to create the commands in,
+ * ignored when using a {@link GuildApplicationCommandManager}
+ * @example
+ * // Set all commands to just this one
+ * client.application.commands.set([
+ * {
+ * name: 'test',
+ * description: 'A test command',
+ * },
+ * ])
+ * .then(console.log)
+ * .catch(console.error);
+ * @example
+ * // Remove all commands
+ * guild.commands.set([])
+ * .then(console.log)
+ * .catch(console.error);
+ */
public set(commands: ApplicationCommandData[]): Promise<Collection<Snowflake, BushApplicationCommand>>;
}
diff --git a/src/lib/extensions/discord.js/BushGuildBan.d.ts b/src/lib/extensions/discord.js/BushGuildBan.d.ts
index 4287792..11875f3 100644
--- a/src/lib/extensions/discord.js/BushGuildBan.d.ts
+++ b/src/lib/extensions/discord.js/BushGuildBan.d.ts
@@ -2,6 +2,9 @@ import type { BushClient, BushGuild, BushUser } from '#lib';
import { GuildBan } from 'discord.js';
import type { RawGuildBanData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Represents a ban in a guild on Discord.
+ */
export class BushGuildBan extends GuildBan {
public constructor(client: BushClient, data: RawGuildBanData, guild: BushGuild);
public guild: BushGuild;
diff --git a/src/lib/extensions/discord.js/BushGuildChannel.ts b/src/lib/extensions/discord.js/BushGuildChannel.ts
index 3324dc8..6880daf 100644
--- a/src/lib/extensions/discord.js/BushGuildChannel.ts
+++ b/src/lib/extensions/discord.js/BushGuildChannel.ts
@@ -2,6 +2,15 @@ import type { BushClient, BushGuild } from '#lib';
import { GuildChannel } from 'discord.js';
import type { RawGuildChannelData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Represents a guild channel from any of the following:
+ * - {@link BushTextChannel}
+ * - {@link BushVoiceChannel}
+ * - {@link BushCategoryChannel}
+ * - {@link BushNewsChannel}
+ * - {@link BushStoreChannel}
+ * - {@link BushStageChannel}
+ */
export class BushGuildChannel extends GuildChannel {
public declare readonly client: BushClient;
public declare guild: BushGuild;
diff --git a/src/lib/extensions/discord.js/BushGuildEmoji.ts b/src/lib/extensions/discord.js/BushGuildEmoji.ts
index 180f78c..2c9d36b 100644
--- a/src/lib/extensions/discord.js/BushGuildEmoji.ts
+++ b/src/lib/extensions/discord.js/BushGuildEmoji.ts
@@ -2,6 +2,9 @@ import type { BushClient, BushGuild, BushGuildEmojiRoleManager, BushUser } from
import { GuildEmoji } from 'discord.js';
import type { RawGuildEmojiData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Represents a custom emoji.
+ */
export class BushGuildEmoji extends GuildEmoji {
public declare readonly client: BushClient;
public declare guild: BushGuild;
diff --git a/src/lib/extensions/discord.js/BushGuildEmojiRoleManager.d.ts b/src/lib/extensions/discord.js/BushGuildEmojiRoleManager.d.ts
index 3aae4f0..9253cad 100644
--- a/src/lib/extensions/discord.js/BushGuildEmojiRoleManager.d.ts
+++ b/src/lib/extensions/discord.js/BushGuildEmojiRoleManager.d.ts
@@ -1,15 +1,51 @@
import type { BushClient, BushGuild, BushGuildEmoji, BushRole, BushRoleResolvable } from '#lib';
import { DataManager, type Collection, type Snowflake } from 'discord.js';
+/**
+ * Manages API methods for roles belonging to emojis and stores their cache.
+ */
export class BushGuildEmojiRoleManager extends DataManager<Snowflake, BushRole, BushRoleResolvable> {
public constructor(emoji: BushGuildEmoji);
public declare readonly client: BushClient;
+
+ /**
+ * The emoji belonging to this manager
+ */
public emoji: BushGuildEmoji;
+
+ /**
+ * The guild belonging to this manager
+ */
public guild: BushGuild;
+
+ /**
+ * Adds a role (or multiple roles) to the list of roles that can use this emoji.
+ * @param roleOrRoles The role or roles to add
+ */
public add(
roleOrRoles: BushRoleResolvable | readonly BushRoleResolvable[] | Collection<Snowflake, BushRole>
): Promise<BushGuildEmoji>;
+
+ /**
+ * Sets the role(s) that can use this emoji.
+ * @param roles The roles or role ids to apply
+ * @example
+ * // Set the emoji's roles to a single role
+ * guildEmoji.roles.set(['391156570408615936'])
+ * .then(console.log)
+ * .catch(console.error);
+ * @example
+ * // Remove all roles from an emoji
+ * guildEmoji.roles.set([])
+ * .then(console.log)
+ * .catch(console.error);
+ */
public set(roles: readonly BushRoleResolvable[] | Collection<Snowflake, BushRole>): Promise<BushGuildEmoji>;
+
+ /**
+ * Removes a role (or multiple roles) from the list of roles that can use this emoji.
+ * @param roleOrRoles The role or roles to remove
+ */
public remove(
roleOrRoles: BushRoleResolvable | readonly BushRoleResolvable[] | Collection<Snowflake, BushRole>
): Promise<BushGuildEmoji>;
diff --git a/src/lib/extensions/discord.js/BushGuildManager.d.ts b/src/lib/extensions/discord.js/BushGuildManager.d.ts
index 4dd0750..95719a3 100644
--- a/src/lib/extensions/discord.js/BushGuildManager.d.ts
+++ b/src/lib/extensions/discord.js/BushGuildManager.d.ts
@@ -10,9 +10,25 @@ import {
} from 'discord.js';
import { type RawGuildData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Manages API methods for Guilds and stores their cache.
+ */
export class BushGuildManager extends CachedManager<Snowflake, BushGuild, BushGuildResolvable> {
public constructor(client: BushClient, iterable?: Iterable<RawGuildData>);
+
+ /**
+ * Creates a guild.
+ * <warn>This is only available to bots in fewer than 10 guilds.</warn>
+ * @param name The name of the guild
+ * @param options Options for creating the guild
+ * @returns The guild that was created
+ */
public create(name: string, options?: GuildCreateOptions): Promise<BushGuild>;
+
+ /**
+ * Obtains one or multiple guilds from Discord, or the guild cache if it's already available.
+ * @param options The guild's id or options
+ */
public fetch(options: Snowflake | FetchGuildOptions): Promise<BushGuild>;
public fetch(options?: FetchGuildsOptions): Promise<Collection<Snowflake, OAuth2Guild>>;
}
diff --git a/src/lib/extensions/discord.js/BushGuildMember.ts b/src/lib/extensions/discord.js/BushGuildMember.ts
index fe9c4c9..f6d5259 100644
--- a/src/lib/extensions/discord.js/BushGuildMember.ts
+++ b/src/lib/extensions/discord.js/BushGuildMember.ts
@@ -1,79 +1,11 @@
-import { Moderation, ModLogType, type BushClient, type BushGuild, type BushRole, type BushUser } from '#lib';
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+import { BushClientEvents, Moderation, ModLogType, type BushClient, type BushGuild, type BushRole, type BushUser } from '#lib';
import { GuildMember, MessageEmbed, type Partialize, type Role } from 'discord.js';
import type { RawGuildMemberData } from 'discord.js/typings/rawDataTypes';
-interface BushPunishmentOptions {
- reason?: string | null;
- moderator?: BushGuildMember;
- evidence?: string;
-}
-
-interface BushTimedPunishmentOptions extends BushPunishmentOptions {
- duration?: number;
-}
-
-interface AddRoleOptions extends BushTimedPunishmentOptions {
- role: BushRole | Role;
- addToModlog: boolean;
-}
-
-interface RemoveRoleOptions extends BushTimedPunishmentOptions {
- role: BushRole | Role;
- addToModlog: boolean;
-}
-
-type PunishmentResponse = 'success' | 'error creating modlog entry' | 'failed to dm';
-
-type WarnResponse = PunishmentResponse;
-
-type AddRoleResponse =
- | PunishmentResponse
- | 'user hierarchy'
- | 'role managed'
- | 'client hierarchy'
- | 'error creating role entry'
- | 'error adding role';
-
-type RemoveRoleResponse =
- | PunishmentResponse
- | 'user hierarchy'
- | 'role managed'
- | 'client hierarchy'
- | 'error removing role entry'
- | 'error removing role';
-
-type MuteResponse =
- | PunishmentResponse
- | 'missing permissions'
- | 'no mute role'
- | 'invalid mute role'
- | 'mute role not manageable'
- | 'error giving mute role'
- | 'error creating mute entry';
-
-type UnmuteResponse =
- | PunishmentResponse
- | 'missing permissions'
- | 'no mute role'
- | 'invalid mute role'
- | 'mute role not manageable'
- | 'error removing mute role'
- | 'error removing mute entry';
-
-type KickResponse = PunishmentResponse | 'missing permissions' | 'error kicking';
-
-interface BushBanOptions extends BushTimedPunishmentOptions {
- deleteDays?: number;
-}
-
-type BanResponse = PunishmentResponse | 'missing permissions' | 'error creating ban entry' | 'error banning';
-
-export type PartialBushGuildMember = Partialize<
- BushGuildMember,
- 'joinedAt' | 'joinedTimestamp',
- 'warn' | 'addRole' | 'removeRole' | 'mute' | 'unmute' | 'bushKick' | 'bushBan' | 'isOwner' | 'isSuperUser'
->;
-
+/**
+ * Represents a member of a guild on Discord.
+ */
export class BushGuildMember extends GuildMember {
public declare readonly client: BushClient;
public declare guild: BushGuild;
@@ -83,6 +15,14 @@ export class BushGuildMember extends GuildMember {
super(client, data, guild);
}
+ /**
+ * Send a punishment dm to the user.
+ * @param punishment The punishment that the user has received.
+ * @param reason The reason the user to be punished.
+ * @param duration The duration of the punishment.
+ * @param sendFooter Whether or not to send the guild's punishment footer with the dm.
+ * @returns Whether or not the dm was sent successfully.
+ */
public async punishDM(punishment: string, reason?: string | null, duration?: number, sendFooter = true): Promise<boolean> {
const ending = await this.guild.getSetting('punishmentEnding');
const dmEmbed =
@@ -98,6 +38,12 @@ export class BushGuildMember extends GuildMember {
return !!dmSuccess;
}
+ /**
+ * Warn the user, create a modlog entry, and send a dm to the user.
+ * @param options Options for warning the user.
+ * @returns An object with the result of the warning, and the case number of the warn.
+ * @emits {@link BushClientEvents.bushWarn}
+ */
public async warn(options: BushPunishmentOptions): Promise<{ result: WarnResponse | null; caseNum: number | null }> {
let caseID: string | undefined = undefined;
let dmSuccessEvent: boolean | undefined = undefined;
@@ -131,6 +77,12 @@ export class BushGuildMember extends GuildMember {
return ret as { result: WarnResponse | null; caseNum: number | null };
}
+ /**
+ * Add a role to the user, if it is a punishment create a modlog entry, and create a punishment entry if it is temporary or a punishment.
+ * @param options Options for adding a role to the user.
+ * @returns A status message for adding the add.
+ * @emits {@link BushClientEvents.bushPunishRole}
+ */
public async addRole(options: AddRoleOptions): Promise<AddRoleResponse> {
const ifShouldAddRole = this.#checkIfShouldAddRole(options.role, options.moderator);
if (ifShouldAddRole !== true) return ifShouldAddRole;
@@ -186,6 +138,12 @@ export class BushGuildMember extends GuildMember {
return ret;
}
+ /**
+ * Remove a role from the user, if it is a punishment create a modlog entry, and destroy a punishment entry if it was temporary or a punishment.
+ * @param options Options for removing a role from the user.
+ * @returns A status message for removing the role.
+ * @emits {@link BushClientEvents.bushPunishRoleRemove}
+ */
public async removeRole(options: RemoveRoleOptions): Promise<RemoveRoleResponse> {
const ifShouldAddRole = this.#checkIfShouldAddRole(options.role, options.moderator);
if (ifShouldAddRole !== true) return ifShouldAddRole;
@@ -237,11 +195,17 @@ export class BushGuildMember extends GuildMember {
return ret;
}
+ /**
+ * Check whether or not a role should be added/removed from the user based on hierarchy.
+ * @param role The role to check if can be modified.
+ * @param moderator The moderator that is trying to add/remove the role.
+ * @returns `true` if the role should be added/removed or a string for the reason why it shouldn't.
+ */
#checkIfShouldAddRole(
role: BushRole | Role,
moderator?: BushGuildMember
): true | 'user hierarchy' | 'role managed' | 'client hierarchy' {
- if (moderator && moderator.roles.highest.position <= role.position /* && this.guild.ownerId !== this.id */) {
+ if (moderator && moderator.roles.highest.position <= role.position && this.guild.ownerId !== this.user.id) {
client.console.debug(`${this.roles.highest.position} <= ${role.position}`);
return 'user hierarchy';
} else if (role.managed) {
@@ -252,6 +216,12 @@ export class BushGuildMember extends GuildMember {
return true;
}
+ /**
+ * Mute the user, create a modlog entry, creates a punishment entry, and dms the user.
+ * @param options Options for muting the user.
+ * @returns A status message for muting the user.
+ * @emits {@link BushClientEvents.bushMute}
+ */
public async mute(options: BushTimedPunishmentOptions): Promise<MuteResponse> {
// checks
if (!this.guild.me!.permissions.has('MANAGE_ROLES')) return 'missing permissions';
@@ -325,6 +295,12 @@ export class BushGuildMember extends GuildMember {
return ret;
}
+ /**
+ * Unmute the user, create a modlog entry, remove the punishment entry, and dm the user.
+ * @param options Options for unmuting the user.
+ * @returns A status message for unmuting the user.
+ * @emits {@link BushClientEvents.bushUnmute}
+ */
public async unmute(options: BushPunishmentOptions): Promise<UnmuteResponse> {
//checks
if (!this.guild.me!.permissions.has('MANAGE_ROLES')) return 'missing permissions';
@@ -393,6 +369,12 @@ export class BushGuildMember extends GuildMember {
return ret;
}
+ /**
+ * Kick the user, create a modlog entry, and dm the user.
+ * @param options Options for kicking the user.
+ * @returns A status message for kicking the user.
+ * @emits {@link BushClientEvents.bushKick}
+ */
public async bushKick(options: BushPunishmentOptions): Promise<KickResponse> {
// checks
if (!this.guild.me?.permissions.has('KICK_MEMBERS') || !this.kickable) return 'missing permissions';
@@ -437,6 +419,12 @@ export class BushGuildMember extends GuildMember {
return ret;
}
+ /**
+ * Ban the user, create a modlog entry, create a punishment entry, and dm the user.
+ * @param options Options for banning the user.
+ * @returns A status message for banning the user.
+ * @emits {@link BushClientEvents.bushBan}
+ */
public async bushBan(options: BushBanOptions): Promise<BanResponse> {
// checks
if (!this.guild.me!.permissions.has('BAN_MEMBERS') || !this.bannable) return 'missing permissions';
@@ -497,11 +485,160 @@ export class BushGuildMember extends GuildMember {
return ret;
}
- public get isOwner(): boolean {
+ /**
+ * Whether or not the user is an owner of the bot.
+ */
+ public isOwner(): boolean {
return client.isOwner(this);
}
- public get isSuperUser(): boolean {
+ /**
+ * Whether or not the user is a super user of the bot.
+ */
+ public isSuperUser(): boolean {
return client.isSuperUser(this);
}
}
+
+/**
+ * Options for punishing a user.
+ */
+interface BushPunishmentOptions {
+ /**
+ * The reason for the punishment.
+ */
+ reason?: string | null;
+
+ /**
+ * The moderator who punished the user.
+ */
+ moderator?: BushGuildMember;
+
+ /**
+ * Evidence for the punishment.
+ */
+ evidence?: string;
+}
+
+/**
+ * Punishment options for punishments that can be temporary.
+ */
+interface BushTimedPunishmentOptions extends BushPunishmentOptions {
+ /**
+ * The duration of the punishment.
+ */
+ duration?: number;
+}
+
+/**
+ * Options for a role add punishment.
+ */
+interface AddRoleOptions extends BushTimedPunishmentOptions {
+ /**
+ * The role to add to the user.
+ */
+ role: BushRole | Role;
+
+ /**
+ * Whether to create a modlog entry for this punishment.
+ */
+ addToModlog: boolean;
+}
+
+/**
+ * Options for a role remove punishment.
+ */
+interface RemoveRoleOptions extends BushTimedPunishmentOptions {
+ /**
+ * The role to remove from the user.
+ */
+ role: BushRole | Role;
+
+ /**
+ * Whether to create a modlog entry for this punishment.
+ */
+ addToModlog: boolean;
+}
+
+/**
+ * Options for banning a user.
+ */
+interface BushBanOptions extends BushTimedPunishmentOptions {
+ /**
+ * The number of days to delete the user's messages for.
+ */
+ deleteDays?: number;
+}
+
+type PunishmentResponse = 'success' | 'error creating modlog entry' | 'failed to dm';
+
+/**
+ * Response returned when warning a user.
+ */
+type WarnResponse = PunishmentResponse;
+
+/**
+ * Response returned when adding a role to a user.
+ */
+type AddRoleResponse =
+ | PunishmentResponse
+ | 'user hierarchy'
+ | 'role managed'
+ | 'client hierarchy'
+ | 'error creating role entry'
+ | 'error adding role';
+
+/**
+ * Response returned when removing a role from a user.
+ */
+type RemoveRoleResponse =
+ | PunishmentResponse
+ | 'user hierarchy'
+ | 'role managed'
+ | 'client hierarchy'
+ | 'error removing role entry'
+ | 'error removing role';
+
+/**
+ * Response returned when muting a user.
+ */
+type MuteResponse =
+ | PunishmentResponse
+ | 'missing permissions'
+ | 'no mute role'
+ | 'invalid mute role'
+ | 'mute role not manageable'
+ | 'error giving mute role'
+ | 'error creating mute entry';
+
+/**
+ * Response returned when unmuting a user.
+ */
+type UnmuteResponse =
+ | PunishmentResponse
+ | 'missing permissions'
+ | 'no mute role'
+ | 'invalid mute role'
+ | 'mute role not manageable'
+ | 'error removing mute role'
+ | 'error removing mute entry';
+
+/**
+ * Response returned when kicking a user.
+ */
+type KickResponse = PunishmentResponse | 'missing permissions' | 'error kicking';
+
+/**
+ * Response returned when banning a user.
+ */
+type BanResponse = PunishmentResponse | 'missing permissions' | 'error creating ban entry' | 'error banning';
+
+export type PartialBushGuildMember = Partialize<
+ BushGuildMember,
+ 'joinedAt' | 'joinedTimestamp',
+ 'warn' | 'addRole' | 'removeRole' | 'mute' | 'unmute' | 'bushKick' | 'bushBan' | 'isOwner' | 'isSuperUser'
+>;
+
+/**
+ * @typedef {BushClientEvents} VSCodePleaseDontRemove
+ */ \ No newline at end of file
diff --git a/src/lib/extensions/discord.js/BushGuildMemberManager.d.ts b/src/lib/extensions/discord.js/BushGuildMemberManager.d.ts
index 0866fce..a0e65e7 100644
--- a/src/lib/extensions/discord.js/BushGuildMemberManager.d.ts
+++ b/src/lib/extensions/discord.js/BushGuildMemberManager.d.ts
@@ -14,25 +14,156 @@ import {
} from 'discord.js';
import type { RawGuildMemberData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Manages API methods for GuildMembers and stores their cache.
+ */
export class BushGuildMemberManager extends CachedManager<Snowflake, BushGuildMember, BushGuildMemberResolvable> {
public constructor(guild: BushGuild, iterable?: Iterable<RawGuildMemberData>);
public declare readonly client: BushClient;
+
+ /**
+ * The guild this manager belongs to
+ */
public guild: BushGuild;
+
+ /**
+ * Adds a user to the guild using OAuth2. Requires the `CREATE_INSTANT_INVITE` permission.
+ * @param user The user to add to the guild
+ * @param options Options for adding the user to the guild
+ */
public add(
user: BushUserResolvable,
options: AddGuildMemberOptions & { fetchWhenExisting: false }
): Promise<BushGuildMember | null>;
public add(user: BushUserResolvable, options: AddGuildMemberOptions): Promise<BushGuildMember>;
+
+ /**
+ * Bans a user from the guild.
+ * @param user The user to ban
+ * @param options Options for the ban
+ * @returns Result object will be resolved as specifically as possible.
+ * If the GuildMember cannot be resolved, the User will instead be attempted to be resolved. If that also cannot
+ * be resolved, the user id will be the result.
+ * Internally calls the GuildBanManager#create method.
+ * @example
+ * // Ban a user by id (or with a user/guild member object)
+ * guild.members.ban('84484653687267328')
+ * .then(kickInfo => console.log(`Banned ${kickInfo.user?.tag ?? kickInfo.tag ?? kickInfo}`))
+ * .catch(console.error);
+ */
public ban(user: BushUserResolvable, options?: BanOptions): Promise<BushGuildMember | BushUser | Snowflake>;
+
+ /**
+ * Edits a member of the guild.
+ * <info>The user must be a member of the guild</info>
+ * @param user The member to edit
+ * @param data The data to edit the member with
+ * @param reason Reason for editing this user
+ */
public edit(user: BushUserResolvable, data: GuildMemberEditData, reason?: string): Promise<void>;
+
+ /**
+ * Fetches member(s) from Discord, even if they're offline.
+ * @param options If a UserResolvable, the user to fetch.
+ * If undefined, fetches all members.
+ * If a query, it limits the results to users with similar usernames.
+ * @example
+ * // Fetch all members from a guild
+ * guild.members.fetch()
+ * .then(console.log)
+ * .catch(console.error);
+ * @example
+ * // Fetch a single member
+ * guild.members.fetch('66564597481480192')
+ * .then(console.log)
+ * .catch(console.error);
+ * @example
+ * // Fetch a single member without checking cache
+ * guild.members.fetch({ user, force: true })
+ * .then(console.log)
+ * .catch(console.error)
+ * @example
+ * // Fetch a single member without caching
+ * guild.members.fetch({ user, cache: false })
+ * .then(console.log)
+ * .catch(console.error);
+ * @example
+ * // Fetch by an array of users including their presences
+ * guild.members.fetch({ user: ['66564597481480192', '191615925336670208'], withPresences: true })
+ * .then(console.log)
+ * .catch(console.error);
+ * @example
+ * // Fetch by query
+ * guild.members.fetch({ query: 'hydra', limit: 1 })
+ * .then(console.log)
+ * .catch(console.error);
+ */
public fetch(
options: BushUserResolvable | FetchMemberOptions | (FetchMembersOptions & { user: BushUserResolvable })
): Promise<BushGuildMember>;
public fetch(options?: FetchMembersOptions): Promise<Collection<Snowflake, BushGuildMember>>;
+
+ /**
+ * Kicks a user from the guild.
+ * <info>The user must be a member of the guild</info>
+ * @param user The member to kick
+ * @param reason Reason for kicking
+ * @returns Result object will be resolved as specifically as possible.
+ * If the GuildMember cannot be resolved, the User will instead be attempted to be resolved. If that also cannot
+ * be resolved, the user's id will be the result.
+ * @example
+ * // Kick a user by id (or with a user/guild member object)
+ * guild.members.kick('84484653687267328')
+ * .then(banInfo => console.log(`Kicked ${banInfo.user?.tag ?? banInfo.tag ?? banInfo}`))
+ * .catch(console.error);
+ */
public kick(user: BushUserResolvable, reason?: string): Promise<BushGuildMember | BushUser | Snowflake>;
+
+ /**
+ * Lists up to 1000 members of the guild.
+ * @param options Options for listing members
+ */
public list(options?: GuildListMembersOptions): Promise<Collection<Snowflake, BushGuildMember>>;
+
+ /**
+ * Prunes members from the guild based on how long they have been inactive.
+ * @param options Options for pruning
+ * @returns The number of members that were/will be kicked
+ * @example
+ * // See how many members will be pruned
+ * guild.members.prune({ dry: true })
+ * .then(pruned => console.log(`This will prune ${pruned} people!`))
+ * .catch(console.error);
+ * @example
+ * // Actually prune the members
+ * guild.members.prune({ days: 1, reason: 'too many people!' })
+ * .then(pruned => console.log(`I just pruned ${pruned} people!`))
+ * .catch(console.error);
+ * @example
+ * // Include members with a specified role
+ * guild.members.prune({ days: 7, roles: ['657259391652855808'] })
+ * .then(pruned => console.log(`I just pruned ${pruned} people!`))
+ * .catch(console.error);
+ */
public prune(options: GuildPruneMembersOptions & { dry?: false; count: false }): Promise<null>;
public prune(options?: GuildPruneMembersOptions): Promise<number>;
+
+ /**
+ * Searches for members in the guild based on a query.
+ * @param options Options for searching members
+ */
public search(options: GuildSearchMembersOptions): Promise<Collection<Snowflake, BushGuildMember>>;
+
+ /**
+ * Unbans a user from the guild. Internally calls the {@link GuildBanManager.remove} method.
+ * @param user The user to unban
+ * @param reason Reason for unbanning user
+ * @returns The user that was unbanned
+ * @example
+ * // Unban a user by id (or with a user/guild member object)
+ * guild.members.unban('84484653687267328')
+ * .then(user => console.log(`Unbanned ${user.username} from ${guild.name}`))
+ * .catch(console.error);
+ */
public unban(user: BushUserResolvable, reason?: string): Promise<BushUser>;
}
diff --git a/src/lib/extensions/discord.js/BushMessage.ts b/src/lib/extensions/discord.js/BushMessage.ts
index 9f6d422..b442196 100644
--- a/src/lib/extensions/discord.js/BushMessage.ts
+++ b/src/lib/extensions/discord.js/BushMessage.ts
@@ -4,7 +4,7 @@ import type {
BushGuild,
BushGuildMember,
BushGuildTextBasedChannel,
- BushTextBasedChannels,
+ BushTextBasedChannel,
BushUser
} from '#lib';
import { Message, type If, type Partialize } from 'discord.js';
@@ -15,19 +15,23 @@ export type PartialBushMessage = Partialize<
'type' | 'system' | 'pinned' | 'tts',
'content' | 'cleanContent' | 'author'
>;
+
+/**
+ * Represents a message on Discord.
+ */
export class BushMessage<Cached extends boolean = boolean> extends Message<Cached> {
public declare readonly client: BushClient;
public declare util: BushCommandUtil<BushMessage<true>>;
public declare readonly guild: If<Cached, BushGuild>;
public declare readonly member: BushGuildMember | null;
public declare author: BushUser;
- public declare readonly channel: If<Cached, BushGuildTextBasedChannel, BushTextBasedChannels>;
+ public declare readonly channel: If<Cached, BushGuildTextBasedChannel, BushTextBasedChannel>;
public constructor(client: BushClient, data: RawMessageData) {
super(client, data);
}
}
-export interface BushMessage {
+export interface BushMessage<Cached extends boolean = boolean> extends Message<Cached> {
fetch(force?: boolean): Promise<BushMessage>;
}
diff --git a/src/lib/extensions/discord.js/BushMessageManager.d.ts b/src/lib/extensions/discord.js/BushMessageManager.d.ts
index f6bc8e7..84918c0 100644
--- a/src/lib/extensions/discord.js/BushMessageManager.d.ts
+++ b/src/lib/extensions/discord.js/BushMessageManager.d.ts
@@ -1,4 +1,4 @@
-import { BushMessageResolvable, type BushMessage, type BushTextBasedChannels } from '#lib';
+import { BushMessageResolvable, BushTextBasedChannel, type BushMessage } from '#lib';
import {
CachedManager,
type BaseFetchOptions,
@@ -11,17 +11,95 @@ import {
} from 'discord.js';
import type { RawMessageData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Manages API methods for Messages and holds their cache.
+ */
export class BushMessageManager extends CachedManager<Snowflake, BushMessage, BushMessageResolvable> {
- public constructor(channel: BushTextBasedChannels, iterable?: Iterable<RawMessageData>);
- public channel: BushTextBasedChannels;
+ public constructor(channel: BushTextBasedChannel, iterable?: Iterable<RawMessageData>);
+
+ /**
+ * The channel that the messages belong to
+ */
+ public channel: BushTextBasedChannel;
+
+ /**
+ * The cache of Messages
+ */
public cache: Collection<Snowflake, BushMessage>;
+
+ /**
+ * Publishes a message in an announcement channel to all channels following it, even if it's not cached.
+ * @param message The message to publish
+ */
public crosspost(message: BushMessageResolvable): Promise<BushMessage>;
+
+ /**
+ * Deletes a message, even if it's not cached.
+ * @param message The message to delete
+ */
public delete(message: BushMessageResolvable): Promise<void>;
+
+ /**
+ * Edits a message, even if it's not cached.
+ * @param message The message to edit
+ * @param options The options to edit the message
+ */
public edit(message: BushMessageResolvable, options: MessagePayload | MessageEditOptions): Promise<BushMessage>;
+
+ /**
+ * Gets a message, or messages, from this channel.
+ * <info>The returned Collection does not contain reaction users of the messages if they were not cached.
+ * Those need to be fetched separately in such a case.</info>
+ * @param message The id of the message to fetch, or query parameters.
+ * @param options Additional options for this fetch
+ * @example
+ * // Get message
+ * channel.messages.fetch('99539446449315840')
+ * .then(message => console.log(message.content))
+ * .catch(console.error);
+ * @example
+ * // Get messages
+ * channel.messages.fetch({ limit: 10 })
+ * .then(messages => console.log(`Received ${messages.size} messages`))
+ * .catch(console.error);
+ * @example
+ * // Get messages and filter by user id
+ * channel.messages.fetch()
+ * .then(messages => console.log(`${messages.filter(m => m.author.id === '84484653687267328').size} messages`))
+ * .catch(console.error);
+ */
public fetch(message: Snowflake, options?: BaseFetchOptions): Promise<BushMessage>;
public fetch(options?: ChannelLogsQueryOptions, cacheOptions?: BaseFetchOptions): Promise<Collection<Snowflake, BushMessage>>;
+
+ /**
+ * Fetches the pinned messages of this channel and returns a collection of them.
+ * <info>The returned Collection does not contain any reaction data of the messages.
+ * Those need to be fetched separately.</info>
+ * @param cache Whether to cache the message(s)
+ * @example
+ * // Get pinned messages
+ * channel.messages.fetchPinned()
+ * .then(messages => console.log(`Received ${messages.size} messages`))
+ * .catch(console.error);
+ */
public fetchPinned(cache?: boolean): Promise<Collection<Snowflake, BushMessage>>;
+
+ /**
+ * Adds a reaction to a message, even if it's not cached.
+ * @param message The message to react to
+ * @param emoji The emoji to react with
+ */
public react(message: BushMessageResolvable, emoji: EmojiIdentifierResolvable): Promise<void>;
+
+ /**
+ * Pins a message to the channel's pinned messages, even if it's not cached.
+ * @param message The message to pin
+ */
public pin(message: BushMessageResolvable): Promise<void>;
+
+ /**
+ * Unpins a message from the channel's pinned messages, even if it's not cached.
+ * @param message The message to unpin
+ */
public unpin(message: BushMessageResolvable): Promise<void>;
}
diff --git a/src/lib/extensions/discord.js/BushMessageReaction.ts b/src/lib/extensions/discord.js/BushMessageReaction.ts
index 51b439a..47d4119 100644
--- a/src/lib/extensions/discord.js/BushMessageReaction.ts
+++ b/src/lib/extensions/discord.js/BushMessageReaction.ts
@@ -4,6 +4,9 @@ import type { RawMessageReactionData } from 'discord.js/typings/rawDataTypes';
export type PartialBushMessageReaction = Partialize<BushMessageReaction, 'count'>;
+/**
+ * Represents a reaction to a message.
+ */
export class BushMessageReaction extends MessageReaction {
public declare readonly client: BushClient;
public declare readonly emoji: BushGuildEmoji | BushReactionEmoji;
diff --git a/src/lib/extensions/discord.js/BushNewsChannel.ts b/src/lib/extensions/discord.js/BushNewsChannel.ts
index 716c57d..7df7f37 100644
--- a/src/lib/extensions/discord.js/BushNewsChannel.ts
+++ b/src/lib/extensions/discord.js/BushNewsChannel.ts
@@ -1,6 +1,9 @@
import type { BushGuild, BushGuildMember, BushMessageManager, BushThreadManager } from '#lib';
import { NewsChannel, type AllowedThreadTypeForNewsChannel, type Collection, type Snowflake } from 'discord.js';
+/**
+ * Represents a guild news channel on Discord.
+ */
export class BushNewsChannel extends NewsChannel {
public declare threads: BushThreadManager<AllowedThreadTypeForNewsChannel>;
public declare guild: BushGuild;
diff --git a/src/lib/extensions/discord.js/BushPresence.ts b/src/lib/extensions/discord.js/BushPresence.ts
index 60408f0..f0a3ba6 100644
--- a/src/lib/extensions/discord.js/BushPresence.ts
+++ b/src/lib/extensions/discord.js/BushPresence.ts
@@ -2,6 +2,9 @@ import type { BushClient, BushGuild, BushGuildMember, BushUser } from '#lib';
import { Presence } from 'discord.js';
import type { RawPresenceData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Represents a user's presence.
+ */
export class BushPresence extends Presence {
public declare guild: BushGuild | null;
public declare readonly member: BushGuildMember | null;
diff --git a/src/lib/extensions/discord.js/BushReactionEmoji.ts b/src/lib/extensions/discord.js/BushReactionEmoji.ts
index b85916c..b2a7eb0 100644
--- a/src/lib/extensions/discord.js/BushReactionEmoji.ts
+++ b/src/lib/extensions/discord.js/BushReactionEmoji.ts
@@ -2,6 +2,11 @@ import type { BushMessageReaction } from '#lib';
import { ReactionEmoji } from 'discord.js';
import type { RawReactionEmojiData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Represents a limited emoji set used for both custom and unicode emojis. Custom emojis
+ * will use this class opposed to the Emoji class when the client doesn't know enough
+ * information about them.
+ */
export class BushReactionEmoji extends ReactionEmoji {
public declare reaction: BushMessageReaction;
diff --git a/src/lib/extensions/discord.js/BushRole.ts b/src/lib/extensions/discord.js/BushRole.ts
index bf09e2d..acf795d 100644
--- a/src/lib/extensions/discord.js/BushRole.ts
+++ b/src/lib/extensions/discord.js/BushRole.ts
@@ -2,6 +2,9 @@ import type { BushClient, BushGuild, BushGuildMember } from '#lib';
import { Role, type Collection, type Snowflake } from 'discord.js';
import type { RawRoleData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Represents a role on Discord.
+ */
export class BushRole extends Role {
public declare guild: BushGuild;
public declare readonly members: Collection<Snowflake, BushGuildMember>;
diff --git a/src/lib/extensions/discord.js/BushSelectMenuInteraction.ts b/src/lib/extensions/discord.js/BushSelectMenuInteraction.ts
index d33ddd3..903b43f 100644
--- a/src/lib/extensions/discord.js/BushSelectMenuInteraction.ts
+++ b/src/lib/extensions/discord.js/BushSelectMenuInteraction.ts
@@ -1,15 +1,18 @@
-import type { BushClient, BushGuild, BushGuildMember, BushGuildTextBasedChannel, BushTextBasedChannels, BushUser } from '#lib';
+import type { BushClient, BushGuild, BushGuildMember, BushGuildTextBasedChannel, BushTextBasedChannel, BushUser } from '#lib';
import type { APIInteractionGuildMember } from 'discord-api-types/v9';
import { SelectMenuInteraction, type CacheType, type CacheTypeReducer } from 'discord.js';
import type { RawMessageSelectMenuInteractionData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Represents a select menu interaction.
+ */
export class BushSelectMenuInteraction<Cached extends CacheType = CacheType> extends SelectMenuInteraction<Cached> {
public declare readonly channel: CacheTypeReducer<
Cached,
BushGuildTextBasedChannel | null,
BushGuildTextBasedChannel | null,
BushGuildTextBasedChannel | null,
- BushTextBasedChannels | null
+ BushTextBasedChannel | null
>;
public declare readonly guild: CacheTypeReducer<Cached, BushGuild, null>;
public declare member: CacheTypeReducer<Cached, BushGuildMember, APIInteractionGuildMember>;
diff --git a/src/lib/extensions/discord.js/BushStageChannel.ts b/src/lib/extensions/discord.js/BushStageChannel.ts
index 1391757..5f6c581 100644
--- a/src/lib/extensions/discord.js/BushStageChannel.ts
+++ b/src/lib/extensions/discord.js/BushStageChannel.ts
@@ -2,11 +2,14 @@ import type { BushCategoryChannel, BushGuild, BushGuildMember, BushStageInstance
import { StageChannel, type Collection, type Snowflake } from 'discord.js';
import type { RawGuildChannelData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Represents a guild stage channel on Discord.
+ */
export class BushStageChannel extends StageChannel {
- public declare readonly instance: BushStageInstance | null;
public declare readonly members: Collection<Snowflake, BushGuildMember>;
public declare guild: BushGuild;
public declare readonly parent: BushCategoryChannel | null;
+ public declare readonly stageInstance: BushStageInstance | null;
public constructor(guild: BushGuild, data?: RawGuildChannelData) {
super(guild, data);
diff --git a/src/lib/extensions/discord.js/BushStageInstance.ts b/src/lib/extensions/discord.js/BushStageInstance.ts
index 3b46bf6..80fa5cf 100644
--- a/src/lib/extensions/discord.js/BushStageInstance.ts
+++ b/src/lib/extensions/discord.js/BushStageInstance.ts
@@ -2,6 +2,9 @@ import type { BushClient, BushGuild, BushStageChannel } from '#lib';
import { StageInstance } from 'discord.js';
import type { RawStageInstanceData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Represents a stage instance.
+ */
export class BushStageInstance extends StageInstance {
public declare readonly channel: BushStageChannel | null;
public declare readonly guild: BushGuild | null;
diff --git a/src/lib/extensions/discord.js/BushStoreChannel.ts b/src/lib/extensions/discord.js/BushStoreChannel.ts
index 918c27b..cb75076 100644
--- a/src/lib/extensions/discord.js/BushStoreChannel.ts
+++ b/src/lib/extensions/discord.js/BushStoreChannel.ts
@@ -2,6 +2,10 @@ import type { BushCategoryChannel, BushClient, BushGuild, BushGuildMember } from
import { StoreChannel, type Collection, type Snowflake } from 'discord.js';
import type { RawGuildChannelData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Represents a guild store channel on Discord.
+ * @deprecated Store channels are deprecated and will be removed from Discord in March 2022. See [Self-serve Game Selling Deprecation](https://support-dev.discord.com/hc/en-us/articles/4414590563479) for more information
+ */
// eslint-disable-next-line deprecation/deprecation
export class BushStoreChannel extends StoreChannel {
public declare guild: BushGuild;
diff --git a/src/lib/extensions/discord.js/BushTextChannel.ts b/src/lib/extensions/discord.js/BushTextChannel.ts
index 57f0833..45e1200 100644
--- a/src/lib/extensions/discord.js/BushTextChannel.ts
+++ b/src/lib/extensions/discord.js/BushTextChannel.ts
@@ -2,6 +2,9 @@ import type { BushGuild, BushMessageManager, BushThreadManager } from '#lib';
import { TextChannel, type AllowedThreadTypeForTextChannel } from 'discord.js';
import type { RawGuildChannelData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Represents a guild text channel on Discord.
+ */
export class BushTextChannel extends TextChannel {
public declare guild: BushGuild;
public declare messages: BushMessageManager;
diff --git a/src/lib/extensions/discord.js/BushThreadChannel.ts b/src/lib/extensions/discord.js/BushThreadChannel.ts
index 5f68213..4310e83 100644
--- a/src/lib/extensions/discord.js/BushThreadChannel.ts
+++ b/src/lib/extensions/discord.js/BushThreadChannel.ts
@@ -10,6 +10,9 @@ import type {
import { ThreadChannel, type Collection, type Snowflake } from 'discord.js';
import type { RawThreadChannelData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Represents a thread channel on Discord.
+ */
export class BushThreadChannel extends ThreadChannel {
public declare guild: BushGuild;
public declare messages: BushMessageManager;
diff --git a/src/lib/extensions/discord.js/BushThreadManager.d.ts b/src/lib/extensions/discord.js/BushThreadManager.d.ts
index c824ae7..1366d68 100644
--- a/src/lib/extensions/discord.js/BushThreadManager.d.ts
+++ b/src/lib/extensions/discord.js/BushThreadManager.d.ts
@@ -14,12 +14,69 @@ import {
} from 'discord.js';
import type { RawThreadChannelData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Manages API methods for {@link BushThreadChannel} objects and stores their cache.
+ */
export class BushThreadManager<AllowedThreadType> extends CachedManager<Snowflake, BushThreadChannel, ThreadChannelResolvable> {
public constructor(channel: TextChannel | NewsChannel, iterable?: Iterable<RawThreadChannelData>);
+
+ /**
+ * The channel this Manager belongs to
+ */
public channel: TextChannel | NewsChannel;
+
+ /**
+ * Creates a new thread in the channel.
+ * @param options Options to create a new thread
+ * @example
+ * // Create a new public thread
+ * channel.threads
+ * .create({
+ * name: 'food-talk',
+ * autoArchiveDuration: 60,
+ * reason: 'Needed a separate thread for food',
+ * })
+ * .then(threadChannel => console.log(threadChannel))
+ * .catch(console.error);
+ * @example
+ * // Create a new private thread
+ * channel.threads
+ * .create({
+ * name: 'mod-talk',
+ * autoArchiveDuration: 60,
+ * type: 'GUILD_PRIVATE_THREAD',
+ * reason: 'Needed a separate thread for moderation',
+ * })
+ * .then(threadChannel => console.log(threadChannel))
+ * .catch(console.error);
+ */
public create(options: ThreadCreateOptions<AllowedThreadType>): Promise<ThreadChannel>;
+
+ /**
+ * Obtains a thread from Discord, or the channel cache if it's already available.
+ * @param options The options to fetch threads. If it is a
+ * ThreadChannelResolvable then the specified thread will be fetched. Fetches all active threads if `undefined`
+ * @param cacheOptions Additional options for this fetch. <warn>The `force` field gets ignored
+ * if `options` is not a {@link ThreadChannelResolvable}</warn>
+ * @example
+ * // Fetch a thread by its id
+ * channel.threads.fetch('831955138126104859')
+ * .then(channel => console.log(channel.name))
+ * .catch(console.error);
+ */
public fetch(options: ThreadChannelResolvable, cacheOptions?: BaseFetchOptions): Promise<ThreadChannel | null>;
public fetch(options?: FetchThreadsOptions, cacheOptions?: { cache?: boolean }): Promise<FetchedThreads>;
+
+ /**
+ * Obtains a set of archived threads from Discord, requires `READ_MESSAGE_HISTORY` in the parent channel.
+ * @param options The options to fetch archived threads
+ * @param cache Whether to cache the new thread objects if they aren't already
+ */
public fetchArchived(options?: FetchArchivedThreadOptions, cache?: boolean): Promise<FetchedThreads>;
+
+ /**
+ * Obtains the accessible active threads from Discord, requires `READ_MESSAGE_HISTORY` in the parent channel.
+ * @param cache Whether to cache the new thread objects if they aren't already
+ */
public fetchActive(cache?: boolean): Promise<FetchedThreads>;
}
diff --git a/src/lib/extensions/discord.js/BushThreadMember.ts b/src/lib/extensions/discord.js/BushThreadMember.ts
index fa7588e..a316046 100644
--- a/src/lib/extensions/discord.js/BushThreadMember.ts
+++ b/src/lib/extensions/discord.js/BushThreadMember.ts
@@ -2,6 +2,9 @@ import type { BushGuildMember, BushThreadChannel, BushUser } from '#lib';
import { ThreadMember } from 'discord.js';
import type { RawThreadMemberData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Represents a Member for a Thread.
+ */
export class BushThreadMember extends ThreadMember {
public declare readonly guildMember: BushGuildMember | null;
public declare readonly user: BushUser | null;
diff --git a/src/lib/extensions/discord.js/BushThreadMemberManager.d.ts b/src/lib/extensions/discord.js/BushThreadMemberManager.d.ts
index 7560c0e..dedf102 100644
--- a/src/lib/extensions/discord.js/BushThreadMemberManager.d.ts
+++ b/src/lib/extensions/discord.js/BushThreadMemberManager.d.ts
@@ -2,13 +2,42 @@ import type { BushClient, BushThreadChannel, BushThreadMember, BushThreadMemberR
import { CachedManager, type BaseFetchOptions, type Collection, type Snowflake, type UserResolvable } from 'discord.js';
import type { RawThreadMemberData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Manages API methods for GuildMembers and stores their cache.
+ */
export class BushThreadMemberManager extends CachedManager<Snowflake, BushThreadMember, BushThreadMemberResolvable> {
public constructor(thread: BushThreadChannel, iterable?: Iterable<RawThreadMemberData>);
public declare readonly client: BushClient;
+
+ /**
+ * The thread this manager belongs to
+ */
public thread: BushThreadChannel;
+
+ /**
+ * Adds a member to the thread.
+ * @param member The member to add
+ * @param reason The reason for adding this member
+ */
public add(member: UserResolvable | '@me', reason?: string): Promise<Snowflake>;
+
+ /**
+ * Fetches member(s) for the thread from Discord, requires access to the `GUILD_MEMBERS` gateway intent.
+ * @param member The member to fetch. If `undefined`, all members in the thread are fetched, and will be
+ * cached based on `options.cache`. If boolean, this serves the purpose of `options.cache`.
+ * @param options Additional options for this fetch
+ */
public fetch(member?: UserResolvable, options?: BaseFetchOptions): Promise<BushThreadMember>;
- /** @deprecated Use `fetch(member, options)` instead. */
+
+ /**
+ * @deprecated Use `fetch(member, options)` instead.
+ */
public fetch(cache?: boolean): Promise<Collection<Snowflake, BushThreadMember>>;
+
+ /**
+ * Remove a user from the thread.
+ * @param id The id of the member to remove
+ * @param reason The reason for removing this member from the thread
+ */
public remove(id: Snowflake | '@me', reason?: string): Promise<Snowflake>;
}
diff --git a/src/lib/extensions/discord.js/BushUser.ts b/src/lib/extensions/discord.js/BushUser.ts
index 9b2c92a..5ab288e 100644
--- a/src/lib/extensions/discord.js/BushUser.ts
+++ b/src/lib/extensions/discord.js/BushUser.ts
@@ -4,6 +4,9 @@ import type { RawUserData } from 'discord.js/typings/rawDataTypes';
export type PartialBushUser = Partialize<BushUser, 'username' | 'tag' | 'discriminator' | 'isOwner' | 'isSuperUser'>;
+/**
+ * Represents a user on Discord.
+ */
export class BushUser extends User {
public declare readonly client: BushClient;
public declare readonly dmChannel: BushDMChannel | null;
@@ -12,10 +15,16 @@ export class BushUser extends User {
super(client, data);
}
+ /**
+ * Indicates whether the user is an owner of the bot.
+ */
public isOwner(): boolean {
return client.isOwner(this);
}
+ /**
+ * Indicates whether the user is a superuser of the bot.
+ */
public isSuperUser(): boolean {
return client.isSuperUser(this);
}
diff --git a/src/lib/extensions/discord.js/BushUserManager.d.ts b/src/lib/extensions/discord.js/BushUserManager.d.ts
index 595332a..5d814da 100644
--- a/src/lib/extensions/discord.js/BushUserManager.d.ts
+++ b/src/lib/extensions/discord.js/BushUserManager.d.ts
@@ -1,8 +1,59 @@
-import type { BushClient, BushUser, BushUserResolvable } from '#lib';
-import { CachedManager, type BaseFetchOptions, type Snowflake } from 'discord.js';
+import type { BushClient, BushDMChannel, BushUser, BushUserResolvable } from '#lib';
+import {
+ CachedManager,
+ Message,
+ MessageOptions,
+ MessagePayload,
+ UserFlags,
+ type BaseFetchOptions,
+ type Snowflake
+} from 'discord.js';
import type { RawUserData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Manages API methods for users and stores their cache.
+ */
export class BushUserManager extends CachedManager<Snowflake, BushUser, BushUserResolvable> {
- public constructor(client: BushClient, iterable?: Iterable<RawUserData>);
- public fetch(id: Snowflake, options?: BaseFetchOptions): Promise<BushUser>;
+ private constructor(client: BushClient, iterable?: Iterable<RawUserData>);
+
+ /**
+ * The DM between the client's user and a user
+ * @param userId The user id
+ * @private
+ */
+ public dmChannel(userId: Snowflake): BushDMChannel | null;
+
+ /**
+ * Creates a {@link DMChannel} between the client and a user.
+ * @param user The UserResolvable to identify
+ * @param options Additional options for this fetch
+ */
+ public createDM(user: BushUserResolvable, options?: BaseFetchOptions): Promise<BushDMChannel>;
+
+ /**
+ * Deletes a {@link DMChannel} (if one exists) between the client and a user. Resolves with the channel if successful.
+ * @param user The UserResolvable to identify
+ */
+ public deleteDM(user: BushUserResolvable): Promise<BushDMChannel>;
+
+ /**
+ * Obtains a user from Discord, or the user cache if it's already available.
+ * @param user The user to fetch
+ * @param options Additional options for this fetch
+ */
+ public fetch(user: BushUserResolvable, options?: BaseFetchOptions): Promise<BushUser>;
+
+ /**
+ * Fetches a user's flags.
+ * @param user The UserResolvable to identify
+ * @param options Additional options for this fetch
+ */
+ public fetchFlags(user: BushUserResolvable, options?: BaseFetchOptions): Promise<UserFlags>;
+
+ /**
+ * Sends a message to a user.
+ * @param user The UserResolvable to identify
+ * @param options The options to provide
+ */
+ public send(user: BushUserResolvable, options: string | MessagePayload | MessageOptions): Promise<Message>;
}
diff --git a/src/lib/extensions/discord.js/BushVoiceChannel.ts b/src/lib/extensions/discord.js/BushVoiceChannel.ts
index d5cdafc..9f246e5 100644
--- a/src/lib/extensions/discord.js/BushVoiceChannel.ts
+++ b/src/lib/extensions/discord.js/BushVoiceChannel.ts
@@ -2,6 +2,9 @@ import type { BushClient, BushGuild, BushGuildMember } from '#lib';
import { VoiceChannel, type Collection, type Snowflake } from 'discord.js';
import type { RawGuildChannelData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Represents a guild voice channel on Discord.
+ */
export class BushVoiceChannel extends VoiceChannel {
public declare readonly client: BushClient;
public declare readonly members: Collection<Snowflake, BushGuildMember>;
diff --git a/src/lib/extensions/discord.js/BushVoiceState.ts b/src/lib/extensions/discord.js/BushVoiceState.ts
index a479143..3f19201 100644
--- a/src/lib/extensions/discord.js/BushVoiceState.ts
+++ b/src/lib/extensions/discord.js/BushVoiceState.ts
@@ -1,10 +1,13 @@
-import type { BushGuild, BushGuildMember, BushStageChannel, BushVoiceChannel } from '#lib';
+import type { BushClient, BushGuild, BushGuildMember, BushVoiceBasedChannel } from '#lib';
import { VoiceState } from 'discord.js';
import type { RawVoiceStateData } from 'discord.js/typings/rawDataTypes';
+/**
+ * Represents the voice state for a Guild Member.
+ */
export class BushVoiceState extends VoiceState {
- // public declare readonly client: BushClient;
- public declare readonly channel: BushVoiceChannel | BushStageChannel | null;
+ public declare readonly client: BushClient;
+ public declare readonly channel: BushVoiceBasedChannel | null;
public declare guild: BushGuild;
public declare readonly member: BushGuildMember | null;
diff --git a/src/lib/extensions/global.d.ts b/src/lib/extensions/global.d.ts
index 1df86bb..a6f2b5a 100644
--- a/src/lib/extensions/global.d.ts
+++ b/src/lib/extensions/global.d.ts
@@ -1,7 +1,14 @@
/* eslint-disable no-var */
import type { BushClient, BushClientUtil } from '#lib';
declare global {
+ /**
+ * The bushbot client.
+ */
var client: BushClient;
+
+ /**
+ * The bushbot client util.
+ */
var util: BushClientUtil;
// eslint-disable-next-line @typescript-eslint/no-unused-vars