./Ticker
./Ticker
SIASapphire - Imagine a framework
Created by ./Ticker on 6/14/2024 in #sapphire-support
Coommands are not registered
No description
7 replies
SIASapphire - Imagine a framework
Created by ./Ticker on 6/8/2024 in #sapphire-support
Is there a way to make slash commands hidden for people with lower perms?
I know this is possible for a guild only server, how do I do it with Sapphire?
5 replies
SIASapphire - Imagine a framework
Created by ./Ticker on 5/6/2024 in #discordjs-support
Question about developing in TypeScript
My bot which is used by 10,000 members is fully written in Sapphire for JavaScript. I was thinking about converting it to TypeScript to make the code better, and safer. I wanted to ask, from your experience, does using TypeScript make a difference in how you code? does it make a difference in the performance? Is it worth it? Cheers!
8 replies
SIASapphire - Imagine a framework
Created by ./Ticker on 3/30/2024 in #discordjs-support
Button error
anybody knows why this is happening? So I have a ticketing system that just stopped working now, for some ungodly reason, closing the ticket takes ages, it will not close it and then error out.
2024-03-30 20:58:07 - ERROR - Encountered error while handling an interaction handler run method for interaction-handler "ticketClose" at path "/home/container/src/interaction-handlers/ticket/ticketClose.js" TypeError: Cannot read properties of null (reading 'delete')
2024-03-30 20:58:07 - ERROR - Encountered error while handling an interaction handler run method for interaction-handler "ticketClose" at path "/home/container/src/interaction-handlers/ticket/ticketClose.js" TypeError: Cannot read properties of null (reading 'delete')
Code:
interaction.reply({ content: "Closing..." })
const ticketChannel = interaction.channel;
const ticketOwnerId = ticketChannel.topic;
const ticketOwner = await this.container.client.users.fetch(ticketOwnerId);
const logs = interaction.guild.channels.cache.get(config.ticket_logs);
const attachment = await createTranscript(ticketChannel, {
limit: -1,
returnBuffer: false,
fileName: `${ticketChannel.name}.html`,
poweredBy: "Ticker Bots"
})
let summary = {};
ticketChannel.messages.cache.map(message => {
if (summary.hasOwnProperty(message.author.id))
summary[message.author.id].number++;
else
summary[message.author.id] = { number: 0, user: message.author };
});
let amount = "";
for (let user in summary) {
amount += `\`${summary[user].number + 1}\` - ${summary[user].user.tag}\n(${summary[user].user.id})\n`;
}

let key = Object.keys(summary).sort((a, b) => summary[b].number - summary[a].number)[0];
const logEmbed = new EmbedBuilder()
.setColor('Random')
.setTitle(`Ticket Closed`)
.addFields({ name: `Ticket Name:`, value: `**\`${ticketChannel.name}\`(${ticketChannel})**`, inline: false })
.addFields({ name: `Ticket Owner:`, value: `**\`${ticketOwner.username}#${ticketOwner.discriminator}\`(${ticketOwner})**`, inline: false })
.addFields({ name: `Closed By:`, value: `**\`${interaction.user.username}#${interaction.user.discriminator}\`(${interaction.user})**`, inline: false })
.addFields({ name: `Opened At:`, value: `**<t:${parseInt(ticketChannel.createdTimestamp / 1000)}:d>, <t:${parseInt(ticketChannel.createdTimestamp / 1000)}:T>\n<t:${parseInt(ticketChannel.createdTimestamp / 1000)}:R>**`, inline: false })
.addFields({ name: `Closed At:`, value: `**<t:${parseInt(Date.now() / 1000)}:d>, <t:${parseInt(Date.now() / 1000)}:T>\n<t:${parseInt(Date.now() / 1000)}:R>**`, inline: false })
.addFields({ name: `Users In ticket:`, value: `**${amount}**`, inline: false })
.addFields({ name: `Most Active:`, value: `**${summary[key].user.tag}\(${summary[key].user})**`, inline: true })
.setTimestamp();
await logs.send({ embeds: [logEmbed], files: [attachment] });
await interaction.channel.delete();
interaction.reply({ content: "Closing..." })
const ticketChannel = interaction.channel;
const ticketOwnerId = ticketChannel.topic;
const ticketOwner = await this.container.client.users.fetch(ticketOwnerId);
const logs = interaction.guild.channels.cache.get(config.ticket_logs);
const attachment = await createTranscript(ticketChannel, {
limit: -1,
returnBuffer: false,
fileName: `${ticketChannel.name}.html`,
poweredBy: "Ticker Bots"
})
let summary = {};
ticketChannel.messages.cache.map(message => {
if (summary.hasOwnProperty(message.author.id))
summary[message.author.id].number++;
else
summary[message.author.id] = { number: 0, user: message.author };
});
let amount = "";
for (let user in summary) {
amount += `\`${summary[user].number + 1}\` - ${summary[user].user.tag}\n(${summary[user].user.id})\n`;
}

