Globally setting the guild in which to register commands by default

Even though I'm setting ApplicationCommandRegistries.setDefaultGuildIds(<GUILD_ID>); before <SapphireClient>.login the commands are still being registered globally. The commands do not have the guildIds option set.
78 Replies
Favna
Favna3mo ago
Which type of overwrite are you using?
Teixeira
Teixeira3mo ago
Sorry could you clarify what you mean by overwrite?
Favna
Favna3mo ago
Are you using BulkOverwrite, Verbose overwrite, or not configured anything so the default. The behaviorIfIdentical
Teixeira
Teixeira3mo ago
The default one, haven't configured it
Favna
Favna3mo ago
Righhttt... I'm 200% sure this was tested to work. Please show code. The more the better. Also @vladdy
vladdy
vladdy3mo ago
...I sure hope you're calling setDefaultGuildIds with an array
Teixeira
Teixeira3mo ago
I've double-checked and yes I am, also tried using the exact same value in the guildIds option of the actual command's registerChatInputCommand call and it works as expected
vladdy
vladdy3mo ago
that is strange, I use that in highlights dev and it works fine do you call that set before or after calling client.login?
Favna
Favna3mo ago
We have a tag for this
Teixeira
Teixeira3mo ago
What the hell?
No description
vladdy
vladdy3mo ago
discord moment
Teixeira
Teixeira3mo ago
So here's how I am doing it:
ApplicationCommandRegistries.setDefaultGuildIds(this._environment.GUILD_IDS.split(','));
await this.client.login(this._environment.DISCORD_TOKEN);
ApplicationCommandRegistries.setDefaultGuildIds(this._environment.GUILD_IDS.split(','));
await this.client.login(this._environment.DISCORD_TOKEN);
And the command:
/**
* Adds usable quotes.
*/
export class QuotesSubcommandGroup extends Subcommand {
public constructor(context: Subcommand.LoaderContext, options: Subcommand.Options) {
super(context, {
...options,
name: 'quotes',
subcommands: [
{
name: 'add',
chatInputRun: 'chatInputAdd'
},
{
name: 'remove',
chatInputRun: 'chatInputRemove'
}
]
});
}

/**
* Registers this slash command.
*
* @param registry - The {@link Command.Registry} instance associated with this command.
*/
public override registerApplicationCommands(registry: Subcommand.Registry) {
registry.registerChatInputCommand(
(builder) =>
builder
.setName('quotes') //
.setDescription('Manages the list of quotes.')
.setDefaultMemberPermissions('0')
.addSubcommand((subCommand) => {
return subCommand //
.setName('add')
.setDescription('Add quotes to the list.');
})
{
idHints: ['1217871312098295838'],
}
);
}
}
/**
* Adds usable quotes.
*/
export class QuotesSubcommandGroup extends Subcommand {
public constructor(context: Subcommand.LoaderContext, options: Subcommand.Options) {
super(context, {
...options,
name: 'quotes',
subcommands: [
{
name: 'add',
chatInputRun: 'chatInputAdd'
},
{
name: 'remove',
chatInputRun: 'chatInputRemove'
}
]
});
}

/**
* Registers this slash command.
*
* @param registry - The {@link Command.Registry} instance associated with this command.
*/
public override registerApplicationCommands(registry: Subcommand.Registry) {
registry.registerChatInputCommand(
(builder) =>
builder
.setName('quotes') //
.setDescription('Manages the list of quotes.')
.setDefaultMemberPermissions('0')
.addSubcommand((subCommand) => {
return subCommand //
.setName('add')
.setDescription('Add quotes to the list.');
})
{
idHints: ['1217871312098295838'],
}
);
}
}
vladdy
vladdy3mo ago
hmmm and what do the logs say also which behaviorWhenMissing are you using? just the default one?
Teixeira
Teixeira3mo ago
Yes the default one Hold on I'll reproduce it and get the logs
vladdy
vladdy3mo ago
oh also, share the sapphire version pls
Teixeira
Teixeira3mo ago
├── @sapphire/cli@1.9.3
├── @sapphire/framework@5.0.7
├── @sapphire/plugin-logger@4.0.2
├── @sapphire/plugin-subcommands@6.0.3
├── @sapphire/prettier-config@2.0.0
├── @sapphire/timestamp@1.0.3
├── @sapphire/ts-config@5.0.1
├── discord.js@14.14.1
├── @sapphire/cli@1.9.3
├── @sapphire/framework@5.0.7
├── @sapphire/plugin-logger@4.0.2
├── @sapphire/plugin-subcommands@6.0.3
├── @sapphire/prettier-config@2.0.0
├── @sapphire/timestamp@1.0.3
├── @sapphire/ts-config@5.0.1
├── discord.js@14.14.1
Here are the logs:
2024-03-14 17:30:11 - INFO - Shard of id 0 is now ready with 0 unavailable guilds.
2024-03-14 17:30:11 - INFO - ApplicationCommandRegistries: Initializing...
2024-03-14 17:30:11 - INFO - Successfully logged in as "QOTD Bot" (1217468921607880764)
2024-03-14 17:30:12 - DEBUG - ApplicationCommandRegistry[quotes] Preparing to process 1 possible command registrations / updates...
2024-03-14 17:30:12 - DEBUG - ApplicationCommandRegistry[quotes] Creating new global chat input command with name "quotes"
2024-03-14 17:30:12 - INFO - ApplicationCommandRegistry[quotes] Successfully created chat input command "quotes" with id "1217887517987180725". You should add the id to the "idHints" property of the register method you used!
2024-03-14 17:30:12 - DEBUG - ApplicationCommandRegistry[quotes] Registering id "1217887517987180725" to internal chat input map
2024-03-14 17:30:11 - INFO - Shard of id 0 is now ready with 0 unavailable guilds.
2024-03-14 17:30:11 - INFO - ApplicationCommandRegistries: Initializing...
2024-03-14 17:30:11 - INFO - Successfully logged in as "QOTD Bot" (1217468921607880764)
2024-03-14 17:30:12 - DEBUG - ApplicationCommandRegistry[quotes] Preparing to process 1 possible command registrations / updates...
2024-03-14 17:30:12 - DEBUG - ApplicationCommandRegistry[quotes] Creating new global chat input command with name "quotes"
2024-03-14 17:30:12 - INFO - ApplicationCommandRegistry[quotes] Successfully created chat input command "quotes" with id "1217887517987180725". You should add the id to the "idHints" property of the register method you used!
2024-03-14 17:30:12 - DEBUG - ApplicationCommandRegistry[quotes] Registering id "1217887517987180725" to internal chat input map
Favna
Favna3mo ago
Also make sure you've installed the package.json dependencies (run your install command again) and make sure you are running the latest compiled TS code (nuke dist and if you have it tsconfig.tsbuildinfo then rebuild)
Teixeira
Teixeira3mo ago
On it
vladdy
vladdy3mo ago
(i've had that non-nuked dist bite my ass before)
Favna
Favna3mo ago
I think we all have tbh
Teixeira
Teixeira3mo ago
Last time I had a similar "mystery" issue not deleting tsconfig.tsbuildinfo was the culprit Deleted node_modules, reinstalled dependencies, deleted dist and tsconfig.tsbuildinfo, re-built dist files, didn't resolve it though, logs:
2024-03-14 17:33:49 - INFO - Successfully logged in as "QOTD Bot" (1217468921607880764)
2024-03-14 17:33:49 - DEBUG - ApplicationCommandRegistry[quotes] Preparing to process 1 possible command registrations / updates...
2024-03-14 17:33:49 - DEBUG - ApplicationCommandRegistry[quotes] Checking if command "quotes" is identical with global chat input command with id "1217887517987180725"
2024-03-14 17:33:49 - DEBUG - ApplicationCommandRegistry[quotes] Registering id "1217887517987180725" to internal chat input map
2024-03-14 17:33:49 - DEBUG - ApplicationCommandRegistry[quotes] Took 2ms to process differences via fast compute differences
2024-03-14 17:33:49 - DEBUG - ApplicationCommandRegistry[quotes] Command "quotes" is identical to command "quotes" (1217887517987180725)
2024-03-14 17:33:49 - INFO - Successfully logged in as "QOTD Bot" (1217468921607880764)
2024-03-14 17:33:49 - DEBUG - ApplicationCommandRegistry[quotes] Preparing to process 1 possible command registrations / updates...
2024-03-14 17:33:49 - DEBUG - ApplicationCommandRegistry[quotes] Checking if command "quotes" is identical with global chat input command with id "1217887517987180725"
2024-03-14 17:33:49 - DEBUG - ApplicationCommandRegistry[quotes] Registering id "1217887517987180725" to internal chat input map
2024-03-14 17:33:49 - DEBUG - ApplicationCommandRegistry[quotes] Took 2ms to process differences via fast compute differences
2024-03-14 17:33:49 - DEBUG - ApplicationCommandRegistry[quotes] Command "quotes" is identical to command "quotes" (1217887517987180725)
Favna
Favna3mo ago
FWIW you can make it be written to dist so deleting the folder is all you need to do. compilerOptions.tsBuildInfoFile set it to sth like dist/tsbuildinfo.json
TSConfig Reference - Docs on every TSConfig option
From allowJs to useDefineForClassFields the TSConfig reference includes information about all of the active compiler flags setting up a TypeScript project.
Teixeira
Teixeira3mo ago
Just double-checking, this is the right import for the ApplicationCommandRegistries when calling its setDefaultGuildIds method right?
import { ApplicationCommandRegistries, ... } from '@sapphire/framework';
import { ApplicationCommandRegistries, ... } from '@sapphire/framework';
Favna
Favna3mo ago
Yez
Teixeira
Teixeira3mo ago
Didn't know this, awesome Out of curiosity any particular reason why this option isn't set on @sapphire/ts-config?
vladdy
vladdy3mo ago
different outdirs can be provided and that'd break
Teixeira
Teixeira3mo ago
Ah of course makes sense
Favna
Favna3mo ago
I'm a bit stuck on your problem tbh. I'd have to review the sapphire code to give proper guidance but doing so from mobile is a big no. Way too PITA.
vladdy
vladdy3mo ago
can you log what your this._environment.GUILD_IDS.split(',') returns?
Teixeira
Teixeira3mo ago
const guildIds = this._environment.GUILD_IDS.split(',');
this.logger.debug(guildIds);
ApplicationCommandRegistries.setDefaultGuildIds(guildIds);
await this.client.login(this._environment.DISCORD_TOKEN);
const guildIds = this._environment.GUILD_IDS.split(',');
this.logger.debug(guildIds);
ApplicationCommandRegistries.setDefaultGuildIds(guildIds);
await this.client.login(this._environment.DISCORD_TOKEN);
2024-03-14 17:42:23 - DEBUG - [ '1217485244840677546' ]
2024-03-14 17:42:23 - DEBUG - [ '1217485244840677546' ]
vladdy
vladdy3mo ago
huh
Teixeira
Teixeira3mo ago
Could it have anything to do with the fact the command in question extends the Subcommand class from @sapphire/plugin-subcommands@6.0.3 instead of the "normal" Command one? I haven't tried it with a "normal" one yet will do that and see if it persists
vladdy
vladdy3mo ago
nah, shouldn't matter
Teixeira
Teixeira3mo ago
I just tried it and it works as expected with normal commands
import { Command } from '@sapphire/framework';

/**
* TODO
*/
export class TestCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
super(context, { ...options });
}

