Duck
Duck
SIASapphire - Imagine a framework
Created by Duck on 12/16/2023 in #discordjs-support
Encountered error while handling an interaction handler run method for interaction-handler
Been trying to debug an interaction error and haven't been able to figure out why it's erroring. There isn't a single method on the interaction which is allowing me to edit a reply or send a new one and I am confused. The code I am using is code I'm using on other interactions and it works perfectly fine, so I'm confused. GroupButton.ts button for groups
public run(interaction: ButtonInteraction) {
// If the group is undefined then we should not run
if (!this.group) return;

// We can now run the command
return replyWithCommands(interaction, this.group.name);
}
public run(interaction: ButtonInteraction) {
// If the group is undefined then we should not run
if (!this.group) return;

// We can now run the command
return replyWithCommands(interaction, this.group.name);
}
replyToInteraction.ts Interaction util for my help command
export async function replyWithCommands(
interaction: ChatInputCommandInteraction | MessageComponentInteraction,
groupName: string
) {
await autoDeferReply(interaction);

// Check the group exists
const group = await getGroup(interaction.client, interaction, groupName);
if (!group) {
return sendDeferredEphermeralResponse(interaction, {
content: `The group \`${groupName}\` does not exist.`,
});
}

// Get all the commands for the group
const commands = await getCommandsForGroup(
interaction.client,
interaction,
group.name
);

// Create a button for going back to the groups
const backButton = new ButtonBuilder() //
.setCustomId(GroupButtonIDs.BackToGroup)
.setEmoji(":back:")
.setStyle(ButtonStyle.Primary);

// Add the button to a action row
const row = new ActionRowBuilder<ButtonBuilder>();
row.addComponents(backButton);

// Embed builder
const embed = new EmbedBuilder() //
.setColor(0x2095ab)
.setAuthor({
name: interaction.user.username,
iconURL: interaction.user.displayAvatarURL(),
})
.addFields([
{
name: "Information",
value: `Click on the 🔙 button to go back to the groups.`,
},
{
name: `${group.name} Commands`,
value:
commands
.map(
(command) =>
`\`/${command.name}\` ${command.description}`
)
.join("\n") || "No commands found",
},
]);

return sendDeferredResponse(interaction, {
embeds: [embed],
components: [row],
});
}
export async function replyWithCommands(
interaction: ChatInputCommandInteraction | MessageComponentInteraction,
groupName: string
) {
await autoDeferReply(interaction);

// Check the group exists
const group = await getGroup(interaction.client, interaction, groupName);
if (!group) {
return sendDeferredEphermeralResponse(interaction, {
content: `The group \`${groupName}\` does not exist.`,
});
}

// Get all the commands for the group
const commands = await getCommandsForGroup(
interaction.client,
interaction,
group.name
);

// Create a button for going back to the groups
const backButton = new ButtonBuilder() //
.setCustomId(GroupButtonIDs.BackToGroup)
.setEmoji(":back:")
.setStyle(ButtonStyle.Primary);

// Add the button to a action row
const row = new ActionRowBuilder<ButtonBuilder>();
row.addComponents(backButton);

// Embed builder
const embed = new EmbedBuilder() //
.setColor(0x2095ab)
.setAuthor({
name: interaction.user.username,
iconURL: interaction.user.displayAvatarURL(),
})
.addFields([
{
name: "Information",
value: `Click on the 🔙 button to go back to the groups.`,
},
{
name: `${group.name} Commands`,
value:
commands
.map(
(command) =>
`\`/${command.name}\` ${command.description}`
)
.join("\n") || "No commands found",
},
]);

return sendDeferredResponse(interaction, {
embeds: [embed],
components: [row],
});
}
interactionReplyUtil General utils for interactions
/**
* This util will defer the reply only when it is able to.
*
* @param interaction
*/
export async function autoDeferReply(
interaction: ChatInputCommandInteraction | MessageComponentInteraction
) {
const fromMessageComponent = isMessageComponentInteraction(interaction);
// Defer the interaction if it hasn't already been (command interaction)
if (
!fromMessageComponent &&
!interaction.deferred &&
!interaction.replied
) {
await interaction.deferReply();
}
}

export async function sendDeferredResponse(
interaction: ChatInputCommandInteraction | MessageComponentInteraction,
options?: BaseMessageOptions
): Promise<InteractionResponse<boolean> | Message<boolean>> {
const { content, embeds, components } = options ?? {};
// Response to the interaction
const responseObj: BaseMessageOptions = {
content: content ?? "",
embeds,
components,
};
const fromMessageComponent = isMessageComponentInteraction(interaction);
// A button interaction cause this function to be called
if (fromMessageComponent && !interaction.replied) {
return interaction.update(responseObj);
}
// A command interaction cause this function to be called
return interaction.editReply(responseObj);
}
/**
* This util will defer the reply only when it is able to.
*
* @param interaction
*/
export async function autoDeferReply(
interaction: ChatInputCommandInteraction | MessageComponentInteraction
) {
const fromMessageComponent = isMessageComponentInteraction(interaction);
// Defer the interaction if it hasn't already been (command interaction)
if (
!fromMessageComponent &&
!interaction.deferred &&
!interaction.replied
) {
await interaction.deferReply();
}
}