let key = Object.keys(summary).sort((a, b) => summary[b].number - summary[a].number)[0];
const logEmbed = new EmbedBuilder()
.setColor('Random')
.setTitle(`Ticket Closed`)
.addFields({ name: `Ticket Name:`, value: `**\`${ticketChannel.name}\`(${ticketChannel})**`, inline: false })
.addFields({ name: `Ticket Owner:`, value: `**\`${ticketOwner.username}#${ticketOwner.discriminator}\`(${ticketOwner})**`, inline: false })
.addFields({ name: `Closed By:`, value: `**\`${interaction.user.username}#${interaction.user.discriminator}\`(${interaction.user})**`, inline: false })
.addFields({ name: `Opened At:`, value: `**<t:${parseInt(ticketChannel.createdTimestamp / 1000)}:d>, <t:${parseInt(ticketChannel.createdTimestamp / 1000)}:T>\n<t:${parseInt(ticketChannel.createdTimestamp / 1000)}:R>**`, inline: false })
.addFields({ name: `Closed At:`, value: `**<t:${parseInt(Date.now() / 1000)}:d>, <t:${parseInt(Date.now() / 1000)}:T>\n<t:${parseInt(Date.now() / 1000)}:R>**`, inline: false })
.addFields({ name: `Users In ticket:`, value: `**${amount}**`, inline: false })
.addFields({ name: `Most Active:`, value: `**${summary[key].user.tag}\(${summary[key].user})**`, inline: true })
.setTimestamp();
await logs.send({ embeds: [logEmbed], files: [attachment] });
await interaction.channel.delete();
3 replies
SIASapphire - Imagine a framework
Created by ./Ticker on 3/23/2024 in #sapphire-support
Scheduled Tasks with Common JS
I am looking to do a task every 2 minutes, I want to use scheduled tasks but seems like all the examples are in Typescript/ESM, can anyone show or explain how to use it with CommonJS?
7 replies
SIASapphire - Imagine a framework
Created by ./Ticker on 3/17/2024 in #sapphire-support
Is there a way to make precondition in interaction be ephemeral?
cause with the OwnerOnly the CLI gives it throws the error in a regular reply.
14 replies
SIASapphire - Imagine a framework
Created by ./Ticker on 3/16/2024 in #discordjs-support
Bot not starting in VPS
No description
5 replies
SIASapphire - Imagine a framework
Created by ./Ticker on 3/8/2024 in #sapphire-support
Paginated Message Bug
DiscordAPIError[40060]: Interaction has already been acknowledged.
at handleErrors (D:\bots\scully\node_modules\@discordjs\rest\dist\index.js:722:13)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async BurstHandler.runRequest (D:\bots\scully\node_modules\@discordjs\rest\dist\index.js:826:23)
at async _REST.request (D:\bots\scully\node_modules\@discordjs\rest\dist\index.js:1266:22)
at async ButtonInteraction.update (D:\bots\scully\node_modules\discord.js\src\structures\interfaces\InteractionResponses.js:233:5)
at async safelyReplyToInteraction (D:\bots\scully\node_modules\@sapphire\discord.js-utilities\dist\cjs\index.cjs:675:7)
at async _PaginatedMessage.handleCollect (D:\bots\scully\node_modules\@sapphire\discord.js-utilities\dist\cjs\index.cjs:1741:11) {
requestBody: {
files: [],
json: {
type: 7,
data: {
content: 'This is the second page',
tts: false,
nonce: undefined,
embeds: [
{
title: undefined,
description: undefined,
url: undefined,
timestamp: '2024-03-08T02:49:43.491Z',
color: 16711680,
fields: undefined,
author: undefined,
thumbnail: undefined,
image: undefined,
video: undefined,
footer: [Object]
}
],
components: [
{ type: 1, components: [Array] },
{ type: 1, components: [Array] }
],
username: undefined,
avatar_url: undefined,
allowed_mentions: undefined,
flags: undefined,
message_reference: undefined,
attachments: undefined,
sticker_ids: undefined,
thread_name: undefined
}
}
},
rawError: {
message: 'Interaction has already been acknowledged.',
code: 40060
},
code: 40060,
status: 400,
method: 'POST',
url: 'https://discord.com/api/v10/interactions/1215491616278716497/aW50ZXJhY3Rpb246MTIxNTQ5MTYxNjI3ODcxNjQ5Nzoxd1pNZjRJaWFKeHI0cElGR0NaMHlaNnBQSHB4aVhPZjRNTmIxUnh0eDBJNHdkb2lIODVadklJeENhV2hpRHBqSGdza1B5NlVWZEVLNkRkOU9sM2FuU1d1RFhSRFhpTmJic2g0WUp2eHRreG81alBCQmpyN1RLMzk1aWU2Qk9kWg/callback'
}
DiscordAPIError[40060]: Interaction has already been acknowledged.
at handleErrors (D:\bots\scully\node_modules\@discordjs\rest\dist\index.js:722:13)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async BurstHandler.runRequest (D:\bots\scully\node_modules\@discordjs\rest\dist\index.js:826:23)
at async _REST.request (D:\bots\scully\node_modules\@discordjs\rest\dist\index.js:1266:22)
at async ButtonInteraction.update (D:\bots\scully\node_modules\discord.js\src\structures\interfaces\InteractionResponses.js:233:5)
at async safelyReplyToInteraction (D:\bots\scully\node_modules\@sapphire\discord.js-utilities\dist\cjs\index.cjs:675:7)
at async _PaginatedMessage.handleCollect (D:\bots\scully\node_modules\@sapphire\discord.js-utilities\dist\cjs\index.cjs:1741:11) {
requestBody: {
files: [],
json: {
type: 7,
data: {
content: 'This is the second page',
tts: false,
nonce: undefined,
embeds: [
{
title: undefined,
description: undefined,
url: undefined,
timestamp: '2024-03-08T02:49:43.491Z',
color: 16711680,
fields: undefined,
author: undefined,
thumbnail: undefined,
image: undefined,
video: undefined,
footer: [Object]
}
],
components: [
{ type: 1, components: [Array] },
{ type: 1, components: [Array] }
],
username: undefined,
avatar_url: undefined,
allowed_mentions: undefined,
flags: undefined,
message_reference: undefined,
attachments: undefined,
sticker_ids: undefined,
thread_name: undefined
}
}
},
rawError: {
message: 'Interaction has already been acknowledged.',
code: 40060
},
code: 40060,
status: 400,
method: 'POST',
url: 'https://discord.com/api/v10/interactions/1215491616278716497/aW50ZXJhY3Rpb246MTIxNTQ5MTYxNjI3ODcxNjQ5Nzoxd1pNZjRJaWFKeHI0cElGR0NaMHlaNnBQSHB4aVhPZjRNTmIxUnh0eDBJNHdkb2lIODVadklJeENhV2hpRHBqSGdza1B5NlVWZEVLNkRkOU9sM2FuU1d1RFhSRFhpTmJic2g0WUp2eHRreG81alBCQmpyN1RLMzk1aWU2Qk9kWg/callback'
}
Default paginated message code:
const { PaginatedMessage } = require('@sapphire/discord.js-utilities');
const { Command } = require('@sapphire/framework');
const { EmbedBuilder } = require('discord.js');
const { sendLoadingMessage } = require('../../lib/utils');

