diff --git a/packages/discord-types/enums/commands.ts b/packages/discord-types/enums/commands.ts index b85e5b220..f534dce81 100644 --- a/packages/discord-types/enums/commands.ts +++ b/packages/discord-types/enums/commands.ts @@ -41,3 +41,25 @@ export const enum InteractionType { APPLICATION_COMMAND_AUTOCOMPLETE = 4, MODAL_SUBMIT = 5, } + +export const enum ApplicationCommandSectionType { + BUILT_IN = 0, + APPLICATION = 1, +} + +export const enum ApplicationCommandPermissionType { + ROLE = 1, + USER = 2, + CHANNEL = 3, +} + +export const enum InteractionContextType { + GUILD = 0, + BOT_DM = 1, + PRIVATE_CHANNEL = 2, +} + +export const enum ApplicationCommandHandlerType { + APP_HANDLER = 1, + DISCORD_LAUNCH_ACTIVITY = 2, +} diff --git a/packages/discord-types/src/stores/ApplicationCommandIndexStore.d.ts b/packages/discord-types/src/stores/ApplicationCommandIndexStore.d.ts new file mode 100644 index 000000000..2b1affd75 --- /dev/null +++ b/packages/discord-types/src/stores/ApplicationCommandIndexStore.d.ts @@ -0,0 +1,443 @@ +import { Application, Channel, FluxStore } from ".."; +import { CommandArgument, CommandContext } from "../common/messages/Commands"; +import { + ApplicationCommandHandlerType, + ApplicationCommandInputType, + ApplicationCommandOptionType, + ApplicationCommandPermissionType, + ApplicationCommandSectionType, + ApplicationCommandType, + ApplicationIntegrationType, + ChannelType, + InteractionContextType +} from "../../enums"; + +/** Score method for ranking command results. */ +export type ApplicationCommandScoreMethod = + | "none" + | "application_only" + | "command_only" + | "command_or_application"; + +/** Built-in command handling mode. */ +export type BuiltInCommandMode = + | "allow" + | "deny" + | "only_text"; + +/** Target for fetching guild command index. */ +export interface ApplicationCommandIndexGuildTarget { + type: "guild"; + guildId: string; +} + +/** Target for fetching channel command index. */ +export interface ApplicationCommandIndexChannelTarget { + type: "channel"; + channelId: string; +} + +/** Target for fetching user command index. */ +export interface ApplicationCommandIndexUserTarget { + type: "user"; +} + +/** Target for fetching application-specific command index. */ +export interface ApplicationCommandIndexApplicationTarget { + type: "application"; + applicationId: string; +} + +/** Union of all fetch target types. */ +export type ApplicationCommandIndexFetchTarget = + | ApplicationCommandIndexGuildTarget + | ApplicationCommandIndexChannelTarget + | ApplicationCommandIndexUserTarget + | ApplicationCommandIndexApplicationTarget; + +/** Context for querying commands with a channel. */ +export interface ApplicationCommandChannelContext { + type: "channel"; + channel: Channel; +} + +/** Context for querying commands without a channel. */ +export interface ApplicationCommandContextlessContext { + type: "contextless"; +} + +/** Union of query context types. */ +export type ApplicationCommandContext = + | ApplicationCommandChannelContext + | ApplicationCommandContextlessContext; + +/** Fetch state when not fetching. */ +export interface ApplicationCommandIndexFetchStateIdle { + fetching: false; + retryAfter?: number; +} + +/** Fetch state when actively fetching. */ +export interface ApplicationCommandIndexFetchStateFetching { + fetching: true; + abort: AbortController; + promise: Promise; +} + +/** Union of fetch state types. */ +export type ApplicationCommandIndexFetchState = + | ApplicationCommandIndexFetchStateIdle + | ApplicationCommandIndexFetchStateFetching; + +/** Result of a successful command index fetch. */ +export interface ApplicationCommandIndexResult { + /** Command sections keyed by application ID. */ + sections: Record; + /** Maps bot user ID to application ID. */ + sectionIdsByBotId: Record; + /** Version symbol for cache invalidation. */ + version: symbol; +} + +/** State for a command index entry. */ +export interface ApplicationCommandIndexState { + /** Server version symbol for staleness detection. */ + serverVersion: symbol; + /** Current fetch state. */ + fetchState: ApplicationCommandIndexFetchState; + /** Fetched result, if available. */ + result?: ApplicationCommandIndexResult; +} + +/** A section containing commands from a single application. */ +export interface ApplicationCommandSection { + /** Section descriptor with application info. */ + descriptor: ApplicationCommandSectionDescriptor; + /** Commands keyed by command ID. */ + commands: Record; +} + +/** Descriptor for a command section. */ +export interface ApplicationCommandSectionDescriptor { + /** Section ID, typically the application ID or a special value like "-1" for built-in. */ + id: string; + /** Section type. */ + type: ApplicationCommandSectionType; + /** Display name for the section. */ + name: string; + /** Application icon hash. */ + icon?: string | null; + /** Full application object for application sections. */ + application?: Application; + /** Whether this is a user-installed app. */ + isUserApp?: boolean; + /** Bot user ID for this application. */ + botId?: string; + /** Permissions for the application's commands. */ + permissions?: ApplicationCommandPermission[] | Record; +} + +/** Permission override for a command. */ +export interface ApplicationCommandPermission { + /** Type of permission target. */ + type: ApplicationCommandPermissionType; + /** ID of the role, user, or channel. */ + id: string; + /** Whether the target has permission to use the command. */ + permission: boolean; +} + +/** Option for an application command. */ +export interface ApplicationCommandOption { + /** Option type. */ + type: ApplicationCommandOptionType; + /** Option name. */ + name: string; + /** Localized display name for the option. */ + displayName?: string; + /** Localized option name from server. Bot commands only. */ + serverLocalizedName?: string; + /** Option description. */ + description: string; + /** Localized display description for the option. */ + displayDescription?: string; + /** Localized option description from server. Bot commands only. */ + serverLocalizedDescription?: string; + /** Whether this option is required. */ + required?: boolean; + /** Choices for string/integer/number options. */ + choices?: ApplicationCommandOptionChoice[]; + /** Nested options for subcommands. */ + options?: ApplicationCommandOption[]; + /** Channel types allowed for channel options. */ + channel_types?: ChannelType[]; + /** Minimum value for number/integer options. */ + min_value?: number; + /** Maximum value for number/integer options. */ + max_value?: number; + /** Minimum length for string options. */ + min_length?: number; + /** Maximum length for string options. */ + max_length?: number; + /** Whether autocomplete is enabled. */ + autocomplete?: boolean; +} + +/** Choice for a command option. */ +export interface ApplicationCommandOptionChoice { + /** Choice name. */ + name: string; + /** Localized choice name, if available. */ + name_localized?: string; + /** Choice value. */ + value: string | number; +} + +/** Raw application command from the API. */ +export interface RawApplicationCommand { + id: string; + application_id: string; + version: string; + guild_id?: string; + type?: ApplicationCommandType; + name: string; + name_default?: string; + name_localized?: string; + description: string; + description_default?: string; + description_localized?: string; + options?: ApplicationCommandOption[]; + default_member_permissions?: string | null; + dm_permission?: boolean; + nsfw?: boolean; + contexts?: InteractionContextType[]; + integration_types?: ApplicationIntegrationType[]; + permissions?: ApplicationCommandPermission[]; + global_popularity_rank?: number; + handler?: ApplicationCommandHandlerType; +} + +/** Processed application command. */ +export interface ApplicationCommand { + /** Command version string. Bot commands only. */ + version?: string; + /** Guild ID if guild-specific. Bot commands only. */ + guildId?: string; + /** Composite command ID including subcommand path. */ + id: string; + /** Original untranslated command name. */ + untranslatedName: string; + /** Localized command name from server. Bot commands only. */ + serverLocalizedName?: string; + /** Application ID. */ + applicationId: string; + /** Command type. */ + type: ApplicationCommandType; + /** Input type. */ + inputType: ApplicationCommandInputType; + /** Original untranslated description. */ + untranslatedDescription: string; + /** Command options. */ + options: ApplicationCommandOption[]; + /** Root command reference for subcommands. Bot commands only. */ + rootCommand?: RawApplicationCommand; + /** Path of subcommand options for nested commands. Bot commands only. */ + subCommandPath?: ApplicationCommandOption[]; + /** Default member permissions required as bigint. Bot commands only. */ + defaultMemberPermissions?: bigint; + /** Whether usable in DMs. Bot commands only. */ + dmPermission?: boolean; + /** Command permissions. Bot commands only. */ + permissions?: ApplicationCommandPermission[] | Record; + /** Localized display name. */ + displayName: string; + /** Localized display description. */ + displayDescription: string; + /** Whether this is an NSFW command. Bot commands only. */ + nsfw?: boolean; + /** Allowed interaction contexts. Bot commands only. */ + contexts?: InteractionContextType[]; + /** Integration types that can use this command. Bot commands only. */ + integration_types?: ApplicationIntegrationType[]; + /** Global popularity ranking. Bot commands only. */ + global_popularity_rank?: number; + /** Handler type. Bot commands only. */ + handler?: ApplicationCommandHandlerType; + /** Section descriptor for display purposes. */ + section?: ApplicationCommandSectionDescriptor; + /** Score for search ranking. */ + score?: number; + /** Predicate to check if command should be shown. Built-in commands only. */ + predicate?(ctx: CommandContext): boolean; + /** Execute the command. Built-in commands only. */ + execute?(args: CommandArgument[], ctx: CommandContext): void; +} + +/** Sectioned command group for display. */ +export interface SectionedApplicationCommands { + /** Section this group belongs to. */ + section: ApplicationCommandSectionDescriptor; + /** Commands in this section. */ + data: ApplicationCommand[]; +} + +/** Filter options for querying commands. */ +export interface ApplicationCommandQueryFilters { + /** Command types to include. */ + commandTypes: ApplicationCommandType[]; + /** Search text. */ + text?: string; + /** Built-in command handling mode. */ + builtIns?: BuiltInCommandMode; + /** Whether to include application commands. */ + applicationCommands?: boolean; +} + +/** Options for querying commands. */ +export interface ApplicationCommandQueryOptions { + /** Number of placeholder commands to show while loading. */ + placeholderCount?: number; + /** Score method for ranking results. */ + scoreMethod?: ApplicationCommandScoreMethod; + /** Whether to allow empty sections in results. */ + allowEmptySections?: boolean; + /** Whether to allow fetching if needed. */ + allowFetch?: boolean; + /** Whether to include application state. */ + allowApplicationState?: boolean; + /** Specific application ID to query. */ + applicationId?: string; + /** Sorting options. */ + sortOptions?: ApplicationCommandSortOptions; + /** Whether to include install-on-demand apps. */ + installOnDemand?: boolean; +} + +/** Sorting options for application command queries. */ +export interface ApplicationCommandSortOptions { + /** Sorting options for applications. */ + applications: ApplicationCommandSortConfig; + /** Sorting options for commands. */ + commands: ApplicationCommandSortConfig; +} + +/** Sort configuration for frecency and score. */ +export interface ApplicationCommandSortConfig { + /** Whether to use frecency for sorting. */ + useFrecency: boolean; + /** Whether to use score for sorting. */ + useScore: boolean; +} + +/** Result of a command query. */ +export interface ApplicationCommandQueryResult { + /** All section descriptors. */ + descriptors: ApplicationCommandSectionDescriptor[]; + /** Flat list of all commands. */ + commands: ApplicationCommand[]; + /** Commands grouped by section. */ + sectionedCommands: SectionedApplicationCommands[]; + /** Whether data is still loading. */ + loading: boolean; +} + +/** Parameters for checking context state application. */ +export interface ApplicationCommandContextStateParams { + applicationId: string; + channelId: string; + guildId?: string; +} + +/** Result of getting section info. */ +export interface ApplicationCommandSectionInfo { + /** Section descriptor. */ + descriptor?: ApplicationCommandSectionDescriptor; + /** Commands in this section. */ + sectionCommands?: ApplicationCommand[]; + /** Whether installed in a guild. */ + isGuildInstalled: boolean; + /** Whether installed for user. */ + isUserInstalled: boolean; +} + +/** + * Store for application command indexes. + * Manages fetching, caching, and querying of slash commands and context menu commands. + */ +export class ApplicationCommandIndexStore extends FluxStore { + /** Internal index cache keyed by guild/channel/user ID. */ + indices: Record; + /** + * Gets the command index state for the given context. + * @param context Channel context or contextless context. + * @returns Index state for the context. + */ + getContextState(context: ApplicationCommandContext): ApplicationCommandIndexState; + + /** + * Checks if an application has commands in the context state. + * @param params Application and channel info. + * @returns Whether the application has commands in context. + */ + hasContextStateApplication(params: ApplicationCommandContextStateParams): boolean; + + /** + * Gets the command index state for a guild. + * @param guildId Guild ID. + * @returns Index state for the guild. + */ + getGuildState(guildId: string): ApplicationCommandIndexState; + + /** + * Gets the command index state for the current user's installed apps. + * @returns Index state for user-installed apps. + */ + getUserState(): ApplicationCommandIndexState; + + /** + * Checks if an application has commands in the user state. + * @param applicationId Application ID. + * @returns Whether the application has user commands. + */ + hasUserStateApplication(applicationId: string): boolean; + + /** + * Gets the command index state for a specific application. + * @param applicationId Application ID. + * @returns Index state for the application. + */ + getApplicationState(applicationId: string): ApplicationCommandIndexState; + + /** + * Gets all application index states. + * @returns Map of application ID to index state. + */ + getApplicationStates(): Map; + + /** + * Checks if an application state exists. + * @param applicationId Application ID. + * @returns Whether the application state exists. + */ + hasApplicationState(applicationId: string): boolean; + + /** + * Queries commands based on context and filters. + * @param context Channel or contextless context. + * @param filters Query filters. + * @param options Query options. + * @returns Query result with commands and sections. + */ + query( + context: ApplicationCommandContext, + filters: ApplicationCommandQueryFilters, + options: ApplicationCommandQueryOptions + ): ApplicationCommandQueryResult; + + /** + * Queries for install-on-demand app commands. + * @param applicationId Application ID. + * @param channelId Channel ID. + */ + queryInstallOnDemandApp(applicationId: string, channelId: string): void; +} diff --git a/packages/discord-types/src/stores/EditMessageStore.d.ts b/packages/discord-types/src/stores/EditMessageStore.d.ts new file mode 100644 index 000000000..f66786aa5 --- /dev/null +++ b/packages/discord-types/src/stores/EditMessageStore.d.ts @@ -0,0 +1,253 @@ +import { ApplicationCommandOptionType } from "../../enums"; +import { FluxStore, Message } from ".."; + +/** Slate node type values used in the rich text editor. */ +export type SlateNodeType = + | "text" + | "line" + | "s" + | "u" + | "strong" + | "em" + | "image" + | "emoji" + | "customEmoji" + | "link" + | "url" + | "autolink" + | "highlight" + | "paragraph" + | "br" + | "newline" + | "escape" + | "spoiler" + | "blockQuote" + | "inlineCode" + | "codeBlock" + | "mention" + | "userMention" + | "channelMention" + | "channel" + | "guild" + | "attachmentLink" + | "shopLink" + | "soundboard" + | "staticRouteLink" + | "roleMention" + | "commandMention" + | "timestamp" + | "timestampMentionInput" + | "list" + | "heading" + | "subtext" + | "silentPrefix" + | "gameMention" + | "gameMentionInput" + | "textMention" + | "applicationCommandOption"; + +/** A plain text leaf node. */ +export interface SlateTextNode { + text: string; +} + +/** Base interface for Slate element nodes with children. */ +export interface SlateBaseElement { + type: string; + children: SlateNode[]; +} + +/** A line element in the editor. */ +export interface SlateLineElement extends SlateBaseElement { + type: "line"; + codeBlockState?: { + isInCodeBlock: boolean; + }; +} + +/** A block quote element. */ +export interface SlateBlockQuoteElement extends SlateBaseElement { + type: "blockQuote"; +} + +/** An emoji element. */ +export interface SlateEmojiElement extends SlateBaseElement { + type: "emoji"; + emoji: { + name: string; + src?: string; + surrogate: string; + jumboable?: boolean; + }; +} + +/** A custom emoji element. */ +export interface SlateCustomEmojiElement extends SlateBaseElement { + type: "customEmoji"; + emoji: { + emojiId: string; + name: string; + animated: boolean; + jumboable?: boolean; + }; +} + +/** A user mention element. */ +export interface SlateUserMentionElement extends SlateBaseElement { + type: "userMention"; + userId: string; +} + +/** A channel mention element. */ +export interface SlateChannelMentionElement extends SlateBaseElement { + type: "channelMention"; + channelId: string; +} + +/** A role mention element. */ +export interface SlateRoleMentionElement extends SlateBaseElement { + type: "roleMention"; + roleId: string; +} + +/** A text mention element (for @everyone, @here, etc.). */ +export interface SlateTextMentionElement extends SlateBaseElement { + type: "textMention"; + name: string; +} + +/** A soundboard element. */ +export interface SlateSoundboardElement extends SlateBaseElement { + type: "soundboard"; + guildId: string; + soundId: string; +} + +/** Timestamp format style characters. */ +export type TimestampStyle = "t" | "T" | "d" | "D" | "f" | "F" | "R"; + +/** Parsed timestamp data. */ +export interface ParsedTimestamp { + /** The Unix timestamp in seconds as a string. */ + timestamp: string; + /** The format style character. */ + format: TimestampStyle | undefined; + /** The parsed Moment.js object. */ + parsed: object; + /** The full formatted date string. */ + full: string; + /** The formatted string based on the format style. */ + formatted: string; +} + +/** A timestamp element. */ +export interface SlateTimestampElement extends SlateBaseElement { + type: "timestamp"; + parsed: ParsedTimestamp; +} + +/** A static route link element. */ +export interface SlateStaticRouteLinkElement extends SlateBaseElement { + type: "staticRouteLink"; + id: string; + itemId?: string; +} + +/** A game mention element. */ +export interface SlateGameMentionElement extends SlateBaseElement { + type: "gameMention"; + applicationId: string; +} + +/** A timestamp mention input element (while typing). */ +export interface SlateTimestampMentionInputElement extends SlateBaseElement { + type: "timestampMentionInput"; +} + +/** A game mention input element (while typing). */ +export interface SlateGameMentionInputElement extends SlateBaseElement { + type: "gameMentionInput"; +} + +/** An application command option element. */ +export interface SlateApplicationCommandOptionElement extends SlateBaseElement { + type: "applicationCommandOption"; + optionType: ApplicationCommandOptionType; +} + +/** Union of all Slate element types. */ +export type SlateElement = + | SlateLineElement + | SlateBlockQuoteElement + | SlateEmojiElement + | SlateCustomEmojiElement + | SlateUserMentionElement + | SlateChannelMentionElement + | SlateRoleMentionElement + | SlateTextMentionElement + | SlateSoundboardElement + | SlateTimestampElement + | SlateTimestampMentionInputElement + | SlateStaticRouteLinkElement + | SlateGameMentionElement + | SlateGameMentionInputElement + | SlateApplicationCommandOptionElement + | SlateBaseElement; + +/** A Slate node can be either an element or a text leaf. */ +export type SlateNode = SlateElement | SlateTextNode; + +/** The rich value representation used by Slate editor for message editing. */ +export type SlateValue = SlateLineElement[]; + +export class EditMessageStore extends FluxStore { + /** + * Gets the action source that triggered editing for a channel. + * @param channelId The channel ID. + * @returns The source string or undefined if not editing. + */ + getEditActionSource(channelId: string): string | undefined; + + /** + * Gets the message currently being edited in a channel. + * @param channelId The channel ID. + * @returns The message being edited or null if not editing. + */ + getEditingMessage(channelId: string): Message | null; + + /** + * Gets the ID of the message currently being edited in a channel. + * @param channelId The channel ID. + * @returns The message ID or undefined if not editing. + */ + getEditingMessageId(channelId: string): string | undefined; + + /** + * Gets the rich value (Slate editor format) of the editing text. + * @param channelId The channel ID. + * @returns The Slate value or undefined if not editing. + */ + getEditingRichValue(channelId: string): SlateValue | undefined; + + /** + * Gets the plain text value of the editing text. + * @param channelId The channel ID. + * @returns The text value or undefined if not editing. + */ + getEditingTextValue(channelId: string): string | undefined; + + /** + * Checks if a specific message is currently being edited. + * @param channelId The channel ID. + * @param messageId The message ID to check. + * @returns True if the specific message is being edited. + */ + isEditing(channelId: string, messageId: string): boolean; + + /** + * Checks if any message is currently being edited in a channel. + * @param channelId The channel ID. + * @returns True if any message is being edited in the channel. + */ + isEditingAny(channelId: string): boolean; +} diff --git a/packages/discord-types/src/stores/index.d.ts b/packages/discord-types/src/stores/index.d.ts index 12f70760c..d46a3cbd5 100644 --- a/packages/discord-types/src/stores/index.d.ts +++ b/packages/discord-types/src/stores/index.d.ts @@ -1,12 +1,14 @@ // please keep in alphabetical order export * from "./AccessibilityStore"; export * from "./ActiveJoinedThreadsStore"; +export * from "./ApplicationCommandIndexStore"; export * from "./ApplicationStore"; export * from "./AuthenticationStore"; export * from "./CallStore"; export * from "./ChannelRTCStore"; export * from "./ChannelStore"; export * from "./DraftStore"; +export * from "./EditMessageStore"; export * from "./EmojiStore"; export * from "./FluxStore"; export * from "./FriendsStore"; diff --git a/src/webpack/common/stores.ts b/src/webpack/common/stores.ts index 5961b10a0..fc54d6948 100644 --- a/src/webpack/common/stores.ts +++ b/src/webpack/common/stores.ts @@ -79,8 +79,8 @@ export let LocaleStore: t.LocaleStore; export let RTCConnectionStore: t.RTCConnectionStore; export let SoundboardStore: t.SoundboardStore; export let PopoutWindowStore: t.PopoutWindowStore; -export let ApplicationCommandIndexStore: GenericStore; -export let EditMessageStore: GenericStore; +export let ApplicationCommandIndexStore: t.ApplicationCommandIndexStore; +export let EditMessageStore: t.EditMessageStore; /** * @see jsdoc of {@link t.useStateFromStores}