Refactor and update types and handlers

- README changes: removed 'as const' annotation and note.
- Connector changes: dispatched event for commands in gateway.
- Updated processor type guard for command handlers.
- Removed readonly from CommandHandler types in handler definitions.
- Test adjustments: updated demo tests to reliable command registration.
This commit is contained in:
2025-01-12 15:36:01 -06:00
parent 8943b5a06e
commit e6e4fd1a02
5 changed files with 18 additions and 18 deletions
+1 -3
View File
@@ -70,7 +70,7 @@ const avatarCommand = createCommandHandler({
description: 'The user to get the avatar for', description: 'The user to get the avatar for',
required: true required: true
} }
] as const, ],
execute: async (context: Context, args) => { execute: async (context: Context, args) => {
// Args will be typed here as { user: User } // Args will be typed here as { user: User }
context.reply(args.user.avatarURL); context.reply(args.user.avatarURL);
@@ -85,8 +85,6 @@ client.applicationCommands.register('avatar', ApplicationCommandType.Chat, avata
// <...> // <...>
``` ```
> NOTE: The `as const` is required to ensure the types are resolved correctly. This is to work around some TypeScript weirdness.
## Hydration ## Hydration
Hydration allows you to fetch and fill data on Discord objects. This is useful for when you need to fetch additional data about an object. Hydration allows you to fetch and fill data on Discord objects. This is useful for when you need to fetch additional data about an object.
+9 -7
View File
@@ -204,14 +204,16 @@ export class Gateway {
this.client.messages.set(message.id, message); this.client.messages.set(message.id, message);
// Generate context // Generate context
const context = new Context(this.client, this.api, { message }); const context = new Context(this.client, this.api, { message });
// Dispatch event for the command
this.bus.emit(`command:${command}`, context, args);
// // Check if command exists // // Check if command exists
if (this.processor[HandlerType.ChatCommands].has(command)) { // if (this.processor[HandlerType.ChatCommands].has(command)) {
// Execute the handler // // Execute the handler
this.processor[HandlerType.ChatCommands].execute(command, context, args); // this.processor[HandlerType.ChatCommands].execute(command, context, args);
} else { // } else {
// TODO: Custom unknown command handler // // TODO: Custom unknown command handler
context.reply(`Unknown command: ${command}`); // context.reply(`Unknown command: ${command}`);
} // }
} }
}; };
+1 -1
View File
@@ -180,7 +180,7 @@ export class Processor {
has: (event: string) => this.handlers[HandlerType.Interactions].has(event) ?? this.handlers[HandlerType.Interactions].get(event)?.length! > 0 has: (event: string) => this.handlers[HandlerType.Interactions].has(event) ?? this.handlers[HandlerType.Interactions].get(event)?.length! > 0
}; };
static isCommandHandler = (handler: Handler): handler is CommandHandler<readonly ApplicationCommandOption[]> => { static isCommandHandler = (handler: Handler): handler is CommandHandler<ApplicationCommandOption[]> => {
if (typeof handler === 'object') { if (typeof handler === 'object') {
return 'args' in handler && Trait.execute in handler && handler instanceof CommandHandler; return 'args' in handler && Trait.execute in handler && handler instanceof CommandHandler;
} else { } else {
+6 -6
View File
@@ -108,16 +108,16 @@ export type ArgsFromOptions<T extends readonly ApplicationCommandOption[]> = {
: unknown | undefined; : unknown | undefined;
}; };
export type CommandHandlerExecuteFunction<T extends readonly ApplicationCommandOption[]> = (context: Context, args: ArgsFromOptions<T>) => Promise<any> | any; export type CommandHandlerExecuteFunction<T extends ApplicationCommandOption[]> = (context: Context, args: ArgsFromOptions<T>) => Promise<any> | any;
export type CommandHandlerInput<T extends readonly ApplicationCommandOption[]> = { export type CommandHandlerInput<T extends ApplicationCommandOption[]> = {
args: T; args: T;
description: string; description: string;
contexts?: ApplicationCommandContext[]; contexts?: ApplicationCommandContext[];
execute: CommandHandlerExecuteFunction<T>; execute: CommandHandlerExecuteFunction<T>;
}; };
export class CommandHandler<T extends readonly ApplicationCommandOption[]> { export class CommandHandler<T extends ApplicationCommandOption[]> {
args: T; args: T;
description: string; description: string;
contexts?: ApplicationCommandContext[]; contexts?: ApplicationCommandContext[];
@@ -155,7 +155,7 @@ export class CommandHandler<T extends readonly ApplicationCommandOption[]> {
}; };
// Helper function to infer type of `args` // Helper function to infer type of `args`
export function createCommandHandler<T extends readonly ApplicationCommandOption[]>( export function createCommandHandler<T extends ApplicationCommandOption[]>(
handler: CommandHandlerInput<T> handler: CommandHandlerInput<T>
): CommandHandler<T> { ): CommandHandler<T> {
return new CommandHandler(handler); return new CommandHandler(handler);
@@ -166,6 +166,6 @@ export type EventHandlerFunction = (context: Context | null, payload: EventPaylo
export type InteractionHandlerFunction<P = InteractionData> = (context: Context, payload: P) => Promise<any> | any; export type InteractionHandlerFunction<P = InteractionData> = (context: Context, payload: P) => Promise<any> | any;
export type HandlerWithoutContext = EventHandlerFunction; export type HandlerWithoutContext = EventHandlerFunction;
export type HanderWithContext = InteractionHandlerFunction | CommandHandlerFunction | CommandHandler<readonly ApplicationCommandOption[]>; export type HanderWithContext = InteractionHandlerFunction | CommandHandlerFunction | CommandHandler<ApplicationCommandOption[]>;
export type Handler = InteractionHandlerFunction<InteractionCommpoentData> | InteractionHandlerFunction<InteractionCommandData> | EventHandlerFunction | CommandHandlerFunction | CommandHandler<readonly ApplicationCommandOption[]>; export type Handler = InteractionHandlerFunction<InteractionCommpoentData> | InteractionHandlerFunction<InteractionCommandData> | EventHandlerFunction | CommandHandlerFunction | CommandHandler<ApplicationCommandOption[]>;
+1 -1
View File
@@ -62,7 +62,7 @@ client.applicationCommands.register('hello', ApplicationCommandType.Chat, create
{ name: "Bear", value: "Bear" } { name: "Bear", value: "Bear" }
] ]
} }
] as const, ],
execute: async (context, args) => { execute: async (context, args) => {
context.reply( context.reply(
`\ `\