export async function sendDeferredResponse(
interaction: ChatInputCommandInteraction | MessageComponentInteraction,
options?: BaseMessageOptions
): Promise<InteractionResponse<boolean> | Message<boolean>> {
const { content, embeds, components } = options ?? {};
// Response to the interaction
const responseObj: BaseMessageOptions = {
content: content ?? "",
embeds,
components,
};
const fromMessageComponent = isMessageComponentInteraction(interaction);
// A button interaction cause this function to be called
if (fromMessageComponent && !interaction.replied) {
return interaction.update(responseObj);
}
// A command interaction cause this function to be called
return interaction.editReply(responseObj);
}
9 replies
SIASapphire - Imagine a framework
Created by Duck on 4/7/2023 in #sapphire-support
TypeError: Cannot read properties of undefined (reading 'write')
\testing-forbidden\node_modules\@sapphire\framework\dist\lib\utils\logger\Logger.js:27
this.write(ILogger_js.LogLevel.Error, ...values);
^

TypeError: Cannot read properties of undefined (reading 'write')
at error (\testing-forbidden\node_modules\@sapphire\framework\dist\lib\utils\logger\Logger.js:27:10)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

Node.js v18.14.1
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
\testing-forbidden\node_modules\@sapphire\framework\dist\lib\utils\logger\Logger.js:27
this.write(ILogger_js.LogLevel.Error, ...values);
^

TypeError: Cannot read properties of undefined (reading 'write')
at error (\testing-forbidden\node_modules\@sapphire\framework\dist\lib\utils\logger\Logger.js:27:10)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

Node.js v18.14.1
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
I am using @sapphire/plugin-logger. I am building a provider to my database that currently uses the logging methods, I assumed it was because the client hadn't logged in yet so I moved my provider instantiation to the ReadyListener. This is my ReadyListener at the moment
import { Listener } from "@sapphire/framework";
import type { Client } from "discord.js";

import { MongoProvider } from "../provider/MongoProvider";
import * as Schemas from "../provider/schemas";

export class ReadyListener extends Listener {
public constructor(context: Listener.Context, options: Listener.Options) {
super(context, {
...options,
event: "ready",
once: true,
});
}

public run(bot: Client) {
if (!bot.user) {
this.container.logger.error(
"Ready: Bot has initialised with no user"
);
return;
}
this.container.logger.info(
`Ready: Bot has initialised as ${bot.user.tag} (${bot.user.id})`
);

// Setup theprovider
bot.provider = new MongoProvider(
{
hostname: process.env.DB_HOSTNAME,
port: process.env.DB_PORT,
auth: {
username: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
},
},
{ guilds: Schemas.GuildSchema }
);

// Test the that the insert document method works
bot.provider.waitForConnection(() => {
bot.provider.insertDocument("guilds", {
guildID: "1",
prefix: "!",
});
});
}
}
import { Listener } from "@sapphire/framework";
import type { Client } from "discord.js";

import { MongoProvider } from "../provider/MongoProvider";
import * as Schemas from "../provider/schemas";

export class ReadyListener extends Listener {
public constructor(context: Listener.Context, options: Listener.Options) {
super(context, {
...options,
event: "ready",
once: true,
});
}

public run(bot: Client) {
if (!bot.user) {
this.container.logger.error(
"Ready: Bot has initialised with no user"
);
return;
}
this.container.logger.info(
`Ready: Bot has initialised as ${bot.user.tag} (${bot.user.id})`
);

// Setup theprovider
bot.provider = new MongoProvider(
{
hostname: process.env.DB_HOSTNAME,
port: process.env.DB_PORT,
auth: {
username: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
},
},
{ guilds: Schemas.GuildSchema }
);

// Test the that the insert document method works
bot.provider.waitForConnection(() => {
bot.provider.insertDocument("guilds", {
guildID: "1",
prefix: "!",
});
});
}
}
I can also confirm that the logger is functioning before the error
2023-04-07 22:53:02 - INFO - ApplicationCommandRegistries: Initializing...
2023-04-07 22:53:02 - INFO - Ready: Bot has initialised as testing-forbidden#5339 (1091541627056689242)
2023-04-07 22:53:02 - INFO - MongoProvider: Attempting to connect to the database...
2023-04-07 22:53:02 - INFO - MongoProvider: Connected to database. Initialising provider...
2023-04-07 22:53:02 - INFO - MongoProvider: Provider initialised.
2023-04-07 22:53:02 - INFO - ApplicationCommandRegistries: Initializing...
2023-04-07 22:53:02 - INFO - Ready: Bot has initialised as testing-forbidden#5339 (1091541627056689242)
2023-04-07 22:53:02 - INFO - MongoProvider: Attempting to connect to the database...
2023-04-07 22:53:02 - INFO - MongoProvider: Connected to database. Initialising provider...
2023-04-07 22:53:02 - INFO - MongoProvider: Provider initialised.
10 replies