@sapphire/framework
Version:
Discord bot framework built for advanced and amazing bots.
1,148 lines (1,133 loc) • 170 kB
text/typescript
import { ChannelTypes, GuildBasedChannelTypes, TextBasedChannelTypes, AnyInteraction } from '@sapphire/discord.js-utilities';
import { ArgumentStream, IUnorderedStrategy, Lexer } from '@sapphire/lexure';
import * as _sapphire_result from '@sapphire/result';
import { Result, Option } from '@sapphire/result';
export * from '@sapphire/result';
import { Awaitable, Nullish } from '@sapphire/utilities';
export { Awaitable } from '@sapphire/utilities';
import * as discord_js from 'discord.js';
import { Message, DMChannel, CategoryChannel, NewsChannel, ThreadChannel, ChannelType, TextChannel, StageChannel, VoiceChannel, GuildMember, Role, User, ChatInputCommandInteraction, ContextMenuCommandInteraction, Collection, Snowflake, PermissionResolvable, ChatInputApplicationCommandData, UserApplicationCommandData, MessageApplicationCommandData, ApplicationCommandManager, ApplicationCommand, CommandInteraction, TextBasedChannel, PermissionsBitField, AutocompleteInteraction, PermissionsString, Interaction, ClientEvents, Client, Events as Events$1, ClientOptions, Guild, PartialDMChannel } from 'discord.js';
import { URL } from 'node:url';
import { AliasPiece, Piece, AliasPieceJSON, AliasStore, Store, StoreRegistry, LoaderStrategy } from '@sapphire/pieces';
export { AliasPiece, AliasPieceJSON, AliasPieceOptions, AliasStore, Container, LoaderError, LoaderPieceContext, MissingExportsError, Piece, PieceContext, PieceJSON, PieceLocationJSON, PieceOf, PieceOptions, Store, StoreManagerManuallyRegisteredPiece, StoreManuallyRegisteredPiece, StoreOf, StoreOptions, StoreRegistry, StoreRegistryEntries, StoreRegistryKey, StoreRegistryValue, container } from '@sapphire/pieces';
import { SlashCommandBuilder, SlashCommandSubcommandsOnlyBuilder, SlashCommandOptionsOnlyBuilder, ContextMenuCommandBuilder } from '@discordjs/builders';
import { RateLimitManager } from '@sapphire/ratelimits';
import { EventEmitter } from 'node:events';
/**
* The UserError class to be emitted in the pieces.
* @property name This will be `'UserError'` and can be used to distinguish the type of error when any error gets thrown
* @example
* ```typescript
* throw new UserError({
* identifier: 'AddArgumentError',
* message: 'You must write two numbers, but the second one did not match.',
* context: { received: 2, expected: 3 }
* });
* ```
*/
declare class UserError extends Error {
/**
* An identifier, useful to localize emitted errors.
*/
readonly identifier: string;
/**
* User-provided context.
*/
readonly context: unknown;
/**
* Constructs an UserError.
* @param options The UserError options
*/
constructor(options: UserError.Options);
get name(): string;
}
declare namespace UserError {
/**
* The options for {@link UserError}.
* @since 1.0.0
*/
interface Options {
/**
* The identifier for this error.
* @since 1.0.0
*/
identifier: string;
/**
* The message to be passed to the Error constructor.
* @since 1.0.0
*/
message?: string;
/**
* The extra context to provide more information about this error.
* @since 1.0.0
* @default null
*/
context?: unknown;
}
}
declare enum Identifiers {
ArgsMissing = "argsMissing",
ArgsUnavailable = "argsUnavailable",
ArgumentBooleanError = "booleanError",
ArgumentChannelError = "channelError",
ArgumentDateError = "dateError",
ArgumentDateTooEarly = "dateTooEarly",
ArgumentDateTooFar = "dateTooFar",
ArgumentDMChannelError = "dmChannelError",
ArgumentEmojiError = "emojiError",
ArgumentFloatError = "floatError",
ArgumentFloatTooLarge = "floatTooLarge",
ArgumentFloatTooSmall = "floatTooSmall",
ArgumentGuildError = "guildError",
ArgumentGuildCategoryChannelError = "categoryChannelError",
ArgumentGuildChannelError = "guildChannelError",
ArgumentGuildChannelMissingGuildError = "guildChannelMissingGuildError",
ArgumentGuildNewsChannelError = "guildNewsChannelError",
ArgumentGuildNewsThreadChannelError = "guildNewsThreadChannelError",
ArgumentGuildPrivateThreadChannelError = "guildPrivateThreadChannelError",
ArgumentGuildPublicThreadChannelError = "guildPublicThreadChannelError",
ArgumentGuildStageVoiceChannelError = "guildStageVoiceChannelError",
ArgumentGuildTextChannelError = "guildTextChannelError",
ArgumentGuildThreadChannelError = "guildThreadChannelError",
ArgumentGuildVoiceChannelError = "guildVoiceChannelError",
ArgumentHyperlinkError = "hyperlinkError",
ArgumentIntegerError = "integerError",
ArgumentIntegerTooLarge = "integerTooLarge",
ArgumentIntegerTooSmall = "integerTooSmall",
ArgumentMemberError = "memberError",
ArgumentMemberMissingGuild = "memberMissingGuild",
ArgumentMessageError = "messageError",
ArgumentNumberError = "numberError",
ArgumentNumberTooLarge = "numberTooLarge",
ArgumentNumberTooSmall = "numberTooSmall",
ArgumentRoleError = "roleError",
ArgumentRoleMissingGuild = "roleMissingGuild",
ArgumentStringTooLong = "stringTooLong",
ArgumentStringTooShort = "stringTooShort",
ArgumentUserError = "userError",
ArgumentEnumEmptyError = "enumEmptyError",
ArgumentEnumError = "enumError",
CommandDisabled = "commandDisabled",
PreconditionCooldown = "preconditionCooldown",
/** @deprecated Use {@link PreconditionRunIn} instead. */
PreconditionDMOnly = "preconditionDmOnly",
/** @deprecated Use {@link PreconditionRunIn} instead. */
PreconditionGuildNewsOnly = "preconditionGuildNewsOnly",
/** @deprecated Use {@link PreconditionRunIn} instead. */
PreconditionGuildNewsThreadOnly = "preconditionGuildNewsThreadOnly",
/** @deprecated Use {@link PreconditionRunIn} instead. */
PreconditionGuildOnly = "preconditionGuildOnly",
/** @deprecated Use {@link PreconditionRunIn} instead. */
PreconditionGuildPrivateThreadOnly = "preconditionGuildPrivateThreadOnly",
/** @deprecated Use {@link PreconditionRunIn} instead. */
PreconditionGuildPublicThreadOnly = "preconditionGuildPublicThreadOnly",
/** @deprecated Use {@link PreconditionRunIn} instead. */
PreconditionGuildTextOnly = "preconditionGuildTextOnly",
/** @deprecated Use {@link PreconditionRunIn} instead. */
PreconditionGuildVoiceOnly = "preconditionGuildVoiceOnly",
PreconditionNSFW = "preconditionNsfw",
PreconditionClientPermissions = "preconditionClientPermissions",
PreconditionClientPermissionsNoClient = "preconditionClientPermissionsNoClient",
PreconditionClientPermissionsNoPermissions = "preconditionClientPermissionsNoPermissions",
PreconditionRunIn = "preconditionRunIn",
PreconditionUserPermissions = "preconditionUserPermissions",
PreconditionUserPermissionsNoPermissions = "preconditionUserPermissionsNoPermissions",
/** @deprecated Use {@link PreconditionRunIn} instead. */
PreconditionThreadOnly = "preconditionThreadOnly",
PreconditionUnavailable = "preconditionUnavailable",
PreconditionMissingMessageHandler = "preconditionMissingMessageHandler",
PreconditionMissingChatInputHandler = "preconditionMissingChatInputHandler",
PreconditionMissingContextMenuHandler = "preconditionMissingContextMenuHandler"
}
declare function resolveEmoji(parameter: string): Result<EmojiObject, Identifiers>;
interface EmojiObject {
name: string | null;
id: string | null;
animated?: boolean;
}
declare enum CooldownLevel {
Author = "author",
Channel = "channel",
Guild = "guild"
}
declare enum PluginHook {
PreGenericsInitialization = "preGenericsInitialization",
PreInitialization = "preInitialization",
PostInitialization = "postInitialization",
PreLogin = "preLogin",
PostLogin = "postLogin"
}
/**
* The scope the cooldown applies to.
*/
declare enum BucketScope {
/**
* Per channel cooldowns.
*/
Channel = 0,
/**
* Global cooldowns.
*/
Global = 1,
/**
* Per guild cooldowns.
*/
Guild = 2,
/**
* Per user cooldowns.
*/
User = 3
}
declare enum RegisterBehavior {
Overwrite = "OVERWRITE",
LogToConsole = "LOG_TO_CONSOLE",
/**
* Finds all differences in the commands provided using our internal computation method, and logs them to the console, while applying them.
*
* @danger This can potentially cause slowdowns when booting up your bot as computing differences on big commands can take a while.
* We recommend you use `OVERWRITE` instead in production.
*/
VerboseOverwrite = "VERBOSE_OVERWRITE",
/**
* Makes Sapphire handle all command registrations, removals, and updates for you.
*
* This mode can only be set as the **default** behavior, and cannot be set per-command.
*
* In this mode:
* - any `idHints` set per-command are no longer respected, and can be omitted.
* - any `behaviorWhenNotIdentical` that are set per-command are no longer respected, and can be omitted.
* - any application commands that are *not* registered through Sapphire's {@link ApplicationCommandRegistry} are removed from the application.
* - the same applies for guild commands, but only for guilds that are registered in the registry via `guildIds`.
*/
BulkOverwrite = "BULK_OVERWRITE"
}
declare enum InternalRegistryAPIType {
ChatInput = 0,
ContextMenu = 1
}
/**
* The allowed values for {@link CommandOptions.runIn} as an enum.
* @since 2.0.0
*/
declare enum CommandOptionsRunTypeEnum {
Dm = "DM",
GuildText = "GUILD_TEXT",
GuildVoice = "GUILD_VOICE",
GuildNews = "GUILD_NEWS",
GuildNewsThread = "GUILD_NEWS_THREAD",
GuildPublicThread = "GUILD_PUBLIC_THREAD",
GuildPrivateThread = "GUILD_PRIVATE_THREAD",
GuildAny = "GUILD_ANY"
}
/**
* The available command pre-conditions.
* @since 2.0.0
*/
declare enum CommandPreConditions {
Cooldown = "Cooldown",
/** @deprecated Use {@link RunIn} instead. */
DirectMessageOnly = "DMOnly",
RunIn = "RunIn",
/** @deprecated Use {@link RunIn} instead. */
GuildNewsOnly = "GuildNewsOnly",
/** @deprecated Use {@link RunIn} instead. */
GuildNewsThreadOnly = "GuildNewsThreadOnly",
/** @deprecated Use {@link RunIn} instead. */
GuildOnly = "GuildOnly",
/** @deprecated Use {@link RunIn} instead. */
GuildPrivateThreadOnly = "GuildPrivateThreadOnly",
/** @deprecated Use {@link RunIn} instead. */
GuildPublicThreadOnly = "GuildPublicThreadOnly",
/** @deprecated Use {@link RunIn} instead. */
GuildTextOnly = "GuildTextOnly",
/** @deprecated Use {@link RunIn} instead. */
GuildVoiceOnly = "GuildVoiceOnly",
/** @deprecated Use {@link RunIn} instead. */
GuildThreadOnly = "GuildThreadOnly",
NotSafeForWork = "NSFW",
ClientPermissions = "ClientPermissions",
UserPermissions = "UserPermissions"
}
/**
* The strategy options used in Sapphire.
*/
interface FlagStrategyOptions {
/**
* The accepted flags. Flags are key-only identifiers that can be placed anywhere in the command. Two different types are accepted:
* * An array of strings, e.g. [`silent`].
* * A boolean defining whether the strategy should accept all keys (`true`) or none at all (`false`).
* @default []
*/
flags?: readonly string[] | boolean;
/**
* The accepted options. Options are key-value identifiers that can be placed anywhere in the command. Two different types are accepted:
* * An array of strings, e.g. [`silent`].
* * A boolean defining whether the strategy should accept all keys (`true`) or none at all (`false`).
* @default []
*/
options?: readonly string[] | boolean;
/**
* The prefixes for both flags and options.
* @default ['--', '-', '—']
*/
prefixes?: string[];
/**
* The flag separators.
* @default ['=', ':']
*/
separators?: string[];
}
declare class ApplicationCommandRegistry {
/**
* The piece this registry is for.
*/
readonly commandName: string;
/**
* A set of all chat input command names and ids that point to this registry.
* You should not use this field directly, but instead use {@link ApplicationCommandRegistry.globalChatInputCommandIds}
*/
readonly chatInputCommands: Set<string>;
/**
* A set of all context menu command names and ids that point to this registry.
* You should not use this field directly, but instead use {@link ApplicationCommandRegistry.globalContextMenuCommandIds}
*/
readonly contextMenuCommands: Set<string>;
/**
* The guild ids that we need to fetch the commands for.
*/
readonly guildIdsToFetch: Set<string>;
/**
* The global slash command id for this command.
* @deprecated This field will only show the first global command id registered for this registry.
* Use {@link ApplicationCommandRegistry.globalChatInputCommandIds} instead.
*/
globalCommandId: string | null;
/**
* A set of all registered and valid global chat input command ids that point to this registry.
*/
readonly globalChatInputCommandIds: Set<string>;
/**
* A set of all registered and valid global context menu command ids that point to this registry.
*/
readonly globalContextMenuCommandIds: Set<string>;
/**
* The guild command ids for this command.
* @deprecated This field will only show the first guild command id registered for this registry per guild.
* Use {@link ApplicationCommandRegistry.guildIdToChatInputCommandIds} and {@link ApplicationCommandRegistry.guildIdToContextMenuCommandIds} instead.
*/
readonly guildCommandIds: Collection<string, string>;
/**
* A map of guild ids to a set of registered and valid chat input command ids that point to this registry.
*/
readonly guildIdToChatInputCommandIds: Collection<string, Set<string>>;
/**
* A map of guild ids to a set of registered and valid context menu command ids that point to this registry.
*/
readonly guildIdToContextMenuCommandIds: Collection<string, Set<string>>;
private readonly apiCalls;
constructor(commandName: string);
get command(): Command<Args, CommandOptions> | undefined;
registerChatInputCommand(command: ChatInputApplicationCommandData | SlashCommandBuilder | SlashCommandSubcommandsOnlyBuilder | SlashCommandOptionsOnlyBuilder | Omit<SlashCommandBuilder, 'addSubcommand' | 'addSubcommandGroup'> | ((builder: SlashCommandBuilder) => unknown), options?: ApplicationCommandRegistryRegisterOptions): this;
registerContextMenuCommand(command: UserApplicationCommandData | MessageApplicationCommandData | ContextMenuCommandBuilder | ((builder: ContextMenuCommandBuilder) => unknown), options?: ApplicationCommandRegistryRegisterOptions): this;
addChatInputCommandNames(...names: string[] | string[][]): this;
addContextMenuCommandNames(...names: string[] | string[][]): this;
addChatInputCommandIds(...commandIds: string[] | string[][]): this;
addContextMenuCommandIds(...commandIds: string[] | string[][]): this;
protected runAPICalls(applicationCommands: ApplicationCommandManager, globalCommands: Collection<string, ApplicationCommand>, guildCommands: Map<string, Collection<string, ApplicationCommand>>): Promise<void>;
protected handleIdAddition(type: InternalRegistryAPIType, id: string, guildId?: string | null): void;
private getGuildIdsToRegister;
private processGuildIds;
private handleAPICall;
private handleCommandPresent;
private logCommandDifferencesFound;
private createMissingCommand;
private info;
private error;
private warn;
private debug;
private trace;
}
declare namespace ApplicationCommandRegistry {
interface RegisterOptions {
/**
* If this is specified, the application commands will only be registered for these guild ids.
*/
guildIds?: string[];
/**
* If we should register the command when it is missing
* @default true
*/
registerCommandIfMissing?: boolean;
/**
* Specifies what we should do when the command is present, but not identical with the data you provided
* @default `ApplicationCommandRegistries.getDefaultBehaviorWhenNotIdentical()`
*/
behaviorWhenNotIdentical?: Exclude<RegisterBehavior, RegisterBehavior.BulkOverwrite>;
/**
* Specifies a list of command ids that we should check in the event of a name mismatch
* @default []
*/
idHints?: string[];
}
}
type ApplicationCommandRegistryRegisterOptions = ApplicationCommandRegistry.RegisterOptions;
interface CooldownPreconditionContext extends AllFlowsPrecondition.Context {
scope?: BucketScope;
delay: number;
limit?: number;
filteredUsers?: Snowflake[];
}
declare class CorePrecondition$e extends AllFlowsPrecondition {
buckets: WeakMap<Command, RateLimitManager<string>>;
messageRun(message: Message, command: Command, context: CooldownPreconditionContext): AllFlowsPrecondition.Result;
chatInputRun(interaction: ChatInputCommandInteraction, command: Command, context: CooldownPreconditionContext): AllFlowsPrecondition.Result;
contextMenuRun(interaction: ContextMenuCommandInteraction, command: Command, context: CooldownPreconditionContext): AllFlowsPrecondition.Result;
private sharedRun;
private getIdFromMessage;
private getIdFromInteraction;
private getManager;
}
/**
* Errors thrown by preconditions
* @property name This will be `'PreconditionError'` and can be used to distinguish the type of error when any error gets thrown
*/
declare class PreconditionError extends UserError {
readonly precondition: Precondition;
constructor(options: PreconditionError.Options);
get name(): string;
}
declare namespace PreconditionError {
/**
* The options for {@link PreconditionError}.
* @since 1.0.0
*/
interface Options extends Omit<UserError.Options, 'identifier'> {
/**
* The precondition that caused the error.
* @since 1.0.0
*/
precondition: Precondition;
/**
* The identifier.
* @since 1.0.0
* @default precondition.name
*/
identifier?: string;
}
}
type PreconditionResult = Awaitable<Result<unknown, UserError>>;
type AsyncPreconditionResult = Promise<Result<unknown, UserError>>;
/**
* The registered preconditions and their contexts, if any. When registering new ones, it is recommended to use
* [module augmentation](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation) so
* custom ones are registered.
*
* When a key's value is `never`, it means that it does not take any context, which allows you to pass its identifier as
* a bare string (e.g. `preconditions: ['NSFW']`), however, if context is required, a non-`never` type should be passed,
* which will type {@link PreconditionContainerArray#append} and require an object with the name and a `context` with
* the defined type.
*
* @example
* ```typescript
* declare module '@sapphire/framework' {
* interface Preconditions {
* // A precondition named `Moderator` which does not read `context`:
* Moderator: never;
*
* // A precondition named `ChannelPermissions` which does read `context`:
* ChannelPermissions: {
* permissions: Permissions;
* };
* }
* }
*
* // [✔] These are valid:
* preconditions.append('Moderator');
* preconditions.append({ name: 'Moderator' });
* preconditions.append({
* name: 'ChannelPermissions',
* context: { permissions: new Permissions(8) }
* });
*
* // [X] These are invalid:
* preconditions.append({ name: 'Moderator', context: {} });
* // ➡ `never` keys do not accept `context`.
*
* preconditions.append('ChannelPermissions');
* // ➡ non-`never` keys always require `context`, a string cannot be used.
*
* preconditions.append({
* name: 'ChannelPermissions',
* context: { unknownProperty: 1 }
* });
* // ➡ mismatching `context` properties, `{ unknownProperty: number }` is not
* // assignable to `{ permissions: Permissions }`.
* ```
*/
interface Preconditions {
Cooldown: CooldownPreconditionContext;
DMOnly: never;
Enabled: never;
GuildNewsOnly: never;
GuildNewsThreadOnly: never;
GuildOnly: never;
GuildPrivateThreadOnly: never;
GuildPublicThreadOnly: never;
GuildTextOnly: never;
GuildVoiceOnly: never;
GuildThreadOnly: never;
NSFW: never;
RunIn: {
types: readonly ChannelType[] | RunInPreconditionCommandSpecificData;
};
ClientPermissions: {
permissions: PermissionsBitField;
};
UserPermissions: {
permissions: PermissionsBitField;
};
}
/**
* The specific data for the precondition types for the `RunIn` precondition, when the command
* specified the types for specific command types.
*/
interface RunInPreconditionCommandSpecificData {
messageRun: readonly ChannelType[];
chatInputRun: readonly ChannelType[];
contextMenuRun: readonly ChannelType[];
}
type PreconditionKeys = keyof Preconditions;
type SimplePreconditionKeys = {
[K in PreconditionKeys]: Preconditions[K] extends never ? K : never;
}[PreconditionKeys];
interface PreconditionOptions extends Piece.Options {
/**
* The position for the precondition to be set at in the global precondition list. If set to `null`, this
* precondition will not be set as a global one.
* @default null
*/
position?: number | null;
}
interface PreconditionContext extends Record<PropertyKey, unknown> {
external?: boolean;
}
declare class Precondition<Options extends Precondition.Options = Precondition.Options> extends Piece<Options, 'preconditions'> {
readonly position: number | null;
constructor(context: Precondition.LoaderContext, options?: Options);
messageRun?(message: Message, command: MessageCommand, context: Precondition.Context): Precondition.Result;
chatInputRun?(interaction: ChatInputCommandInteraction, command: ChatInputCommand, context: Precondition.Context): Precondition.Result;
contextMenuRun?(interaction: ContextMenuCommandInteraction, command: ContextMenuCommand, context: Precondition.Context): Precondition.Result;
ok(): Precondition.Result;
/**
* Constructs a {@link PreconditionError} with the precondition parameter set to `this`.
* @param options The information.
*/
error(options?: Omit<PreconditionError.Options, 'precondition'>): Precondition.Result;
protected fetchChannelFromInteraction(interaction: CommandInteraction): Promise<TextBasedChannel>;
}
declare namespace Precondition {
type Options = PreconditionOptions;
type LoaderContext = Piece.LoaderContext<'preconditions'>;
type Context = PreconditionContext;
type Result = PreconditionResult;
type AsyncResult = AsyncPreconditionResult;
}
declare abstract class AllFlowsPrecondition extends Precondition {
abstract messageRun(message: Message, command: MessageCommand, context: Precondition.Context): Precondition.Result;
abstract chatInputRun(interaction: ChatInputCommandInteraction, command: ChatInputCommand, context: Precondition.Context): Precondition.Result;
abstract contextMenuRun(interaction: ContextMenuCommandInteraction, command: ContextMenuCommand, context: Precondition.Context): Precondition.Result;
}
declare namespace AllFlowsPrecondition {
type Options = PreconditionOptions;
type LoaderContext = Piece.LoaderContext<'preconditions'>;
type Context = PreconditionContext;
type Result = PreconditionResult;
type AsyncResult = AsyncPreconditionResult;
}
/**
* Defines the result's value for a PreconditionContainer.
* @since 1.0.0
*/
type PreconditionContainerResult = Result<unknown, UserError>;
/**
* Defines the return type of the generic {@link IPreconditionContainer.messageRun}.
* @since 1.0.0
*/
type PreconditionContainerReturn = Awaitable<PreconditionContainerResult>;
/**
* Async-only version of {@link PreconditionContainerReturn}, to be used when the run method is async.
* @since 1.0.0
*/
type AsyncPreconditionContainerReturn = Promise<PreconditionContainerResult>;
/**
* An abstracted precondition container to be implemented by classes.
* @since 1.0.0
*/
interface IPreconditionContainer {
/**
* Runs a precondition container.
* @since 1.0.0
* @param message The message that ran this precondition.
* @param command The command the message invoked.
* @param context The context for the precondition.
*/
messageRun(message: Message, command: Command, context?: PreconditionContext): PreconditionContainerReturn;
/**
* Runs a precondition container.
* @since 3.0.0
* @param interaction The interaction that ran this precondition.
* @param command The command the interaction invoked.
* @param context The context for the precondition.
*/
chatInputRun(interaction: ChatInputCommandInteraction, command: Command, context?: PreconditionContext): PreconditionContainerReturn;
/**
* Runs a precondition container.
* @since 3.0.0
* @param interaction The interaction that ran this precondition.
* @param command The command the interaction invoked.
* @param context The context for the precondition.
*/
contextMenuRun(interaction: ContextMenuCommandInteraction, command: Command, context?: PreconditionContext): PreconditionContainerReturn;
}
/**
* Defines the simple options for the {@link PreconditionContainerSingle}, where only the name of the precondition can
* be defined.
* @since 2.0.0
*/
interface SimplePreconditionSingleResolvableDetails {
/**
* The name of the precondition to retrieve from {@link SapphireClient.preconditions}.
* @since 2.0.0
*/
name: SimplePreconditionKeys;
}
/**
* Defines the detailed options for the {@link PreconditionContainerSingle}, where both the {@link PreconditionContext} and the
* name of the precondition can be defined.
* @since 1.0.0
*/
interface PreconditionSingleResolvableDetails<K extends PreconditionKeys = PreconditionKeys> {
/**
* The name of the precondition to retrieve from {@link SapphireClient.preconditions}.
* @since 1.0.0
*/
name: K;
/**
* The context to be set at {@link PreconditionContainerSingle.context}.
* @since 1.0.0
*/
context: Preconditions[K];
}
/**
* Defines the data accepted by {@link PreconditionContainerSingle}'s constructor.
* @since 1.0.0
*/
type PreconditionSingleResolvable = SimplePreconditionKeys | SimplePreconditionSingleResolvableDetails | PreconditionSingleResolvableDetails;
/**
* An {@link IPreconditionContainer} which runs a single precondition from {@link SapphireClient.preconditions}.
* @since 1.0.0
*/
declare class PreconditionContainerSingle implements IPreconditionContainer {
/**
* The context to be used when calling {@link Precondition.run}. This will always be an empty object (`{}`) when the
* container was constructed with a string, otherwise it is a direct reference to the value from
* {@link PreconditionSingleResolvableDetails.context}.
* @since 1.0.0
*/
readonly context: Record<PropertyKey, unknown>;
/**
* The name of the precondition to run.
* @since 1.0.0
*/
readonly name: string;
constructor(data: PreconditionSingleResolvable);
/**
* Runs the container.
* @since 1.0.0
* @param message The message that ran this precondition.
* @param command The command the message invoked.
* @param context The context for the message precondition.
*/
messageRun(message: Message, command: MessageCommand, context?: PreconditionContext): PreconditionResult | _sapphire_result.Err<UserError, any>;
/**
* Runs the container.
* @since 3.0.0
* @param interaction The interaction that ran this precondition.
* @param command The command the interaction invoked.
* @param context The context for the chat input command precondition.
*/
chatInputRun(interaction: ChatInputCommandInteraction, command: ChatInputCommand, context?: PreconditionContext): PreconditionResult | _sapphire_result.Err<UserError, any>;
/**
* Runs the container.
* @since 3.0.0
* @param interaction The interaction that ran this precondition.
* @param command The command the interaction invoked.
* @param context The context for the context menu command precondition.
*/
contextMenuRun(interaction: ContextMenuCommandInteraction, command: ContextMenuCommand, context?: PreconditionContext): PreconditionResult | _sapphire_result.Err<UserError, any>;
}
/**
* Defines the condition for {@link PreconditionContainerArray}s to run.
* @since 1.0.0
*/
interface IPreconditionCondition {
/**
* Runs the containers one by one.
* @seealso {@link PreconditionRunMode.Sequential}
* @since 1.0.0
* @param message The message that ran this precondition.
* @param command The command the message invoked.
* @param entries The containers to run.
* @param context The context for the precondition.
*/
messageSequential(message: Message, command: MessageCommand, entries: readonly IPreconditionContainer[], context: PreconditionContext): PreconditionContainerReturn;
/**
* Runs all the containers using `Promise.all`, then checks the results once all tasks finished running.
* @seealso {@link PreconditionRunMode.Parallel}
* @since 1.0.0
* @param message The message that ran this precondition.
* @param command The command the message invoked.
* @param entries The containers to run.
* @param context The context for the precondition.
*/
messageParallel(message: Message, command: MessageCommand, entries: readonly IPreconditionContainer[], context: PreconditionContext): PreconditionContainerReturn;
/**
* Runs the containers one by one.
* @seealso {@link PreconditionRunMode.Sequential}
* @since 3.0.0
* @param interaction The interaction that ran this precondition.
* @param command The command the interaction invoked.
* @param entries The containers to run.
* @param context The context for the precondition.
*/
chatInputSequential(interaction: ChatInputCommandInteraction, command: ChatInputCommand, entries: readonly IPreconditionContainer[], context: PreconditionContext): PreconditionContainerReturn;
/**
* Runs all the containers using `Promise.all`, then checks the results once all tasks finished running.
* @seealso {@link PreconditionRunMode.Parallel}
* @since 3.0.0
* @param interaction The interaction that ran this precondition.
* @param command The command the interaction invoked.
* @param entries The containers to run.
* @param context The context for the precondition.
*/
chatInputParallel(interaction: ChatInputCommandInteraction, command: ChatInputCommand, entries: readonly IPreconditionContainer[], context: PreconditionContext): PreconditionContainerReturn;
/**
* Runs the containers one by one.
* @seealso {@link PreconditionRunMode.Sequential}
* @since 3.0.0
* @param interaction The interaction that ran this precondition.
* @param command The command the interaction invoked.
* @param entries The containers to run.
* @param context The context for the precondition.
*/
contextMenuSequential(interaction: ContextMenuCommandInteraction, command: ContextMenuCommand, entries: readonly IPreconditionContainer[], context: PreconditionContext): PreconditionContainerReturn;
/**
* Runs all the containers using `Promise.all`, then checks the results once all tasks finished running.
* @seealso {@link PreconditionRunMode.Parallel}
* @since 3.0.0
* @param interaction The interaction that ran this precondition.
* @param command The command the interaction invoked.
* @param entries The containers to run.
* @param context The context for the precondition.
*/
contextMenuParallel(interaction: ContextMenuCommandInteraction, command: ContextMenuCommand, entries: readonly IPreconditionContainer[], context: PreconditionContext): PreconditionContainerReturn;
}
/**
* The run mode for a {@link PreconditionContainerArray}.
* @since 1.0.0
*/
declare enum PreconditionRunMode {
/**
* The entries are run sequentially, this is the default behaviour and can be slow when doing long asynchronous
* tasks, but is performance savvy.
* @since 1.0.0
*/
Sequential = 0,
/**
* All entries are run in parallel using `Promise.all`, then the results are processed after all of them have
* completed.
* @since 1.0.0
*/
Parallel = 1
}
/**
* The condition for a {@link PreconditionContainerArray}.
*/
declare enum PreconditionRunCondition {
/**
* Defines a condition where all the entries must pass. This uses {@link PreconditionConditionAnd}.
* @since 1.0.0
*/
And = 0,
/**
* Defines a condition where at least one entry must pass. This uses {@link PreconditionConditionOr}.
* @since 1.0.0
*/
Or = 1
}
/**
* Defines the detailed options for the {@link PreconditionContainerArray}, where both the {@link PreconditionRunMode} and the
* entries can be defined.
* @since 1.0.0
*/
interface PreconditionArrayResolvableDetails {
/**
* The data that will be used to resolve {@link IPreconditionContainer} dependent of this one.
* @since 1.0.0
*/
entries: readonly PreconditionEntryResolvable[];
/**
* The mode the {@link PreconditionContainerArray} will run.
* @since 1.0.0
*/
mode: PreconditionRunMode;
}
/**
* Defines the data accepted by {@link PreconditionContainerArray}'s constructor.
* @since 1.0.0
*/
type PreconditionArrayResolvable = readonly PreconditionEntryResolvable[] | PreconditionArrayResolvableDetails;
/**
* Defines the data accepted for each entry of the array.
* @since 1.0.0
* @seealso {@link PreconditionArrayResolvable}
* @seealso {@link PreconditionArrayResolvableDetails.entries}
*/
type PreconditionEntryResolvable = PreconditionSingleResolvable | PreconditionArrayResolvable;
/**
* An {@link IPreconditionContainer} that defines an array of multiple {@link IPreconditionContainer}s.
*
* By default, array containers run either of two conditions: AND and OR ({@link PreconditionRunCondition}), the top level
* will always default to AND, where the nested one flips the logic (OR, then children arrays are AND, then OR...).
*
* This allows `['Connect', ['Moderator', ['DJ', 'SongAuthor']]]` to become a thrice-nested precondition container, where:
* - Level 1: [Single(Connect), Array] runs AND, both containers must return a successful value.
* - Level 2: [Single(Moderator), Array] runs OR, either container must return a successful value.
* - Level 3: [Single(DJ), Single(SongAuthor)] runs AND, both containers must return a successful value.
*
* In other words, it is identical to doing:
* ```typescript
* Connect && (Moderator || (DJ && SongAuthor));
* ```
* @remark More advanced logic can be accomplished by adding more {@link IPreconditionCondition}s (e.g. other operators),
* see {@link PreconditionContainerArray.conditions} for more information.
* @since 1.0.0
*/
declare class PreconditionContainerArray implements IPreconditionContainer {
/**
* The mode at which this precondition will run.
* @since 1.0.0
*/
readonly mode: PreconditionRunMode;
/**
* The {@link IPreconditionContainer}s the array holds.
* @since 1.0.0
*/
readonly entries: IPreconditionContainer[];
/**
* The {@link PreconditionRunCondition} that defines how entries must be handled.
* @since 1.0.0
*/
readonly runCondition: PreconditionRunCondition;
constructor(data?: PreconditionArrayResolvable, parent?: PreconditionContainerArray | null);
/**
* Adds a new entry to the array.
* @since 1.0.0
* @param entry The value to add to the entries.
*/
add(entry: IPreconditionContainer): this;
append(keyOrEntries: SimplePreconditionSingleResolvableDetails | SimplePreconditionKeys | PreconditionContainerArray): this;
append<K extends PreconditionKeys>(entry: PreconditionSingleResolvableDetails<K>): this;
/**
* Runs the container.
* @since 1.0.0
* @param message The message that ran this precondition.
* @param command The command the message invoked.
* @param context The context for the message command precondition.
*/
messageRun(message: Message, command: MessageCommand, context?: PreconditionContext): PreconditionContainerReturn;
/**
* Runs the container.
* @since 3.0.0
* @param interaction The interaction that ran this precondition.
* @param command The command the interaction invoked.
* @param context The context for the chat input precondition.
*/
chatInputRun(interaction: ChatInputCommandInteraction, command: ChatInputCommand, context?: PreconditionContext): PreconditionContainerReturn;
/**
* Runs the container.
* @since 3.0.0
* @param interaction The interaction that ran this precondition.
* @param command The command the interaction invoked.
* @param context The context for the context menu precondition.
*/
contextMenuRun(interaction: ContextMenuCommandInteraction, command: ContextMenuCommand, context?: PreconditionContext): PreconditionContainerReturn;
/**
* Parses the precondition entry resolvables, and adds them to the entries.
* @since 1.0.0
* @param entries The entries to parse.
*/
protected parse(entries: Iterable<PreconditionEntryResolvable>): this;
/**
* Retrieves a condition from {@link PreconditionContainerArray.conditions}, assuming existence.
* @since 1.0.0
*/
protected get condition(): IPreconditionCondition;
/**
* The preconditions to be run. Extra ones can be added by augmenting {@link PreconditionRunCondition} and then
* inserting {@link IPreconditionCondition}s.
* @since 1.0.0
* @example
* ```typescript
* // Adding more kinds of conditions
*
* // Set the new condition:
* PreconditionContainerArray.conditions.set(2, PreconditionConditionRandom);
*
* // Augment Sapphire to add the new condition, in case of a JavaScript
* // project, this can be moved to an `Augments.d.ts` (or any other name)
* // file somewhere:
* declare module '@sapphire/framework' {
* export enum PreconditionRunCondition {
* Random = 2
* }
* }
* ```
*/
static readonly conditions: Collection<PreconditionRunCondition, IPreconditionCondition>;
}
declare class Command<PreParseReturn = Args, Options extends Command.Options = Command.Options> extends AliasPiece<Options, 'commands'> {
/**
* The raw name of the command as provided through file name or constructor options.
*
* This is exactly what is set by the developer, completely unmodified internally by the framework.
* Unlike the `name` which gets lowercased for storing it uniquely in the {@link CommandStore}.
*/
rawName: string;
/**
* A basic summary about the command
* @since 1.0.0
*/
description: string;
/**
* The preconditions to be run.
* @since 1.0.0
*/
preconditions: PreconditionContainerArray;
/**
* Longer version of command's summary and how to use it
* @since 1.0.0
*/
detailedDescription: DetailedDescriptionCommand;
/**
* The full category for the command, can be overridden by setting the {@link Command.Options.fullCategory} option.
*
* If {@link Command.Options.fullCategory} is not set, then:
* - If the command is loaded from the file system, then this is the command's location in file system relative to
* the commands folder. For example, if you have a command located at `commands/General/Information/info.ts` then
* this property will be `['General', 'Info']`.
* - If the command is virtual, then this will be `[]`.
*
* @since 2.0.0
*/
readonly fullCategory: readonly string[];
/**
* The strategy to use for the lexer.
* @since 1.0.0
*/
strategy: IUnorderedStrategy;
/**
* If {@link SapphireClient.typing} is true, it can be overridden for a specific command using this property, set via its options.
* Otherwise, this property will be ignored.
* @default true
*/
typing: boolean;
/**
* The application command registry associated with this command.
* @since 3.0.0
*/
readonly applicationCommandRegistry: ApplicationCommandRegistry;
/**
* The lexer to be used for command parsing
* @since 1.0.0
* @private
*/
protected lexer: Lexer;
/**
* @since 1.0.0
* @param context The context.
* @param options Optional Command settings.
*/
constructor(context: Command.LoaderContext, options?: Options);
/**
* The message pre-parse method. This method can be overridden by plugins to define their own argument parser.
* @param message The message that triggered the command.
* @param parameters The raw parameters as a single string.
* @param context The command-context used in this execution.
*/
messagePreParse(message: Message, parameters: string, context: MessageCommand.RunContext): Awaitable<PreParseReturn>;
/**
* The main category for the command, if any.
*
* This getter retrieves the first value of {@link Command.fullCategory}, if it has at least one item, otherwise it
* returns `null`.
*
* @note You can set {@link Command.Options.fullCategory} to override the built-in category resolution.
*/
get category(): string | null;
/**
* The sub-category for the command, if any.
*
* This getter retrieves the second value of {@link Command.fullCategory}, if it has at least two items, otherwise
* it returns `null`.
*
* @note You can set {@link Command.Options.fullCategory} to override the built-in category resolution.
*/
get subCategory(): string | null;
/**
* The parent category for the command.
*
* This getter retrieves the last value of {@link Command.fullCategory}, if it has at least one item, otherwise it
* returns `null`.
*
* @note You can set {@link Command.Options.fullCategory} to override the built-in category resolution.
*/
get parentCategory(): string | null;
/**
* Executes the message command's logic.
* @param message The message that triggered the command.
* @param args The value returned by {@link Command.messagePreParse}, by default an instance of {@link Args}.
* @param context The context in which the command was executed.
*/
messageRun?(message: Message, args: PreParseReturn, context: MessageCommand.RunContext): Awaitable<unknown>;
/**
* Executes the application command's logic.
* @param interaction The interaction that triggered the command.
* @param context The chat input command run context.
*/
chatInputRun?(interaction: ChatInputCommandInteraction, context: ChatInputCommand.RunContext): Awaitable<unknown>;
/**
* Executes the context menu's logic.
* @param interaction The interaction that triggered the command.
* @param context The context menu command run context.
*/
contextMenuRun?(interaction: ContextMenuCommandInteraction, context: ContextMenuCommand.RunContext): Awaitable<unknown>;
/**
* Executes the autocomplete logic.
*
* :::tip
*
* You may use this, or alternatively create an {@link InteractionHandler interaction handler} to handle autocomplete interactions.
* Keep in mind that commands take precedence over interaction handlers.
*
* :::
*
* @param interaction The interaction that triggered the autocomplete.
*/
autocompleteRun?(interaction: AutocompleteInteraction): Awaitable<unknown>;
/**
* Defines the JSON.stringify behavior of the command.
*/
toJSON(): CommandJSON;
/**
* Registers the application commands that should be handled by this command.
* @param registry This command's registry
*/
registerApplicationCommands?(registry: ApplicationCommandRegistry): Awaitable<void>;
/**
* Type-guard that ensures the command supports message commands by checking if the handler for it is present
*/
supportsMessageCommands(): this is MessageCommand;
/**
* Type-guard that ensures the command supports chat input commands by checking if the handler for it is present
*/
supportsChatInputCommands(): this is ChatInputCommand;
/**
* Type-guard that ensures the command supports context menu commands by checking if the handler for it is present
*/
supportsContextMenuCommands(): this is ContextMenuCommand;
/**
* Type-guard that ensures the command supports handling autocomplete interactions by checking if the handler for it is present
*/
supportsAutocompleteInteractions(): this is AutocompleteCommand;
reload(): Promise<void>;
/**
* Parses the command's options and processes them, calling {@link Command#parseConstructorPreConditionsRunIn},
* {@link Command#parseConstructorPreConditionsNsfw},
* {@link Command#parseConstructorPreConditionsRequiredClientPermissions}, and
* {@link Command#parseConstructorPreConditionsCooldown}.
* @since 2.0.0
* @param options The command options given from the constructor.
*/
protected parseConstructorPreConditions(options: Command.Options): void;
/**
* Appends the `NSFW` precondition if {@link Command.Options.nsfw} is set to true.
* @param options The command options given from the constructor.
*/
protected parseConstructorPreConditionsNsfw(options: Command.Options): void;
/**
* Appends the `RunIn` precondition based on the values passed, defaulting to `null`, which doesn't add a
* precondition.
* @param options The command options given from the constructor.
*/
protected parseConstructorPreConditionsRunIn(options: Command.Options): void;
/**
* Appends the `ClientPermissions` precondition when {@link Command.Options.requiredClientPermissions} resolves to a
* non-zero bitfield.
* @param options The command options given from the constructor.
*/
protected parseConstructorPreConditionsRequiredClientPermissions(options: Command.Options): void;
/**
* Appends the `UserPermissions` precondition when {@link Command.Options.requiredUserPermissions} resolves to a
* non-zero bitfield.
* @param options The command options given from the constructor.
*/
protected parseConstructorPreConditionsRequiredUserPermissions(options: Command.Options): void;
/**
* Appends the `Cooldown` precondition when {@link Command.Options.cooldownLimit} and
* {@link Command.Options.cooldownDelay} are both non-zero.
* @param options The command options given from the constructor.
*/
protected parseConstructorPreConditionsCooldown(options: Command.Options): void;
/**
* Resolves the {@link Command.Options.runIn} option into a {@link Command.RunInTypes} array.
* @param types The types to resolve.
* @returns The resolved types, or `null` if no types were resolved.
*/
protected resolveConstructorPreConditionsRunType(types: CommandRunInUnion): readonly ChannelType[] | null;
static runInTypeIsSpecificsObject(types: Command.Options['runIn']): types is CommandSpecificRunIn;
}
declare namespace Command {
type Options = CommandOptions;
type JSON = CommandJSON;
/** @deprecated Use {@linkcode LoaderContext} instead. */
type Context = LoaderContext;
type LoaderContext = AliasPiece.LoaderContext<'commands'>;
type RunInTypes = CommandOptionsRunType;
type RunInUnion = CommandRunInUnion;
type SpecificRunIn = CommandSpecificRunIn;
type ChatInputCommandInteraction<Cached extends discord_js.CacheType = discord_js.CacheType> = discord_js.ChatInputCommandInteraction<Cached>;
type ContextMenuCommandInteraction<Cached extends discord_js.CacheType = discord_js.CacheType> = discord_js.ContextMenuCommandInteraction<Cached>;
type AutocompleteInteraction<Cached extends discord_js.CacheType = discord_js.CacheType> = discord_js.AutocompleteInteraction<Cached>;
type Registry = ApplicationCommandRegistry;
}
type DetailedDescriptionCommand = string | DetailedDescriptionCommandObject;
interface DetailedDescriptionCommandObject {
}
/**
* The allowed values for {@link CommandOptions.runIn}.
* @remark It is discouraged to use this type, we recommend using {@link CommandOptionsRunTypeEnum} instead.
* @since 2.0.0
*/
type CommandOptionsRunType = 'DM' | 'GUILD_TEXT' | 'GUILD_VOICE' | 'GUILD_NEWS' | 'GUILD_NEWS_THREAD' | 'GUILD_PUBLIC_THREAD' | 'GUILD_PRIVATE_THREAD' | 'GUILD_ANY';
/**
* The allowed values for {@link CommandOptions.runIn}.
* @since 4.7.0
*/
type CommandRunInUnion = ChannelType | Command.RunInTypes | CommandOptionsRunTypeEnum | readonly (ChannelType | Command.RunInTypes | CommandOptionsRunTypeEnum)[] | Nullish;
/**
* A more detailed structure for {@link CommandOptions.runIn} when you want to have a different `runIn` for each
* command type.
* @since 4.7.0
*/
interface