/**
* Registers this slash command.
*
* @param registry - The {@link Command.Registry} instance associated with this command.
*/
public override registerApplicationCommands(registry: Command.Registry) {
registry.registerChatInputCommand(
(builder) =>
builder
.setName('test') //
.setDescription('TBD')
);
}

/**
* Handler for executions of this command.
*
* @param interaction - The {@link Command.ChatInputCommandInteraction} object received.
*/
public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) {
// TODO
}
}
import { Command } from '@sapphire/framework';

/**
* TODO
*/
export class TestCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
super(context, { ...options });
}

/**
* Registers this slash command.
*
* @param registry - The {@link Command.Registry} instance associated with this command.
*/
public override registerApplicationCommands(registry: Command.Registry) {
registry.registerChatInputCommand(
(builder) =>
builder
.setName('test') //
.setDescription('TBD')
);
}

/**
* Handler for executions of this command.
*
* @param interaction - The {@link Command.ChatInputCommandInteraction} object received.
*/
public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) {
// TODO
}
}
When ApplicationCommandRegistries.setDefaultGuildIds(guildIds); is set it registers it in the specified guild, and when it is not set it registers it globally, as it should work
vladdy
vladdy3mo ago
strange
Favna
Favna3mo ago
Strange indeed. The registry shouldn't care if it's a subcommand or not Maybe we have an instanceof... No it extends I won't have time before then
Teixeira
Teixeira3mo ago
Here's the uncut command that extends Subcommand instead of Command (doesn't fit on a Discord message): https://pastebin.com/c8dkpBbs Just in case I'm accidentally doing something that causes this issue
Pastebin
import { Subcommand } from '@sapphire/plugin-subcommands';import { ...
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
Teryl
Teryl3mo ago
On <t:1710443064>, @Favna asked me to remind you of this:
debug this issue
Favna
Favna3mo ago
okay I can definitely confirm this is an issue and only with subcommands @vladdy
Favna
Favna3mo ago
No description
No description
Favna
Favna3mo ago
apiCalls just before https://github.com/sapphiredev/framework/blob/main/src/lib/utils/application-commands/ApplicationCommandRegistries.ts#L81 (this is before the global config is read)
[
{
builtData: {
options: [
{
type: 1,
name: "add",
name_localizations: undefined,
description: "Add quotes to the list.",
description_localizations: undefined,
options: [
],
},
{
type: 1,
name: "remove",
name_localizations: undefined,
description: "Remove a quote from the list.",
description_localizations: undefined,
options: [
{
choices: undefined,
autocomplete: undefined,
type: 3,
name: "quote",
name_localizations: undefined,
description: "The quote to remove.",
description_localizations: undefined,
required: true,
max_length: undefined,
min_length: 1,
},
],
},
],
name: "quotes",
name_localizations: undefined,
description: "Manages the list of quotes.",
description_localizations: undefined,
default_permission: undefined,
default_member_permissions: "0",
dm_permission: true,
nsfw: undefined,
type: 1,
},
registerOptions: {
},
type: 0,
},
]
[
{
builtData: {
options: [
{
type: 1,
name: "add",
name_localizations: undefined,
description: "Add quotes to the list.",
description_localizations: undefined,
options: [
],
},
{
type: 1,
name: "remove",
name_localizations: undefined,
description: "Remove a quote from the list.",
description_localizations: undefined,
options: [
{
choices: undefined,
autocomplete: undefined,
type: 3,
name: "quote",
name_localizations: undefined,
description: "The quote to remove.",
description_localizations: undefined,
required: true,
max_length: undefined,
min_length: 1,
},
],
},
],
name: "quotes",
name_localizations: undefined,
description: "Manages the list of quotes.",
description_localizations: undefined,
default_permission: undefined,
default_member_permissions: "0",
dm_permission: true,
nsfw: undefined,
type: 1,
},
registerOptions: {
},
type: 0,
},
]
vladdy
vladdy3mo ago
Uh Can you remind me what's the expected result? @Favna Also I'm surprised this is happening
Favna
Favna3mo ago
the subcommand to register in the guild and not globally
vladdy
vladdy3mo ago
Oh fascinating and yet registerOptions is empty Does this happen only in bulk overwrite?
Favna
Favna3mo ago
No description
Favna
Favna3mo ago
no, @Teixeira initially didnt use it you may want to scroll up to refresh your memory
vladdy
vladdy3mo ago
Oh wait this means something is wrong in the register methods and what they do
Favna
Favna3mo ago
I think I see why it happens
vladdy
vladdy3mo ago
Oh?
Favna
Favna3mo ago
if the user provides idHints or otherwise an empty object (or other options) then the guildIds dont get set because of ?? https://github.com/sapphiredev/framework/blob/af4115af8e179e9ffb349825901dd2ef88178b63/src/lib/utils/application-commands/ApplicationCommandRegistry.ts#L113-L117
vladdy
vladdy3mo ago
Yeah i just checked the code I guess we just want to spread the options object in our defaulted object That'll definitely fix it and keep most expected behaviors That is such a sneaky edge case, I'm genuinely impressed we didn't encounter this sooner
Favna
Favna3mo ago
wait fixed I mixed up the order of the spread slow @vladdy you submitted the review after I already committed the fix
vladdy
vladdy3mo ago
I'm on a phone, sue me
Favna
Favna3mo ago
I will
vladdy
vladdy3mo ago
Lets get this out
Favna
Favna3mo ago
unlike a certain American I'm not across an ocean
vladdy
vladdy3mo ago
Lmao you're still across borders Anyways yeah merge and lets release it too
Favna
Favna3mo ago
ye kinda curious if the sonarqube bot is gonna comment on the PR... I think it should
Teixeira
Teixeira3mo ago
Yep I can confirm I was using idHints
vladdy
vladdy3mo ago
Nice catch
Favna
Favna3mo ago
doesnt look like it does. Sadge.
vladdy
vladdy3mo ago
Well have fun debugging that too 😂
Favna
Favna3mo ago
meh not something that can be debugged. I thought that was a sonarqube feature but I may have just misread the docs
vladdy
vladdy3mo ago
Can you trigger a release too? 💙
Teixeira
Teixeira3mo ago
So I'll have to wait for the update to be pushed to sapphire and then I can npm update my version and should be good to go?
vladdy
vladdy3mo ago
Yap
Teixeira
Teixeira3mo ago
Okay thank you both for the help!
vladdy
vladdy3mo ago
But poke us if tye update didn't work
Favna
Favna3mo ago
No description
vladdy
vladdy3mo ago
Oh neat yarn supports that too?
Favna
Favna3mo ago
I think npm does a callback of sorts because I get that with npm deprecate, with yarn npm publish it gives a token to copy to terminal
Teixeira
Teixeira3mo ago
One last thing, should I mark any of the messages here as the solution, to @Answer Overflow? Feels like I shouldn't but not sure
Favna
Favna3mo ago
probably just the one with the link to the PR anyway released
Teixeira
Teixeira3mo ago
After updating the package I'm getting a TS error:
node_modules/@sapphire/framework/dist/esm/index.d.mts:1:22 - error TS2307: Cannot find module 'src' or its corresponding type declarations.

1 import * as src from 'src';
node_modules/@sapphire/framework/dist/esm/index.d.mts:1:22 - error TS2307: Cannot find module 'src' or its corresponding type declarations.

1 import * as src from 'src';
I ran npm update @sapphire/framework
Favna
Favna3mo ago
yeah I know tsup fucked something up im looking into it fixed @Teixeira
Teixeira
Teixeira3mo ago
Thank you!