class UserCommand extends Command {
constructor(context, options) {
super(context, {
...options,
aliases: ['pm'],
description: 'A command that uses paginated messages.',
generateDashLessAliases: true
});
}

async messageRun(message) {
const response = await sendLoadingMessage(message);

const paginatedMessage = new PaginatedMessage({
template: new EmbedBuilder()
.setColor('#FF0000')
// Be sure to add a space so this is offset from the page numbers!
.setFooter({ text: ' footer after page numbers' })
});

paginatedMessage
.addPageEmbed((embed) =>
embed //
.setDescription('This is the first page')
.setTitle('Page 1')
)
.addPageBuilder((builder) =>
builder //
.setContent('This is the second page')
.setEmbeds([new EmbedBuilder().setTimestamp()])
);

await paginatedMessage.run(response, message.author);
return response;
}
}

module.exports = {
UserCommand
};
const { PaginatedMessage } = require('@sapphire/discord.js-utilities');
const { Command } = require('@sapphire/framework');
const { EmbedBuilder } = require('discord.js');
const { sendLoadingMessage } = require('../../lib/utils');

class UserCommand extends Command {
constructor(context, options) {
super(context, {
...options,
aliases: ['pm'],
description: 'A command that uses paginated messages.',
generateDashLessAliases: true
});
}

async messageRun(message) {
const response = await sendLoadingMessage(message);

const paginatedMessage = new PaginatedMessage({
template: new EmbedBuilder()
.setColor('#FF0000')
// Be sure to add a space so this is offset from the page numbers!
.setFooter({ text: ' footer after page numbers' })
});

paginatedMessage
.addPageEmbed((embed) =>
embed //
.setDescription('This is the first page')
.setTitle('Page 1')
)
.addPageBuilder((builder) =>
builder //
.setContent('This is the second page')
.setEmbeds([new EmbedBuilder().setTimestamp()])
);

await paginatedMessage.run(response, message.author);
return response;
}
}

module.exports = {
UserCommand
};
23 replies
SIASapphire - Imagine a framework
Created by ./Ticker on 2/19/2024 in #sapphire-support
Cannot find module
No description
8 replies
SIASapphire - Imagine a framework
Created by ./Ticker on 1/5/2024 in #sapphire-support
How to use @sapphire/decorators?
I tried using it but am getting this error: Unable to resolve signature of class decorator when called as an expression. The runtime will invoke the decorator with 2 arguments, but the decorator expects 1. import { ApplyOptions } from '@sapphire/decorators'; import { Command, CommandOptions } from '@sapphire/framework'; import { Message, TextChannel } from 'discord.js'; import { addHelpRequestToDatabase } from '../database_handler'; import { mainChatId, logChannelId } from '../config'; @ApplyOptions <Command.Options>({ description: 'ping pong', enabled: true })
4 replies
SIASapphire - Imagine a framework
Created by ./Ticker on 1/1/2024 in #discordjs-support
anyone know how to make bot seem without a status (not online but not offline)
like for @Iriss
7 replies