diff --git a/packages/structures/src/applicationCommands/ApplicationCommand.ts b/packages/structures/src/applicationCommands/ApplicationCommand.ts new file mode 100644 index 000000000000..acfb3d3e60c3 --- /dev/null +++ b/packages/structures/src/applicationCommands/ApplicationCommand.ts @@ -0,0 +1,143 @@ +import { DiscordSnowflake } from '@sapphire/snowflake'; +import type { APIApplicationCommand, ApplicationCommandType } from 'discord-api-types/v10'; +import { Structure } from '../Structure.js'; +import { kData } from '../utils/symbols.js'; +import { isIdSet } from '../utils/type-guards.js'; +import type { Partialize } from '../utils/types.js'; + +/** + * Represents any application command on Discord. + * + * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate` + * @remarks has substructure `User` which needs to be instantiated and stored by an extending class using it + * @remarks intentionally does not export `roles` so that extending classes can resolve `Snowflake[]` to `Role[]` + */ +export class ApplicationCommand extends Structure< + APIApplicationCommand, + Omitted +> { + /** + * The template used for removing data from the raw data stored for each application command + */ + public static override readonly DataTemplate: Partial = {}; + + /** + * @param data - The raw data received from the API for the application command + */ + public constructor(data: Partialize) { + super(data); + } + + /** + * Unique ID of command + * + * @remarks Valid option types: ALL + */ + public get id() { + return this[kData].id; + } + + /** + * Type of command + * + * @remarks Valid option types: ALL + * @defaultValue {@link ApplicationCommandType.ChatInput} + */ + public get type() { + return this[kData].type; + } + + /** + * Id of the parent application + * + * @remarks Valid option types: ALL + */ + public get applicationId() { + return this[kData].application_id; + } + + /** + * Guild ID of the command, if not global + * + * @remarks Valid option types: ALL + */ + public get guildId() { + return this[kData].guild_id; + } + + /** + * Name of the application, 1-32 characters + * + * @remarks Valid option types: ALL + * @see {@link https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-naming} + */ + public get name() { + return this[kData].name; + } + + /** + * Localization map for the `name` field. + * + * @remarks Values follow the same restrictions as `name`. + * @remarks Valid option types: ALL + * @see {@link https://discord.com/developers/docs/reference#locales} + */ + public get nameLocalizations() { + return this[kData].name_localizations; + } + + /** + * Description for {@link ApplicationCommandType.ChatInput} commands, 1-100 characters. + * Empty string for {@link ApplicationCommandType.User} and {@link ApplicationCommandType.Message} commands. + * + * @remarks Valid option types: ALL + */ + public get description() { + return this[kData].description; + } + + /** + * Localization map for the `description` field. + * + * @remarks Values follow the same restrictions as `description`. + * @remarks Valid option types: ALL + * @see {@link https://discord.com/developers/docs/reference#locales} + */ + public get descriptionLocalizations() { + return this[kData].description_localizations; + } + + /** + * Set of permissions represented as a bit set + * + * @see {@link https://discord.com/developers/docs/topics/permissions} + */ + public get defaultMemberPermissions() { + return this[kData].default_member_permissions; + } + + /** + * Whether the command is age-restricted (NSFW) + * + * @defaultValue `false` + * @see {@link https://discord.com/developers/docs/interactions/application-commands#agerestricted-commands} + */ + public get nsfw() { + return this[kData].nsfw; + } + + /** + * The timestamp the command was created at + */ + public get createdTimestamp() { + return isIdSet(this.id) ? DiscordSnowflake.timestampFrom(this.id) : null; + } + + /** + * The time the command was created at + */ + public get createdAt() { + const createdTimestamp = this.createdTimestamp; + return createdTimestamp ? new Date(createdTimestamp) : null; + } +} diff --git a/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionAttachment.ts b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionAttachment.ts new file mode 100644 index 000000000000..a1a064a2b7c9 --- /dev/null +++ b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionAttachment.ts @@ -0,0 +1,24 @@ +import type { APIApplicationCommandAttachmentOption, ApplicationCommandOptionType } from 'discord-api-types/v10'; +import type { Partialize } from '../../utils/types'; +import { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase'; + +/** + * Represents an attachment option type for an application command. + * + * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate` + */ +export class ApplicationCommandOptionAttachment< + Omitted extends keyof APIApplicationCommandAttachmentOption, +> extends ApplicationCommandOptionBase { + /** + * The template used for removing data from the raw data stored for each application attachment option type. + */ + public static override readonly DataTemplate: Partial = {}; + + /** + * @param data - The raw data received from the API for the application command option + */ + public constructor(data: Partialize) { + super(data); + } +} diff --git a/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionBase.ts b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionBase.ts new file mode 100644 index 000000000000..2b0115362a9e --- /dev/null +++ b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionBase.ts @@ -0,0 +1,97 @@ +import type { APIApplicationCommandOptionBase, ApplicationCommandOptionType } from 'discord-api-types/v10'; +import { Structure } from '../../Structure.js'; +import { kData } from '../../utils/symbols.js'; +import type { Partialize } from '../../utils/types.js'; + +/** + * @see {@link https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-structure} + * export type APIApplicationCommandBasicOption = APIApplicationCommandAttachmentOption | APIApplicationCommandBooleanOption | APIApplicationCommandChannelOption | APIApplicationCommandIntegerOption | APIApplicationCommandMentionableOption | APIApplicationCommandNumberOption | APIApplicationCommandRoleOption | APIApplicationCommandStringOption | APIApplicationCommandUserOption; + * /** + * @see {@link https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-structure} + * export type APIApplicationCommandOption = APIApplicationCommandBasicOption | APIApplicationCommandSubcommandGroupOption | APIApplicationCommandSubcommandOption; + */ + +export type ApplicationCommandOptionTypeType = Extract< + APIApplicationCommandOptionBase, + { type: Type } +>; + +/** + * Represents any application command option on Discord. + * + * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate` + * @remarks required options must be listed before optional options + */ +export abstract class ApplicationCommandOptionBase< + CommandOptionType extends ApplicationCommandOptionType, + Omitted extends keyof Omitted | '' = '', +> extends Structure, Omitted> { + /** + * @param data - The raw data received from the API for the application command option + */ + public constructor(data: Partialize, Omitted>) { + super(data); + } + + /** + * Type of this option + * + * @remarks Valid option types: ALL + * @see {@link https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-type} + */ + public get type() { + return this[kData].type; + } + + /** + * 1-32 character name. + * + * @remarks Must be unique within an array of application command options. + * @remarks Valid option types: ALL + * @see {@link https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-naming} + */ + public get name() { + return this[kData].name; + } + + /** + * Localization map for the `name` field. + * + * @remarks Values follow the same restrictions as `name`. + * @remarks Valid option types: ALL + * @see {@link https://discord.com/developers/docs/reference#locales} + */ + public get nameLocalizations() { + return this[kData].name_localizations; + } + + /** + * 1-100 character description + * + * @remarks Valid option types: ALL + */ + public get description() { + return this[kData].description; + } + + /** + * Localization map for the `description` field. + * + * @remarks Values follow the same restrictions as `description`. + * @remarks Valid option types: ALL + * @see {@link https://discord.com/developers/docs/reference#locales} + */ + public get descriptionLocalizations() { + return this[kData].description_localizations; + } + + /** + * Whether the parameter is required or optional + * + * @remarks Valid option types: All except {@link ApplicationCommandOptionType.Subcommand | Subcommand}, {@link ApplicationCommandOptionType.SubcommandGroup | SubcommandGroup} + * @defaultValue `false` + */ + public get required() { + return this[kData].required; + } +} diff --git a/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionBoolean.ts b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionBoolean.ts new file mode 100644 index 000000000000..b96af14df626 --- /dev/null +++ b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionBoolean.ts @@ -0,0 +1,24 @@ +import type { APIApplicationCommandBooleanOption, ApplicationCommandOptionType } from 'discord-api-types/v10'; +import type { Partialize } from '../../utils/types'; +import { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase'; + +/** + * Represents a boolean option type for an application command. + * + * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate` + */ +export class ApplicationCommandOptionBoolean< + Omitted extends keyof APIApplicationCommandBooleanOption, +> extends ApplicationCommandOptionBase { + /** + * The template used for removing data from the raw data stored for each boolean application command option + */ + public static override readonly DataTemplate: Partial = {}; + + /** + * @param data - The raw data received from the API for the boolean application command option + */ + public constructor(data: Partialize) { + super(data); + } +} diff --git a/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionChannel.ts b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionChannel.ts new file mode 100644 index 000000000000..2970b6d0abfb --- /dev/null +++ b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionChannel.ts @@ -0,0 +1,24 @@ +import type { APIApplicationCommandChannelOption, ApplicationCommandOptionAllowedChannelType, ApplicationCommandOptionType } from 'discord-api-types/v10'; +import type { Partialize } from '../../utils/types'; +import { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase'; + +/** + * Represents a channel option type for an application command. + * + * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate` + */ +export class ApplicationCommandOptionChannel< + Omitted extends keyof { channel_types?: ApplicationCommandOptionAllowedChannelType[] } & keyof APIApplicationCommandChannelOption, +> extends ApplicationCommandOptionBase { + /** + * The template used for removing data from the raw data stored for each channel application command option + */ + public static override readonly DataTemplate: Partial = {}; + + /** + * @param data - The raw data received from the API for the channel application command option + */ + public constructor(data: Partialize) { + super(data); + } +} diff --git a/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionChoice.ts b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionChoice.ts new file mode 100644 index 000000000000..304f02e70d69 --- /dev/null +++ b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionChoice.ts @@ -0,0 +1,40 @@ +import type { APIApplicationCommandOptionChoice } from 'discord-api-types/v10'; +import { Structure } from '../../Structure.js'; +import { kData } from '../../utils/symbols.js'; +import type { Partialize } from '../../utils/types.js'; + +/** + * Represents any application command option choice on Discord. + * + * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate` + * @remarks has substructure `User` which needs to be instantiated and stored by an extending class using it + */ +export class ApplicationCommandOptionChoice< + Omitted extends keyof APIApplicationCommandOptionChoice | '' = '', +> extends Structure { + /** + * The template used for removing data from the raw data stored for each application command option choice + */ + public static override readonly DataTemplate: Partial = {}; + + /** + * @param data - The raw data received from the API for the application command option choice + */ + public constructor(data: Partialize) { + super(data); + } + + /** + * 1-100 character choice name + */ + public get name() { + return this[kData].name; + } + + /** + * Type of value depends on the option type that the choice belongs to + */ + public get value() { + return this[kData].value; + } +} diff --git a/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionInteger.ts b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionInteger.ts new file mode 100644 index 000000000000..57504f1518a0 --- /dev/null +++ b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionInteger.ts @@ -0,0 +1,24 @@ +import type { APIApplicationCommandIntegerOption, ApplicationCommandOptionType } from 'discord-api-types/v10'; +import type { Partialize } from '../../utils/types'; +import { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase'; + +/** + * Represents an integer option type for an application command. + * + * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate` + */ +export class ApplicationCommandOptionInteger< + Omitted extends keyof APIApplicationCommandIntegerOption, +> extends ApplicationCommandOptionBase { + /** + * The template used for removing data from the raw data stored for each integer application command option type. + */ + public static override readonly DataTemplate: Partial = {}; + + /** + * @param data - The raw data received from the API for the integer option type + */ + public constructor(data: Partialize) { + super(data); + } +} diff --git a/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionMentionable.ts b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionMentionable.ts new file mode 100644 index 000000000000..7ff9fe51cbda --- /dev/null +++ b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionMentionable.ts @@ -0,0 +1,24 @@ +import type { APIApplicationCommandMentionableOption, ApplicationCommandOptionType } from 'discord-api-types/v10'; +import type { Partialize } from '../../utils/types'; +import { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase'; + +/** + * Represents a mention option type for an application command. + * + * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate` + */ +export class ApplicationCommandOptionMentionable< + Omitted extends keyof APIApplicationCommandMentionableOption, +> extends ApplicationCommandOptionBase { + /** + * The template used for removing data from the raw data stored for each mentionable application command option + */ + public static override readonly DataTemplate: Partial = {}; + + /** + * @param data - The raw data received from the API for the mentionable application command option + */ + public constructor(data: Partialize) { + super(data); + } +} diff --git a/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionNumber.ts b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionNumber.ts new file mode 100644 index 000000000000..7cc3ff8cb959 --- /dev/null +++ b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionNumber.ts @@ -0,0 +1,24 @@ +import type { APIApplicationCommandNumberOption, ApplicationCommandOptionType } from 'discord-api-types/v10'; +import type { Partialize } from '../../utils/types'; +import { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase'; + +/** + * Represents a number option type for an application command. + * + * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate` + */ +export class ApplicationCommandOptionNumber< + Omitted extends keyof APIApplicationCommandNumberOption, +> extends ApplicationCommandOptionBase { + /** + * The template used for removing data from the raw data stored for each number application command option + */ + public static override readonly DataTemplate: Partial = {}; + + /** + * @param data - The raw data received from the API for the number application command option + */ + public constructor(data: Partialize) { + super(data); + } +} diff --git a/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionRole.ts b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionRole.ts new file mode 100644 index 000000000000..a3047aa78bed --- /dev/null +++ b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionRole.ts @@ -0,0 +1,24 @@ +import type { APIApplicationCommandRoleOption, ApplicationCommandOptionType } from 'discord-api-types/v10'; +import type { Partialize } from '../../utils/types'; +import { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase'; + +/** + * Represents a role option type for an application command. + * + * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate` + */ +export class ApplicationCommandOptionRole< + Omitted extends keyof APIApplicationCommandRoleOption, +> extends ApplicationCommandOptionBase { + /** + * The template used for removing data from the raw data stored for each number application command option + */ + public static override readonly DataTemplate: Partial = {}; + + /** + * @param data - The raw data received from the API for the role application command option + */ + public constructor(data: Partialize) { + super(data); + } +} diff --git a/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionString.ts b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionString.ts new file mode 100644 index 000000000000..2c1b6cdb113f --- /dev/null +++ b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionString.ts @@ -0,0 +1,24 @@ +import type { APIApplicationCommandStringOption, ApplicationCommandOptionType } from 'discord-api-types/v10'; +import type { Partialize } from '../../utils/types'; +import { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase'; + +/** + * Represents a string option type for an application command. + * + * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate` + */ +export class ApplicationCommandOptionString< + Omitted extends keyof APIApplicationCommandStringOption, +> extends ApplicationCommandOptionBase { + /** + * The template used for removing data from the raw data stored for each number application command option + */ + public static override readonly DataTemplate: Partial = {}; + + /** + * @param data - The raw data received from the API for the role application command option + */ + public constructor(data: Partialize) { + super(data); + } +} diff --git a/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionUser.ts b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionUser.ts new file mode 100644 index 000000000000..c0346627edec --- /dev/null +++ b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandOptionUser.ts @@ -0,0 +1,24 @@ +import type { APIApplicationCommandUserOption, ApplicationCommandOptionType } from 'discord-api-types/v10'; +import type { Partialize } from '../../utils/types'; +import { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase'; + +/** + * Represents a user option type for an application command. + * + * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate` + */ +export class ApplicationCommandOptionUser< + Omitted extends keyof APIApplicationCommandUserOption, +> extends ApplicationCommandOptionBase { + /** + * The template used for removing data from the raw data stored for each user application command option + */ + public static override readonly DataTemplate: Partial = {}; + + /** + * @param data - The raw data received from the API for the user application command option + */ + public constructor(data: Partialize) { + super(data); + } +} diff --git a/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandSubcommandGroupOption.ts b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandSubcommandGroupOption.ts new file mode 100644 index 000000000000..4f36ee138127 --- /dev/null +++ b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandSubcommandGroupOption.ts @@ -0,0 +1 @@ +/* eslint-disable unicorn/no-empty-file */ diff --git a/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandSubcommandOption.ts b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandSubcommandOption.ts new file mode 100644 index 000000000000..4f36ee138127 --- /dev/null +++ b/packages/structures/src/applicationCommands/ApplicationCommandOptions/ApplicationCommandSubcommandOption.ts @@ -0,0 +1 @@ +/* eslint-disable unicorn/no-empty-file */ diff --git a/packages/structures/src/applicationCommands/ApplicationCommandOptions/index.ts b/packages/structures/src/applicationCommands/ApplicationCommandOptions/index.ts new file mode 100644 index 000000000000..72a91ebec36a --- /dev/null +++ b/packages/structures/src/applicationCommands/ApplicationCommandOptions/index.ts @@ -0,0 +1,11 @@ +// @ts-nocheck TODO: REMOVE ONCE ALL ARE FINISHED +export * from './ApplicationCommandOptionAttachment.js'; +export * from './ApplicationCommandOptionBoolean.js'; +export * from './ApplicationCommandOptionChannel.js'; +export * from './ApplicationCommandOptionChoice.js'; +export * from './ApplicationCommandOptionInteger.js'; +export * from './ApplicationCommandOptionMentionable.js'; +export * from './ApplicationCommandOptionNumber.js'; +export * from './ApplicationCommandOptionRole.js'; +export * from './ApplicationCommandOptionString.js'; +export * from './ApplicationCommandOptionUser.js'; diff --git a/packages/structures/src/applicationCommands/index.ts b/packages/structures/src/applicationCommands/index.ts new file mode 100644 index 000000000000..fec400841392 --- /dev/null +++ b/packages/structures/src/applicationCommands/index.ts @@ -0,0 +1 @@ +export * from './ApplicationCommand.js'; diff --git a/packages/structures/src/index.ts b/packages/structures/src/index.ts index 7ace22f7db69..6f56ccbc2523 100644 --- a/packages/structures/src/index.ts +++ b/packages/structures/src/index.ts @@ -1,3 +1,4 @@ +export * from './applicationCommands/index.js'; export * from './automoderation/index.js'; export * from './bitfields/index.js'; export * from './channels/index.js'; diff --git a/packages/structures/src/messages/ApplicationCommandInteractionMetadata.ts b/packages/structures/src/messages/ApplicationCommandInteractionMetadata.ts index f3199f138119..f328ea3db604 100644 --- a/packages/structures/src/messages/ApplicationCommandInteractionMetadata.ts +++ b/packages/structures/src/messages/ApplicationCommandInteractionMetadata.ts @@ -3,6 +3,9 @@ import { kData } from '../utils/symbols.js'; import type { Partialize } from '../utils/types.js'; import { InteractionMetadata } from './InteractionMetadata.js'; +// TODO: does this better belong in the ApplicationCommands/* folders +// TODO: now that we have appcmds structures(?) + /** * Represents metadata about the application command interaction causing a message. *