diff --git a/src/client/onmessagecreate.ts b/src/client/onmessagecreate.ts index 1530b8d..9968621 100644 --- a/src/client/onmessagecreate.ts +++ b/src/client/onmessagecreate.ts @@ -91,7 +91,7 @@ export async function onMessageCreate( const prefixes = (await self.options.commands.prefix(message)).sort((a, b) => b.length - a.length); const prefix = prefixes.find(x => message.content.startsWith(x)); - if (!(prefix && message.content.startsWith(prefix))) return; + if (!(prefix !== undefined && message.content.startsWith(prefix))) return; const content = message.content.slice(prefix.length).trimStart(); const { fullCommandName, command, parent } = getCommandFromContent( @@ -105,7 +105,8 @@ export async function onMessageCreate( if (!command) return; if (!command.run) return self.logger.warn(`${fullCommandName} command does not have 'run' callback`); - if (!(command.contexts?.includes(InteractionContextType.BotDM) || message.guildId)) return; + if (!command.contexts.includes(InteractionContextType.BotDM) && !message.guildId) return; + if (!command.contexts.includes(InteractionContextType.Guild) && message.guildId) return; if (command.guildId && !command.guildId?.includes(message.guildId!)) return; const resolved: MakeRequired = { diff --git a/src/commands/applications/chat.ts b/src/commands/applications/chat.ts index 2eb6e8f..54260c6 100644 --- a/src/commands/applications/chat.ts +++ b/src/commands/applications/chat.ts @@ -126,8 +126,8 @@ export class BaseCommand { nsfw?: boolean; description!: string; defaultMemberPermissions?: bigint; - integrationTypes?: ApplicationIntegrationType[]; - contexts?: InteractionContextType[]; + integrationTypes: ApplicationIntegrationType[] = []; + contexts: InteractionContextType[] = []; botPermissions?: bigint; name_localizations?: Partial>; description_localizations?: Partial>; diff --git a/src/commands/applications/menu.ts b/src/commands/applications/menu.ts index 96fbb00..4b42d71 100644 --- a/src/commands/applications/menu.ts +++ b/src/commands/applications/menu.ts @@ -1,71 +1,71 @@ -import type { - ApplicationCommandType, - ApplicationIntegrationType, - InteractionContextType, - LocaleString, -} from 'discord-api-types/v10'; -import { magicImport, type PermissionStrings } from '../../common'; -import type { RegisteredMiddlewares } from '../decorators'; -import type { MenuCommandContext } from './menucontext'; -import type { UsingClient } from './shared'; - -export abstract class ContextMenuCommand { - middlewares: (keyof RegisteredMiddlewares)[] = []; - - __filePath?: string; - __t?: { name: string | undefined; description: string | undefined }; - - guildId?: string[]; - name!: string; - type!: ApplicationCommandType.User | ApplicationCommandType.Message; - nsfw?: boolean; - integrationTypes?: ApplicationIntegrationType[]; - contexts?: InteractionContextType[]; - description!: string; - defaultMemberPermissions?: bigint; - botPermissions?: bigint; - dm?: boolean; - name_localizations?: Partial>; - description_localizations?: Partial>; - - toJSON() { - return { - name: this.name, - type: this.type, - nsfw: this.nsfw, - description: this.description, - name_localizations: this.name_localizations, - description_localizations: this.description_localizations, - guild_id: this.guildId, - dm_permission: this.dm, - default_member_permissions: this.defaultMemberPermissions ? this.defaultMemberPermissions.toString() : undefined, - contexts: this.contexts, - integration_types: this.integrationTypes, - }; - } - - async reload() { - delete require.cache[this.__filePath!]; - const __tempCommand = await magicImport(this.__filePath!).then(x => x.default ?? x); - - Object.setPrototypeOf(this, __tempCommand.prototype); - } - - abstract run?(context: MenuCommandContext): any; - onAfterRun?(context: MenuCommandContext, error: unknown | undefined): any; - onRunError(context: MenuCommandContext, error: unknown): any { - context.client.logger.fatal(`${this.name}.`, context.author.id, error); - } - onMiddlewaresError(context: MenuCommandContext, error: string): any { - context.client.logger.fatal(`${this.name}.`, context.author.id, error); - } - onBotPermissionsFail(context: MenuCommandContext, permissions: PermissionStrings): any { - context.client.logger.fatal(`${this.name}.`, context.author.id, permissions); - } - onPermissionsFail(context: MenuCommandContext, permissions: PermissionStrings): any { - context.client.logger.fatal(`${this.name}.`, context.author.id, permissions); - } - onInternalError(client: UsingClient, error?: unknown): any { - client.logger.fatal(error); - } -} +import type { + ApplicationCommandType, + ApplicationIntegrationType, + InteractionContextType, + LocaleString, +} from 'discord-api-types/v10'; +import { magicImport, type PermissionStrings } from '../../common'; +import type { RegisteredMiddlewares } from '../decorators'; +import type { MenuCommandContext } from './menucontext'; +import type { UsingClient } from './shared'; + +export abstract class ContextMenuCommand { + middlewares: (keyof RegisteredMiddlewares)[] = []; + + __filePath?: string; + __t?: { name: string | undefined; description: string | undefined }; + + guildId?: string[]; + name!: string; + type!: ApplicationCommandType.User | ApplicationCommandType.Message; + nsfw?: boolean; + integrationTypes: ApplicationIntegrationType[] = []; + contexts: InteractionContextType[] = []; + description!: string; + defaultMemberPermissions?: bigint; + botPermissions?: bigint; + dm?: boolean; + name_localizations?: Partial>; + description_localizations?: Partial>; + + toJSON() { + return { + name: this.name, + type: this.type, + nsfw: this.nsfw, + description: this.description, + name_localizations: this.name_localizations, + description_localizations: this.description_localizations, + guild_id: this.guildId, + dm_permission: this.dm, + default_member_permissions: this.defaultMemberPermissions ? this.defaultMemberPermissions.toString() : undefined, + contexts: this.contexts, + integration_types: this.integrationTypes, + }; + } + + async reload() { + delete require.cache[this.__filePath!]; + const __tempCommand = await magicImport(this.__filePath!).then(x => x.default ?? x); + + Object.setPrototypeOf(this, __tempCommand.prototype); + } + + abstract run?(context: MenuCommandContext): any; + onAfterRun?(context: MenuCommandContext, error: unknown | undefined): any; + onRunError(context: MenuCommandContext, error: unknown): any { + context.client.logger.fatal(`${this.name}.`, context.author.id, error); + } + onMiddlewaresError(context: MenuCommandContext, error: string): any { + context.client.logger.fatal(`${this.name}.`, context.author.id, error); + } + onBotPermissionsFail(context: MenuCommandContext, permissions: PermissionStrings): any { + context.client.logger.fatal(`${this.name}.`, context.author.id, permissions); + } + onPermissionsFail(context: MenuCommandContext, permissions: PermissionStrings): any { + context.client.logger.fatal(`${this.name}.`, context.author.id, permissions); + } + onInternalError(client: UsingClient, error?: unknown): any { + client.logger.fatal(error); + } +} diff --git a/src/commands/decorators.ts b/src/commands/decorators.ts index c56fa92..c4c72e8 100644 --- a/src/commands/decorators.ts +++ b/src/commands/decorators.ts @@ -1,183 +1,187 @@ -import { - ApplicationCommandType, - ApplicationIntegrationType, - InteractionContextType, - PermissionFlagsBits, - type LocaleString, -} from 'discord-api-types/v10'; -import type { FlatObjectKeys, PermissionStrings } from '../common'; -import type { CommandOption, OptionsRecord, SubCommand } from './applications/chat'; -import type { DefaultLocale, IgnoreCommand, MiddlewareContext } from './applications/shared'; - -export interface RegisteredMiddlewares {} - -type DeclareOptions = - | { - name: string; - description: string; - botPermissions?: PermissionStrings | bigint; - defaultMemberPermissions?: PermissionStrings | bigint; - guildId?: string[]; - nsfw?: boolean; - integrationTypes?: (keyof typeof ApplicationIntegrationType)[]; - contexts?: (keyof typeof InteractionContextType)[]; - ignore?: IgnoreCommand; - aliases?: string[]; - } - | (Omit< - { - name: string; - description: string; - botPermissions?: PermissionStrings | bigint; - defaultMemberPermissions?: PermissionStrings | bigint; - guildId?: string[]; - nsfw?: boolean; - integrationTypes?: (keyof typeof ApplicationIntegrationType)[]; - contexts?: (keyof typeof InteractionContextType)[]; - }, - 'type' | 'description' - > & { - type: ApplicationCommandType.User | ApplicationCommandType.Message; - }); - -export function Locales({ - name: names, - description: descriptions, -}: { - name?: [language: LocaleString, value: string][]; - description?: [language: LocaleString, value: string][]; -}) { - return (target: T) => - class extends target { - name_localizations = names ? Object.fromEntries(names) : undefined; - description_localizations = descriptions ? Object.fromEntries(descriptions) : undefined; - }; -} - -export function LocalesT(name?: FlatObjectKeys, description?: FlatObjectKeys) { - return (target: T) => - class extends target { - __t = { name, description }; - }; -} - -export function GroupsT( - groups: Record< - string /* name for group*/, - { - name?: FlatObjectKeys; - description?: FlatObjectKeys; - defaultDescription: string; - aliases?: string[]; - } - >, -) { - return (target: T) => - class extends target { - __tGroups = groups; - groupsAliases: Record = {}; - constructor(...args: any[]) { - super(...args); - for (const i in groups) { - for (const j of groups[i].aliases ?? []) { - this.groupsAliases[j] = i; - } - } - } - }; -} - -export function Groups( - groups: Record< - string /* name for group*/, - { - name?: [language: LocaleString, value: string][]; - description?: [language: LocaleString, value: string][]; - defaultDescription: string; - aliases?: string[]; - } - >, -) { - return (target: T) => - class extends target { - groups = groups; - groupsAliases: Record = {}; - constructor(...args: any[]) { - super(...args); - for (const i in groups) { - for (const j of groups[i].aliases ?? []) { - this.groupsAliases[j] = i; - } - } - } - }; -} - -export function Group(groupName: string) { - return (target: T) => - class extends target { - group = groupName; - }; -} - -export function Options(options: (new () => SubCommand)[] | OptionsRecord) { - return (target: T) => - class extends target { - options: SubCommand[] | CommandOption[] = Array.isArray(options) - ? options.map(x => new x()) - : Object.entries(options).map(([name, option]) => { - return { - name, - ...option, - } as CommandOption; - }); - }; -} - -export function AutoLoad() { - return (target: T) => - class extends target { - __autoload = true; - }; -} - -export type ParseMiddlewares> = { - [k in keyof T]: T[k]; -}; - -export function Middlewares(cbs: readonly (keyof RegisteredMiddlewares)[]) { - return (target: T) => - class extends target { - middlewares = cbs; - }; -} - -export function Declare(declare: DeclareOptions) { - return (target: T) => - class extends target { - name = declare.name; - nsfw = declare.nsfw; - contexts = declare.contexts?.map(i => InteractionContextType[i]); - integrationTypes = declare.integrationTypes?.map(i => ApplicationIntegrationType[i]); - defaultMemberPermissions = Array.isArray(declare.defaultMemberPermissions) - ? declare.defaultMemberPermissions?.reduce((acc, prev) => acc | PermissionFlagsBits[prev], BigInt(0)) - : declare.defaultMemberPermissions; - botPermissions = Array.isArray(declare.botPermissions) - ? declare.botPermissions?.reduce((acc, prev) => acc | PermissionFlagsBits[prev], BigInt(0)) - : declare.botPermissions; - description = ''; - type: ApplicationCommandType = ApplicationCommandType.ChatInput; - guildId?: string[]; - ignore?: IgnoreCommand; - aliases?: string[]; - constructor(...args: any[]) { - super(...args); - if ('description' in declare) this.description = declare.description; - if ('type' in declare) this.type = declare.type; - if ('guildId' in declare) this.guildId = declare.guildId; - if ('ignore' in declare) this.ignore = declare.ignore; - if ('aliases' in declare) this.aliases = declare.aliases; - // check if all properties are valid - } - }; -} +import { + ApplicationCommandType, + ApplicationIntegrationType, + InteractionContextType, + PermissionFlagsBits, + type LocaleString, +} from 'discord-api-types/v10'; +import type { FlatObjectKeys, PermissionStrings } from '../common'; +import type { CommandOption, OptionsRecord, SubCommand } from './applications/chat'; +import type { DefaultLocale, IgnoreCommand, MiddlewareContext } from './applications/shared'; + +export interface RegisteredMiddlewares {} + +type DeclareOptions = + | { + name: string; + description: string; + botPermissions?: PermissionStrings | bigint; + defaultMemberPermissions?: PermissionStrings | bigint; + guildId?: string[]; + nsfw?: boolean; + integrationTypes?: (keyof typeof ApplicationIntegrationType)[]; + contexts?: (keyof typeof InteractionContextType)[]; + ignore?: IgnoreCommand; + aliases?: string[]; + } + | (Omit< + { + name: string; + description: string; + botPermissions?: PermissionStrings | bigint; + defaultMemberPermissions?: PermissionStrings | bigint; + guildId?: string[]; + nsfw?: boolean; + integrationTypes?: (keyof typeof ApplicationIntegrationType)[]; + contexts?: (keyof typeof InteractionContextType)[]; + }, + 'type' | 'description' + > & { + type: ApplicationCommandType.User | ApplicationCommandType.Message; + }); + +export function Locales({ + name: names, + description: descriptions, +}: { + name?: [language: LocaleString, value: string][]; + description?: [language: LocaleString, value: string][]; +}) { + return (target: T) => + class extends target { + name_localizations = names ? Object.fromEntries(names) : undefined; + description_localizations = descriptions ? Object.fromEntries(descriptions) : undefined; + }; +} + +export function LocalesT(name?: FlatObjectKeys, description?: FlatObjectKeys) { + return (target: T) => + class extends target { + __t = { name, description }; + }; +} + +export function GroupsT( + groups: Record< + string /* name for group*/, + { + name?: FlatObjectKeys; + description?: FlatObjectKeys; + defaultDescription: string; + aliases?: string[]; + } + >, +) { + return (target: T) => + class extends target { + __tGroups = groups; + groupsAliases: Record = {}; + constructor(...args: any[]) { + super(...args); + for (const i in groups) { + for (const j of groups[i].aliases ?? []) { + this.groupsAliases[j] = i; + } + } + } + }; +} + +export function Groups( + groups: Record< + string /* name for group*/, + { + name?: [language: LocaleString, value: string][]; + description?: [language: LocaleString, value: string][]; + defaultDescription: string; + aliases?: string[]; + } + >, +) { + return (target: T) => + class extends target { + groups = groups; + groupsAliases: Record = {}; + constructor(...args: any[]) { + super(...args); + for (const i in groups) { + for (const j of groups[i].aliases ?? []) { + this.groupsAliases[j] = i; + } + } + } + }; +} + +export function Group(groupName: string) { + return (target: T) => + class extends target { + group = groupName; + }; +} + +export function Options(options: (new () => SubCommand)[] | OptionsRecord) { + return (target: T) => + class extends target { + options: SubCommand[] | CommandOption[] = Array.isArray(options) + ? options.map(x => new x()) + : Object.entries(options).map(([name, option]) => { + return { + name, + ...option, + } as CommandOption; + }); + }; +} + +export function AutoLoad() { + return (target: T) => + class extends target { + __autoload = true; + }; +} + +export type ParseMiddlewares> = { + [k in keyof T]: T[k]; +}; + +export function Middlewares(cbs: readonly (keyof RegisteredMiddlewares)[]) { + return (target: T) => + class extends target { + middlewares = cbs; + }; +} + +export function Declare(declare: DeclareOptions) { + return (target: T) => + class extends target { + name = declare.name; + nsfw = declare.nsfw; + contexts = + declare.contexts?.map(i => InteractionContextType[i]) ?? + Object.values(InteractionContextType).filter(x => typeof x === 'number'); + integrationTypes = declare.integrationTypes?.map(i => ApplicationIntegrationType[i]) ?? [ + ApplicationIntegrationType.GuildInstall, + ]; + defaultMemberPermissions = Array.isArray(declare.defaultMemberPermissions) + ? declare.defaultMemberPermissions?.reduce((acc, prev) => acc | PermissionFlagsBits[prev], BigInt(0)) + : declare.defaultMemberPermissions; + botPermissions = Array.isArray(declare.botPermissions) + ? declare.botPermissions?.reduce((acc, prev) => acc | PermissionFlagsBits[prev], BigInt(0)) + : declare.botPermissions; + description = ''; + type: ApplicationCommandType = ApplicationCommandType.ChatInput; + guildId?: string[]; + ignore?: IgnoreCommand; + aliases?: string[]; + constructor(...args: any[]) { + super(...args); + if ('description' in declare) this.description = declare.description; + if ('type' in declare) this.type = declare.type; + if ('guildId' in declare) this.guildId = declare.guildId; + if ('ignore' in declare) this.ignore = declare.ignore; + if ('aliases' in declare) this.aliases = declare.aliases; + // check if all properties are valid + } + }; +} diff --git a/src/commands/handler.ts b/src/commands/handler.ts index c3e88ca..5da093d 100644 --- a/src/commands/handler.ts +++ b/src/commands/handler.ts @@ -143,14 +143,14 @@ export class CommandHandler extends BaseHandler { //TODO: locales if ('contexts' in command && 'contexts' in cached) { - if (command.contexts?.length !== cached.contexts?.length) return true; + if (command.contexts.length !== cached.contexts.length) return true; if (command.contexts && cached.contexts) { if (command.contexts.some(ctx => !cached.contexts!.includes(ctx))) return true; } } if ('integration_types' in command && 'integration_types' in cached) { - if (command.integration_types?.length !== cached.integration_types?.length) return true; + if (command.integration_types.length !== cached.integration_types.length) return true; if (command.integration_types && cached.integration_types) { if (command.integration_types.some(ctx => !cached.integration_types!.includes(ctx))) return true; }