Updated to discord.js v13 preview

This commit is contained in:
WatDuhHekBro 2021-05-17 17:12:14 -05:00 committed by Alyxia Sother
parent 8ffbc367b1
commit 36bc488757
No known key found for this signature in database
GPG Key ID: 355968D14144B739
17 changed files with 148 additions and 80 deletions

67
package-lock.json generated
View File

@ -12,7 +12,7 @@
"dependencies": {
"canvas": "^2.7.0",
"chalk": "^4.1.0",
"discord.js": "^12.5.1",
"discord.js": "github:discordjs/discord.js",
"discord.js-lavalink-lib": "^0.1.8",
"figlet": "^1.5.0",
"glob": "^7.1.6",
@ -20,7 +20,7 @@
"mathjs": "^9.3.0",
"moment": "^2.29.1",
"ms": "^2.1.3",
"onion-lasers": "^1.1.2",
"onion-lasers": "^1.2.0-unstable.0",
"pet-pet-gif": "^1.0.8",
"relevant-urban": "^2.0.0",
"translate-google": "^1.4.3",
@ -41,7 +41,7 @@
"rimraf": "^3.0.2",
"ts-jest": "^26.4.4",
"tsc-watch": "^4.2.9",
"typescript": "^3.9.7"
"typescript": "^4.2.4"
},
"optionalDependencies": {
"fsevents": "^2.1.2"
@ -2348,21 +2348,20 @@
}
},
"node_modules/discord.js": {
"version": "12.5.3",
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.5.3.tgz",
"integrity": "sha512-D3nkOa/pCkNyn6jLZnAiJApw2N9XrIsXUAdThf01i7yrEuqUmDGc7/CexVWwEcgbQR97XQ+mcnqJpmJ/92B4Aw==",
"version": "12.5.0",
"resolved": "git+ssh://git@github.com/discordjs/discord.js.git#ab82cafcde0ee259a32ef14303c1b4a64dea8fae",
"license": "Apache-2.0",
"dependencies": {
"@discordjs/collection": "^0.1.6",
"@discordjs/form-data": "^3.0.1",
"abort-controller": "^3.0.0",
"node-fetch": "^2.6.1",
"prism-media": "^1.2.9",
"setimmediate": "^1.0.5",
"prism-media": "^1.2.2",
"tweetnacl": "^1.0.3",
"ws": "^7.4.4"
"ws": "^7.3.1"
},
"engines": {
"node": ">=12.0.0"
"node": ">=14.0.0"
}
},
"node_modules/discord.js-lavalink-lib": {
@ -5406,11 +5405,11 @@
}
},
"node_modules/onion-lasers": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/onion-lasers/-/onion-lasers-1.1.2.tgz",
"integrity": "sha512-gQHQCdcfDSLeWFFXMTBCy2PZR/n603B+Q2L3vTj+9T1CmJS7OfO7zoFM5QrTkOY4N5hESboOdJ8eRvPXQgdxDg==",
"version": "1.2.0-unstable.0",
"resolved": "https://registry.npmjs.org/onion-lasers/-/onion-lasers-1.2.0-unstable.0.tgz",
"integrity": "sha512-seKXo0CouLNNp2p/M0eORqQ56eJ6MNJe1dSXCI251we8OMJTI5+qRpzB1+OhR2/G4zRkNuWb2aXTUPYNsmVZrA==",
"dependencies": {
"discord.js": "^12.5.3",
"discord.js": "github:discordjs/discord.js",
"glob": "^7.1.6"
}
},
@ -6506,11 +6505,6 @@
"node": ">=0.10.0"
}
},
"node_modules/setimmediate": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
"integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
},
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@ -7466,9 +7460,9 @@
}
},
"node_modules/typescript": {
"version": "3.9.9",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz",
"integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==",
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz",
"integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
@ -9800,18 +9794,16 @@
"dev": true
},
"discord.js": {
"version": "12.5.3",
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.5.3.tgz",
"integrity": "sha512-D3nkOa/pCkNyn6jLZnAiJApw2N9XrIsXUAdThf01i7yrEuqUmDGc7/CexVWwEcgbQR97XQ+mcnqJpmJ/92B4Aw==",
"version": "git+ssh://git@github.com/discordjs/discord.js.git#ab82cafcde0ee259a32ef14303c1b4a64dea8fae",
"from": "discord.js@github:discordjs/discord.js",
"requires": {
"@discordjs/collection": "^0.1.6",
"@discordjs/form-data": "^3.0.1",
"abort-controller": "^3.0.0",
"node-fetch": "^2.6.1",
"prism-media": "^1.2.9",
"setimmediate": "^1.0.5",
"prism-media": "^1.2.2",
"tweetnacl": "^1.0.3",
"ws": "^7.4.4"
"ws": "^7.3.1"
}
},
"discord.js-lavalink-lib": {
@ -12190,11 +12182,11 @@
}
},
"onion-lasers": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/onion-lasers/-/onion-lasers-1.1.2.tgz",
"integrity": "sha512-gQHQCdcfDSLeWFFXMTBCy2PZR/n603B+Q2L3vTj+9T1CmJS7OfO7zoFM5QrTkOY4N5hESboOdJ8eRvPXQgdxDg==",
"version": "1.2.0-unstable.0",
"resolved": "https://registry.npmjs.org/onion-lasers/-/onion-lasers-1.2.0-unstable.0.tgz",
"integrity": "sha512-seKXo0CouLNNp2p/M0eORqQ56eJ6MNJe1dSXCI251we8OMJTI5+qRpzB1+OhR2/G4zRkNuWb2aXTUPYNsmVZrA==",
"requires": {
"discord.js": "^12.5.3",
"discord.js": "github:discordjs/discord.js",
"glob": "^7.1.6"
}
},
@ -13018,11 +13010,6 @@
}
}
},
"setimmediate": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
"integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
},
"shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@ -13778,9 +13765,9 @@
}
},
"typescript": {
"version": "3.9.9",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz",
"integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==",
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz",
"integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==",
"dev": true
},
"underscore": {

View File

@ -12,12 +12,12 @@
"dev-instance": "rimraf dist && tsc && node . dev",
"test": "jest",
"format": "prettier --write **/*",
"postinstall": "husky install"
"postinstall": "node patch.js && husky install"
},
"dependencies": {
"canvas": "^2.7.0",
"chalk": "^4.1.0",
"discord.js": "^12.5.1",
"discord.js": "github:discordjs/discord.js",
"discord.js-lavalink-lib": "^0.1.8",
"figlet": "^1.5.0",
"glob": "^7.1.6",
@ -25,7 +25,7 @@
"mathjs": "^9.3.0",
"moment": "^2.29.1",
"ms": "^2.1.3",
"onion-lasers": "^1.1.2",
"onion-lasers": "^1.2.0-unstable.0",
"pet-pet-gif": "^1.0.8",
"relevant-urban": "^2.0.0",
"translate-google": "^1.4.3",
@ -46,7 +46,7 @@
"rimraf": "^3.0.2",
"ts-jest": "^26.4.4",
"tsc-watch": "^4.2.9",
"typescript": "^3.9.7"
"typescript": "^4.2.4"
},
"optionalDependencies": {
"fsevents": "^2.1.2"

23
patch.js Normal file
View File

@ -0,0 +1,23 @@
// This is a nightmarishly bad way to handle module patches... but oh well, it's on the unstable branch for a reason.
const fs = require("fs");
const DECLARATION_FILE = "node_modules/discord.js/typings/index.d.ts";
fs.readFile(DECLARATION_FILE, "utf-8", (err, data) => {
if (err) console.error(err);
else {
const declaration = data.split(/\r?\n/);
// "discord-api-types/v8" is apparently not found so just ignore it to get the typings to work.
for (let i = 0; i < declaration.length; i++) {
const line = declaration[i];
if (line.includes("@ts-ignore")) {
break;
} else if (line.includes("discord-api-types/v8")) {
declaration.splice(i, 0, "// @ts-ignore");
fs.writeFile(DECLARATION_FILE, declaration.join("\n"), () => {});
break;
}
}
}
});

View File

@ -282,7 +282,7 @@ export default new NamedCommand({
const newName = combined;
if (!voiceChannel) return send("You are not in a voice channel.");
if (!guild!.me?.hasPermission(Permissions.FLAGS.MANAGE_CHANNELS))
if (!guild!.me?.permissions.has(Permissions.FLAGS.MANAGE_CHANNELS))
return send("I can't change channel names without the `Manage Channels` permission.");
guildStorage.channelNames[voiceChannel.id] = newName;
@ -332,6 +332,30 @@ export default new NamedCommand({
}
})
}),
purge: new NamedCommand({
description: "Purges the bot's own messages.",
permission: PERMISSIONS.BOT_SUPPORT,
channelType: CHANNEL_TYPE.GUILD,
async run({send, message, channel, guild, client}) {
// It's probably better to go through the bot's own messages instead of calling bulkDelete which requires MANAGE_MESSAGES.
if (guild!.me?.permissions.has(Permissions.FLAGS.MANAGE_MESSAGES)) {
message.delete();
const msgs = await channel.messages.fetch({
limit: 100
});
const travMessages = msgs.filter((m) => m.author.id === client.user?.id);
await send(`Found ${travMessages.size} messages to delete.`).then((m) => {
setTimeout(() => {
m.delete();
}, 5000);
});
await (channel as TextChannel).bulkDelete(travMessages);
} else {
send("This command must be executed in a guild where I have the `MANAGE_MESSAGES` permission.");
}
}
}),
clear: new NamedCommand({
description: "Clears a given amount of messages.",
usage: "<amount>",

View File

@ -9,7 +9,7 @@ export default new NamedCommand({
const voiceChannel = message.member?.voice.channel;
if (!voiceChannel) return send("You are not in a voice channel.");
if (!voiceChannel.guild.me?.hasPermission("MANAGE_CHANNELS"))
if (!voiceChannel.guild.me?.permissions.has("MANAGE_CHANNELS"))
return send("I am lacking the required permissions to perform this action.");
const prevName = voiceChannel.name;

View File

@ -196,12 +196,13 @@ async function getGuildInfo(guild: Guild, currentGuild: Guild | null) {
const iconURL = guild.iconURL({dynamic: true});
const embed = new MessageEmbed().setDescription(`**Guild information for __${guild.name}__**`).setColor("BLUE");
const displayRoles = !!(currentGuild && guild.id === currentGuild.id);
const owner = await guild.fetchOwner();
embed
.addField("General", [
`** Name:** ${guild.name}`,
`** ID:** ${guild.id}`,
`** Owner:** ${guild.owner?.user.tag} (${guild.ownerID})`,
`** Owner:** ${owner.user.tag} (${guild.ownerID})`,
`** Region:** ${regions[guild.region]}`,
`** Boost Tier:** ${guild.premiumTier ? `Tier ${guild.premiumTier}` : "None"}`,
`** Explicit Filter:** ${filterLevels[guild.explicitContentFilter]}`,

View File

@ -38,7 +38,9 @@ export default new NamedCommand({
let emotes = new Map<string, string>();
for (const emote of emoteCollection) {
emotes.set(emote.id, emote.name);
if (emote.name) {
emotes.set(emote.id, emote.name);
}
}
// The result will be sandbox.emotes because it'll be modified in-place.
@ -77,6 +79,7 @@ export default new NamedCommand({
async function displayEmoteList(emotes: GuildEmoji[], send: SendFunction, author: User) {
emotes.sort((a, b) => {
if (!a.name || !b.name) return 0;
const first = a.name.toLowerCase();
const second = b.name.toLowerCase();

View File

@ -51,9 +51,11 @@ function searchSimilarEmotes(query: string): GuildEmoji[] {
const emoteCandidates: {emote: GuildEmoji; dist: number}[] = [];
for (const emote of client.emojis.cache.values()) {
const dist = levenshtein(emote.name, query);
if (dist <= maxAcceptedDistance) {
emoteCandidates.push({emote, dist});
if (emote.name) {
const dist = levenshtein(emote.name, query);
if (dist <= maxAcceptedDistance) {
emoteCandidates.push({emote, dist});
}
}
}

View File

@ -47,7 +47,7 @@ export default new NamedCommand({
else send("Cannot send an empty message.");
}
if (guild!.me?.hasPermission(Permissions.FLAGS.MANAGE_MESSAGES)) message.delete();
if (guild!.me?.permissions.has(Permissions.FLAGS.MANAGE_MESSAGES)) message.delete();
}
})
});

View File

@ -24,7 +24,7 @@ export default new NamedCommand({
const stats: {
[id: string]: {
name: string;
name: string | null;
formatted: string;
users: number;
bots: number;

View File

@ -1,10 +1,10 @@
import "./modules/globals";
import {Client, Permissions} from "discord.js";
import {Client, Permissions, Intents} from "discord.js";
import path from "path";
// This is here in order to make it much less of a headache to access the client from other files.
// This of course won't actually do anything until the setup process is complete and it logs in.
export const client = new Client();
export const client = new Client({intents: Intents.ALL});
import {launch} from "onion-lasers";
import setup from "./modules/setup";
@ -31,15 +31,15 @@ launch(client, path.join(__dirname, "commands"), {
name: "Moderator",
check: (_user, member) =>
!!member &&
(member.hasPermission(Permissions.FLAGS.MANAGE_ROLES) ||
member.hasPermission(Permissions.FLAGS.MANAGE_MESSAGES) ||
member.hasPermission(Permissions.FLAGS.KICK_MEMBERS) ||
member.hasPermission(Permissions.FLAGS.BAN_MEMBERS))
(member.permissions.has(Permissions.FLAGS.MANAGE_ROLES) ||
member.permissions.has(Permissions.FLAGS.MANAGE_MESSAGES) ||
member.permissions.has(Permissions.FLAGS.KICK_MEMBERS) ||
member.permissions.has(Permissions.FLAGS.BAN_MEMBERS))
},
{
// ADMIN //
name: "Administrator",
check: (_user, member) => !!member && member.hasPermission(Permissions.FLAGS.ADMINISTRATOR)
check: (_user, member) => !!member && member.permissions.has(Permissions.FLAGS.ADMINISTRATOR)
},
{
// OWNER //

View File

@ -10,7 +10,7 @@ client.on("voiceStateUpdate", async (before, after) => {
channel &&
channel.members.size === 0 &&
channel.id in channelNames &&
before.guild.me?.hasPermission(Permissions.FLAGS.MANAGE_CHANNELS)
before.guild.me?.permissions.has(Permissions.FLAGS.MANAGE_CHANNELS)
) {
channel.setName(channelNames[channel.id]);
}

View File

@ -2,17 +2,49 @@
// Like with logging each command invocation, it's not a good idea to pollute the logs with this kind of stuff when it works most of the time.
// However, it's also a pain to debug when no context is provided for an error message.
import {client} from "..";
import {setExecuteCommandListener} from "onion-lasers";
import {TextChannel, DMChannel, NewsChannel} from "discord.js";
let lastEvent = "N/A";
let lastCommandInfo: {
header: string;
args: string[];
channel: TextChannel | DMChannel | NewsChannel | null;
} = {
header: "N/A",
args: [],
channel: null
};
// A generic process handler is set to catch unhandled rejections other than the ones from Lavalink and Discord.
process.on("unhandledRejection", (reason: any) => {
const isLavalinkError = reason?.code === "ECONNREFUSED";
const isDiscordError = reason?.name === "DiscordAPIError";
// If it's a DiscordAPIError on a message event, I'll make the assumption that it comes from the command handler.
if (!isLavalinkError && (!isDiscordError || lastEvent !== "message"))
console.error(`@${lastEvent}\n${reason.stack}`);
if (!isLavalinkError) {
// If it's a DiscordAPIError on a message event, I'll make the assumption that it comes from the command handler.
// That's not always the case though, especially if you add your own message events. Just be wary of that.
if (isDiscordError && lastEvent === "message") {
console.error(
`Command Error: ${lastCommandInfo.header} (${lastCommandInfo.args.join(", ")})\n${reason.stack}`
);
lastCommandInfo.channel?.send(
`There was an error while trying to execute that command!\`\`\`${reason.stack}\`\`\``
);
} else {
console.error(
`@${lastEvent} : /${lastCommandInfo.header} (${lastCommandInfo.args.join(", ")})\n${reason.stack}`
);
}
}
});
// Store info on which command was executed last.
setExecuteCommandListener(({header, args, channel}) => {
lastCommandInfo = {
header,
args,
channel
};
});
// This will dynamically attach all known events instead of doing it manually.

View File

@ -1,10 +1,10 @@
import {GuildMember, VoiceChannel, MessageEmbed, TextChannel, Message, Collection} from "discord.js";
import {GuildMember, VoiceChannel, MessageEmbed, TextChannel, Message, Collection, StageChannel} from "discord.js";
import {client} from "../index";
import {Storage} from "../structures";
type Stream = {
streamer: GuildMember;
channel: VoiceChannel;
channel: VoiceChannel | StageChannel;
category: string;
description?: string;
thumbnail?: string;
@ -19,7 +19,7 @@ export const streamList = new Collection<string, Stream>();
// Probably find a better, DRY way of doing this.
function getStreamEmbed(
streamer: GuildMember,
channel: VoiceChannel,
channel: VoiceChannel | StageChannel,
streamStart: number,
category: string,
description?: string,

View File

@ -5,21 +5,17 @@ import {Config} from "../structures";
// Logging which guilds the bot is added to and removed from makes sense.
// However, logging the specific channels that are added/removed is a tad bit privacy-invading.
client.on("guildCreate", (guild) => {
console.log(
`[GUILD JOIN] ${guild.name} (${guild.id}) added the bot. Owner: ${guild.owner!.user.tag} (${
guild.owner!.user.id
}).`
);
client.on("guildCreate", async (guild) => {
const owner = await guild.fetchOwner();
console.log(`[GUILD JOIN] ${guild.name} (${guild.id}) added the bot. Owner: ${owner.user.tag} (${owner.user.id}).`);
if (Config.systemLogsChannel) {
const channel = client.channels.cache.get(Config.systemLogsChannel);
if (channel && channel.type === "text") {
(channel as TextChannel).send(
`TravBot joined: \`${guild.name}\`. The owner of this guild is: \`${guild.owner!.user.tag}\` (\`${
guild.owner!.user.id
}\`)`
`TravBot joined: \`${guild.name}\`. The owner of this guild is: \`${owner.user.tag}\` (\`${owner.user.id}\`)`
);
} else {
console.warn(`${Config.systemLogsChannel} is not a valid text channel for system logs!`);

View File

@ -8,7 +8,7 @@ const ID_PATTERN = /(\d{17,})/;
// Resolve any available webhooks available for a selected channel.
export async function resolveWebhook(channel: TextChannel | NewsChannel): Promise<Webhook | null> {
if (channel.guild.me?.hasPermission(Permissions.FLAGS.MANAGE_WEBHOOKS)) {
if (channel.guild.me?.permissions.has(Permissions.FLAGS.MANAGE_WEBHOOKS)) {
const webhooksInChannel = await channel.fetchWebhooks();
if (webhooksInChannel.size > 0) return webhooksInChannel.first()!;

View File

@ -243,9 +243,9 @@ export function getPrefix(guild: DiscordGuild | null): string {
}
export interface EmoteRegistryDumpEntry {
ref: string;
ref: string | null;
id: Snowflake;
name: string;
name: string | null;
requires_colons: boolean;
animated: boolean;
url: string;