Skip to content

Commit

Permalink
fix(ApplicationCommandRegistries): add the right ids in the right pla…
Browse files Browse the repository at this point in the history
…ce (#716)

* fix(ApplicationCommandRegistries): add the right ids in the right place
Doesn't break anything funnily enough but its technically wrong

* fix: proper fix for the issue

* chore: proper split

* chore: dumbass 100

* chore: document commandName

* chore: kyra nits
  • Loading branch information
vladfrangu committed Jan 13, 2024
1 parent d41991c commit 34193ef
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 48 deletions.
31 changes: 25 additions & 6 deletions src/lib/utils/application-commands/ApplicationCommandRegistries.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
/* eslint-disable @typescript-eslint/dot-notation */
import { container } from '@sapphire/pieces';
import type { RESTPostAPIApplicationCommandsJSONBody } from 'discord-api-types/v10';
import type { ApplicationCommandManager } from 'discord.js';
import { ApplicationCommandType, type ApplicationCommandManager } from 'discord.js';
import type { Command } from '../../structures/Command';
import type { CommandStore } from '../../structures/CommandStore';
import { RegisterBehavior } from '../../types/Enums';
import { InternalRegistryAPIType, RegisterBehavior } from '../../types/Enums';
import { Events } from '../../types/Events';
import { ApplicationCommandRegistry } from './ApplicationCommandRegistry';
import { getNeededRegistryParameters } from './getNeededParameters';
Expand Down Expand Up @@ -125,8 +126,17 @@ export async function handleBulkOverwrite(commandStore: CommandStore, applicatio
if (piece) {
const registry = piece.applicationCommandRegistry;

registry.globalCommandId = id;
registry.addChatInputCommandIds(id);
switch (globalCommand.type) {
case ApplicationCommandType.ChatInput: {
registry['handleIdAddition'](InternalRegistryAPIType.ChatInput, id);
break;
}
case ApplicationCommandType.User:
case ApplicationCommandType.Message: {
registry['handleIdAddition'](InternalRegistryAPIType.ContextMenu, id);
break;
}
}

// idHints are useless, and any manually added id or names could end up not being valid any longer if you use bulk overwrites
// That said, this might be an issue, so we might need to do it like `handleAppendOrUpdate`
Expand Down Expand Up @@ -161,9 +171,18 @@ export async function handleBulkOverwrite(commandStore: CommandStore, applicatio

if (piece) {
const registry = piece.applicationCommandRegistry;
registry.guildCommandIds.set(guildId, id);

registry.addChatInputCommandIds(id);
switch (guildCommand.type) {
case ApplicationCommandType.ChatInput: {
registry['handleIdAddition'](InternalRegistryAPIType.ChatInput, id, guildId);
break;
}
case ApplicationCommandType.User:
case ApplicationCommandType.Message: {
registry['handleIdAddition'](InternalRegistryAPIType.ContextMenu, id, guildId);
break;
}
}

// idHints are useless, and any manually added ids or names could no longer be valid if you use bulk overwrites.
// That said, this might be an issue, so we might need to do it like `handleAppendOrUpdate`
Expand Down
140 changes: 98 additions & 42 deletions src/lib/utils/application-commands/ApplicationCommandRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ import {
type RESTPostAPIChatInputApplicationCommandsJSONBody,
type RESTPostAPIContextMenuApplicationCommandsJSONBody
} from 'discord-api-types/v10';
import type {
ApplicationCommand,
ApplicationCommandManager,
ChatInputApplicationCommandData,
import {
Collection,
MessageApplicationCommandData,
UserApplicationCommandData
type ApplicationCommand,
type ApplicationCommandManager,
type ChatInputApplicationCommandData,
type MessageApplicationCommandData,
type UserApplicationCommandData
} from 'discord.js';
import { InternalRegistryAPIType, RegisterBehavior } from '../../types/Enums';
import { allGuildIdsToFetchCommandsFor, getDefaultBehaviorWhenNotIdentical, getDefaultGuildIds } from './ApplicationCommandRegistries';
Expand All @@ -26,14 +26,61 @@ import { getCommandDifferences, getCommandDifferencesFast } from './computeDiffe
import { convertApplicationCommandToApiData, normalizeChatInputCommand, normalizeContextMenuCommand } from './normalizeInputs';

export class ApplicationCommandRegistry {
/**
* The piece this registry is for.
*/
public 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}
*/
public readonly chatInputCommands = new 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}
*/
public readonly contextMenuCommands = new Set<string>();

/**
* The guild ids that we need to fetch the commands for.
*/
public readonly guildIdsToFetch = new 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.
*/
public globalCommandId: string | null = null;
public readonly guildCommandIds = new Map<string, string>();

/**
* A set of all registered and valid global chat input command ids that point to this registry.
*/
public readonly globalChatInputCommandIds = new Set<string>();

/**
* A set of all registered and valid global context menu command ids that point to this registry.
*/
public readonly globalContextMenuCommandIds = new 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.
*/
public readonly guildCommandIds = new Collection<string, string>();

/**
* A map of guild ids to a set of registered and valid chat input command ids that point to this registry.
*/
public readonly guildIdToChatInputCommandIds = new 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.
*/
public readonly guildIdToContextMenuCommandIds = new Collection<string, Set<string>>();

private readonly apiCalls: InternalAPICall[] = [];

Expand Down Expand Up @@ -225,6 +272,42 @@ export class ApplicationCommandRegistry {
}
}

protected handleIdAddition(type: InternalRegistryAPIType, id: string, guildId?: string | null) {
switch (type) {
case InternalRegistryAPIType.ChatInput: {
this.addChatInputCommandIds(id);

if (guildId) {
this.guildIdToChatInputCommandIds.ensure(guildId, () => new Set()).add(id);
} else {
this.globalChatInputCommandIds.add(id);
}
break;
}
case InternalRegistryAPIType.ContextMenu: {
this.addContextMenuCommandIds(id);

if (guildId) {
this.guildIdToContextMenuCommandIds.ensure(guildId, () => new Set()).add(id);
} else {
this.globalContextMenuCommandIds.add(id);
}
break;
}
}

// Old field handling
if (guildId) {
// Old, wrongly typed field (thx kyra for spotting >_>)
if (!this.guildCommandIds.has(guildId)) {
this.guildCommandIds.set(guildId, id);
}
} else {
// First come, first serve (thx kyra for spotting >_>)
this.globalCommandId ??= id;
}
}

private getGuildIdsToRegister(options?: ApplicationCommandRegistryRegisterOptions) {
let guildIdsToRegister: ApplicationCommandRegistry.RegisterOptions['guildIds'] = undefined;

Expand Down Expand Up @@ -298,16 +381,8 @@ export class ApplicationCommandRegistry {
const globalCommand = globalCommands.find(findCallback);

if (globalCommand) {
switch (apiCall.type) {
case InternalRegistryAPIType.ChatInput:
this.addChatInputCommandIds(globalCommand.id);
break;
case InternalRegistryAPIType.ContextMenu:
this.addContextMenuCommandIds(globalCommand.id);
break;
}

this.debug(`Checking if command "${commandName}" is identical with global ${type} command with id "${globalCommand.id}"`);
this.handleIdAddition(apiCall.type, globalCommand.id);
await this.handleCommandPresent(globalCommand, builtData, behaviorIfNotEqual, null);
} else if (registerOptions.registerCommandIfMissing ?? true) {
this.debug(`Creating new global ${type} command with name "${commandName}"`);
Expand All @@ -332,16 +407,7 @@ export class ApplicationCommandRegistry {

if (existingGuildCommand) {
this.debug(`Checking if guild ${type} command "${commandName}" is identical to command "${existingGuildCommand.id}"`);

switch (apiCall.type) {
case InternalRegistryAPIType.ChatInput:
this.addChatInputCommandIds(existingGuildCommand.id);
break;
case InternalRegistryAPIType.ContextMenu:
this.addContextMenuCommandIds(existingGuildCommand.id);
break;
}

this.handleIdAddition(apiCall.type, existingGuildCommand.id, guildId);
await this.handleCommandPresent(existingGuildCommand, builtData, behaviorIfNotEqual, guildId);
} else if (registerOptions.registerCommandIfMissing ?? true) {
this.debug(`Creating new guild ${type} command with name "${commandName}" for guild "${guildId}"`);
Expand All @@ -358,12 +424,6 @@ export class ApplicationCommandRegistry {
behaviorIfNotEqual: RegisterBehavior,
guildId: string | null
) {
if (guildId) {
this.guildCommandIds.set(guildId, applicationCommand.id);
} else {
this.globalCommandId = applicationCommand.id;
}

if (behaviorIfNotEqual === RegisterBehavior.BulkOverwrite) {
this.debug(
`Command "${this.commandName}" has the behaviorIfNotEqual set to "BulkOverwrite" which is invalid. Using defaultBehaviorWhenNotIdentical instead`
Expand Down Expand Up @@ -467,12 +527,6 @@ export class ApplicationCommandRegistry {
try {
const result = await commandsManager.create(apiData, guildId);

if (guildId) {
this.guildCommandIds.set(guildId, result.id);
} else {
this.globalCommandId = result.id;
}

this.info(
`Successfully created ${type}${guildId ? ' guild' : ''} command "${apiData.name}" with id "${
result.id
Expand All @@ -481,13 +535,15 @@ export class ApplicationCommandRegistry {

switch (apiData.type) {
case undefined:
case ApplicationCommandType.ChatInput:
this.addChatInputCommandIds(result.id);
case ApplicationCommandType.ChatInput: {
this.handleIdAddition(InternalRegistryAPIType.ChatInput, result.id, guildId);
break;
}
case ApplicationCommandType.Message:
case ApplicationCommandType.User:
this.addContextMenuCommandIds(result.id);
case ApplicationCommandType.User: {
this.handleIdAddition(InternalRegistryAPIType.ContextMenu, result.id, guildId);
break;
}
}
} catch (err) {
this.error(
Expand Down

0 comments on commit 34193ef

Please sign in to comment.