Initial commit
This commit is contained in:
commit
3b3068efaa
18 changed files with 850 additions and 0 deletions
4
.dockerignore
Normal file
4
.dockerignore
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
node_modules/
|
||||
.env.local
|
||||
.git
|
||||
.gitignore
|
||||
3
.env
Normal file
3
.env
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
DISCORD_TOKEN=
|
||||
DISCORD_CLIENT_ID=
|
||||
# permissions for bot : 412854249536
|
||||
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# Configuratrion
|
||||
.env.local
|
||||
|
||||
# Libraries
|
||||
node_modules/
|
||||
|
||||
# Save data
|
||||
data/**/*.json
|
||||
17
.vscode/launch.json
vendored
Normal file
17
.vscode/launch.json
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Launch Program",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"program": "${workspaceFolder}\\index.js"
|
||||
}
|
||||
]
|
||||
}
|
||||
16
Dockerfile
Normal file
16
Dockerfile
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
FROM node:latest
|
||||
|
||||
# Create the directory!
|
||||
RUN mkdir -p /roleautoremover
|
||||
WORKDIR /roleautoremover
|
||||
|
||||
# Copy and Install our bot
|
||||
COPY package.json /roleautoremover
|
||||
COPY package-lock.json /roleautoremover
|
||||
RUN npm install
|
||||
|
||||
# Our precious bot
|
||||
COPY . /roleautoremover
|
||||
|
||||
# Start me!
|
||||
CMD ["node", "index.js"]
|
||||
24
commands/check.js
Normal file
24
commands/check.js
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
const { CommandInteraction, SlashCommandBuilder } = require("discord.js");
|
||||
const { dbGetAll, dbSerialize } = require("../db");
|
||||
const { PermissionFlagsBits } = require('discord-api-types/v10');
|
||||
|
||||
module.exports.name = "role-remover-check";
|
||||
|
||||
module.exports.data = new SlashCommandBuilder()
|
||||
.setName(module.exports.name)
|
||||
.setDescription("Gets the list of roles that are auto removed.")
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageRoles);
|
||||
|
||||
/**
|
||||
* @param {CommandInteraction} interaction
|
||||
*/
|
||||
module.exports.execute = async function(interaction) {
|
||||
const guildId = interaction.guildId;
|
||||
const settings = dbGetAll("roles")
|
||||
const sameGuild = settings.filter(s => s.guildId === guildId)
|
||||
|
||||
// Done
|
||||
return interaction.reply({
|
||||
content: '# Auto removed roles:\n```json\n' + dbSerialize(sameGuild).substring(0, 1900) + '\n```',
|
||||
});
|
||||
};
|
||||
56
commands/create.js
Normal file
56
commands/create.js
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
const { CommandInteraction, SlashCommandBuilder, Role } = require("discord.js");
|
||||
const { dbGet, dbWrite } = require("../db");
|
||||
const { PermissionFlagsBits } = require('discord-api-types/v10');
|
||||
|
||||
module.exports.name = "role-remover-create";
|
||||
|
||||
module.exports.data = new SlashCommandBuilder()
|
||||
.setName(module.exports.name)
|
||||
.setDescription("Adds a role to be auto removed.")
|
||||
.addRoleOption(option => {
|
||||
option.setName("when");
|
||||
option.setDescription("Check for the absence of this role.");
|
||||
option.setRequired(true);
|
||||
return option;
|
||||
})
|
||||
.addRoleOption(option => {
|
||||
option.setName("remove");
|
||||
option.setDescription("Remove this role if missing.");
|
||||
option.setRequired(true);
|
||||
return option;
|
||||
})
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageRoles);
|
||||
|
||||
|
||||
/**
|
||||
* @param {CommandInteraction} interaction
|
||||
*/
|
||||
module.exports.execute = async function(interaction) {
|
||||
// Get settings
|
||||
/** @type {Role} */
|
||||
const optWhen = interaction.options.getRole("when");
|
||||
/** @type {Role} */
|
||||
const optRemove = interaction.options.getRole("remove");
|
||||
const guildId = interaction.guildId;
|
||||
|
||||
let roles = dbGet("roles", optWhen.id);
|
||||
if (roles === null) {
|
||||
roles = {}
|
||||
roles.roleId = optWhen.id;
|
||||
roles.roleName = optWhen.name;
|
||||
roles.guildId = guildId;
|
||||
roles.remove = {};
|
||||
}
|
||||
|
||||
roles.remove[optRemove.id] = {
|
||||
removeId: optRemove.id,
|
||||
removeName: optRemove.name,
|
||||
};
|
||||
|
||||
dbWrite("roles", optWhen.id, roles)
|
||||
|
||||
// Done
|
||||
return interaction.reply({
|
||||
content: `Will now automatically remove role <@&${optRemove.id}> from members without <@&${optWhen.id}>.`,
|
||||
});
|
||||
};
|
||||
56
commands/delete.js
Normal file
56
commands/delete.js
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
const { CommandInteraction, SlashCommandBuilder, Role } = require("discord.js");
|
||||
const { dbGet, dbWrite, dbDelete } = require("../db");
|
||||
const { PermissionFlagsBits } = require('discord-api-types/v10');
|
||||
|
||||
module.exports.name = "role-remover-delete";
|
||||
|
||||
module.exports.data = new SlashCommandBuilder()
|
||||
.setName(module.exports.name)
|
||||
.setDescription("Disables a role to be auto removed.")
|
||||
.addRoleOption(option => {
|
||||
option.setName("when");
|
||||
option.setDescription("Check for the absence of this role.");
|
||||
option.setRequired(true);
|
||||
return option;
|
||||
})
|
||||
.addRoleOption(option => {
|
||||
option.setName("remove");
|
||||
option.setDescription("No longer remove this role if missing.");
|
||||
option.setRequired(true);
|
||||
return option;
|
||||
})
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageRoles);
|
||||
|
||||
|
||||
/**
|
||||
* @param {CommandInteraction} interaction
|
||||
*/
|
||||
module.exports.execute = async function(interaction) {
|
||||
// Get settings
|
||||
/** @type {Role} */
|
||||
const optWhen = interaction.options.getRole("when");
|
||||
/** @type {Role} */
|
||||
const optRemove = interaction.options.getRole("remove");
|
||||
|
||||
const settings = dbGet("roles", optWhen.id);
|
||||
if (!settings) {
|
||||
return interaction.reply({
|
||||
content: "No auto remove settings for this role.",
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
|
||||
delete settings.remove[optRemove.id];
|
||||
// Done
|
||||
if (Object.keys(settings.remove).length === 0) {
|
||||
dbDelete("roles", optWhen.id);
|
||||
return interaction.reply({
|
||||
content: `Disabled all role removal for <@&${optWhen.id}>.`,
|
||||
});
|
||||
} else {
|
||||
dbWrite("roles", optWhen.id, settings)
|
||||
return interaction.reply({
|
||||
content: `Will no longer automatically remove role <@&${optRemove.id}> from members without <@&${optWhen.id}>.`,
|
||||
});
|
||||
}
|
||||
};
|
||||
23
commands/index.js
Normal file
23
commands/index.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const commands = {};
|
||||
|
||||
const basename = path.basename(__filename);
|
||||
fs
|
||||
.readdirSync(__dirname)
|
||||
.filter(file => {
|
||||
return (
|
||||
file.indexOf('.') !== 0 &&
|
||||
file !== basename &&
|
||||
file.slice(-3) === '.js' &&
|
||||
file.indexOf('.test.js') === -1
|
||||
);
|
||||
})
|
||||
.forEach(file => {
|
||||
const command = require(path.join(__dirname, file));
|
||||
console.log('Found command', command)
|
||||
commands[command.name] = command;
|
||||
});
|
||||
|
||||
module.exports.commands = commands;
|
||||
15
config.js
Normal file
15
config.js
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
const dotenv = require("dotenv");
|
||||
|
||||
dotenv.config();
|
||||
dotenv.config({ path: ".env.local", override: true });
|
||||
|
||||
const { DISCORD_TOKEN, DISCORD_CLIENT_ID } = process.env;
|
||||
|
||||
if (!DISCORD_TOKEN || !DISCORD_CLIENT_ID) {
|
||||
throw new Error("Missing environment variables");
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
DISCORD_TOKEN,
|
||||
DISCORD_CLIENT_ID,
|
||||
};
|
||||
0
data/roles/.gitkeep
Normal file
0
data/roles/.gitkeep
Normal file
157
db.js
Normal file
157
db.js
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const cache = {};
|
||||
|
||||
function tableCache(table) {
|
||||
let tableCache = cache[table];
|
||||
if (!tableCache) {
|
||||
tableCache = {};
|
||||
cache[table] = tableCache;
|
||||
}
|
||||
return tableCache;
|
||||
}
|
||||
|
||||
function dbSerialize(data) {
|
||||
return JSON.stringify(data, replacer, 2);
|
||||
}
|
||||
module.exports.dbSerialize = dbSerialize;
|
||||
|
||||
function dbDeserialize(data) {
|
||||
return JSON.parse(data, reviver);
|
||||
}
|
||||
module.exports.dbDeserialize = dbDeserialize;
|
||||
|
||||
function dbDelete(table, id) {
|
||||
const file = dbFile(table, id);
|
||||
if (fs.existsSync(file)) {
|
||||
fs.unlinkSync(file);
|
||||
}
|
||||
delete tableCache(table)[id];
|
||||
}
|
||||
module.exports.dbDelete = dbDelete;
|
||||
|
||||
function dbWrite(table, id, data) {
|
||||
const file = dbFile(table, id);
|
||||
fs.writeFileSync(file, dbSerialize(data));
|
||||
tableCache(table)[id] = data;
|
||||
}
|
||||
module.exports.dbWrite = dbWrite;
|
||||
|
||||
/**
|
||||
* Gets an entry from the database.
|
||||
* @param {string} table The table name
|
||||
* @param {string} id The record ID.
|
||||
* @returns {object | null} The entry
|
||||
*/
|
||||
function dbGet(table, id) {
|
||||
const file = dbFile(table, id);
|
||||
let data = tableCache(table)[id];
|
||||
if (data === undefined) {
|
||||
if (fs.existsSync(file)) {
|
||||
data = dbDeserialize(fs.readFileSync(file));
|
||||
} else {
|
||||
data = null;
|
||||
}
|
||||
tableCache(table)[id] = data;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
module.exports.dbGet = dbGet;
|
||||
|
||||
/**
|
||||
* Gets all entires of a given table from the database.
|
||||
* @param {string} table The table name
|
||||
* @returns {object[]} The entries
|
||||
*/
|
||||
function dbGetAll(table) {
|
||||
const files = fs.readdirSync(dbDir(table));
|
||||
const all = [];
|
||||
for (const file of files) {
|
||||
const id = file.split('.')[0];
|
||||
const data = dbGet(table, id);
|
||||
if (!data) {
|
||||
continue;
|
||||
}
|
||||
all.push(data);
|
||||
}
|
||||
return all;
|
||||
}
|
||||
module.exports.dbGetAll = dbGetAll;
|
||||
|
||||
function dbDir(table) {
|
||||
return path.join('data', dbSafe(table));
|
||||
}
|
||||
|
||||
function dbFile(table, id) {
|
||||
return path.join('data', dbSafe(table), `${dbSafe(id)}.json`);
|
||||
}
|
||||
|
||||
function dbSafe(str) {
|
||||
return str.replace(/[^a-z0-9]/gi, '_').toLowerCase();
|
||||
}
|
||||
|
||||
function reviver(key, value) {
|
||||
if (typeof value === "object" && value != null) {
|
||||
for (const customTypeName in customTypes) {
|
||||
if (value.hasOwnProperty(customTypeName)) {
|
||||
const customTypeValue = value[customTypeName];
|
||||
const customType = customTypes[customTypeName];
|
||||
return customType.reviver(customTypeValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function replacer(key, value) {
|
||||
const rawValue = this[key];
|
||||
for (const customTypeName in customTypes) {
|
||||
const customType = customTypes[customTypeName];
|
||||
if (customType.condition(rawValue)) {
|
||||
return { [customTypeName]: customType.replacer(rawValue) };
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom types support for JSON files. Make sure that no custom type names conflict with actual possible JSON keys.
|
||||
*
|
||||
* When serializing:
|
||||
* - Custom types work by running the `condition` function of every value to be serialized.
|
||||
* - If it returns `true`, the `replacer` function is called with the value.
|
||||
* - The return value of the `replacer` will be saved to JSON wrapped in an object using the key of the custom type. (e.g. `{"$myType": "hello"}`).
|
||||
*
|
||||
* When deserializing:
|
||||
* - Each value is checked if it is an object with a key of any custom type.
|
||||
* - If one is found, the `reviver` is called for the value of this key.
|
||||
* - The return value is used as the actual value.
|
||||
*/
|
||||
const customTypes = {
|
||||
$date: {
|
||||
condition: function (value) {
|
||||
return value instanceof Date;
|
||||
},
|
||||
replacer: function (value) {
|
||||
return value.toISOString();
|
||||
},
|
||||
reviver: function (value) {
|
||||
return new Date(value);
|
||||
},
|
||||
},
|
||||
$set: {
|
||||
/** @param {Set} value */
|
||||
condition: function (value) {
|
||||
return value instanceof Set;
|
||||
},
|
||||
/** @param {Set} value */
|
||||
replacer: function (value) {
|
||||
return [...value];
|
||||
},
|
||||
/** @param {Array} value */
|
||||
reviver: function (value) {
|
||||
return new Set(value);
|
||||
},
|
||||
},
|
||||
}
|
||||
48
deploy-commands.js
Normal file
48
deploy-commands.js
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
const { REST, Routes, CommandInteraction } = require("discord.js");
|
||||
const { commands } = require("./commands");
|
||||
const config = require("./config");
|
||||
|
||||
const commandsData = Object.values(commands).map((command) => command.data);
|
||||
|
||||
const rest = new REST({ version: "10" }).setToken(config.DISCORD_TOKEN);
|
||||
|
||||
/**
|
||||
* @typedef DeployCommandsProps
|
||||
* @property {string} guildId
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {DeployCommandsProps}
|
||||
*/
|
||||
module.exports.deployCommands = async function deployCommands({ guildId }) {
|
||||
try {
|
||||
console.log("Started refreshing commands in %s.", guildId);
|
||||
|
||||
await rest.put(
|
||||
Routes.applicationGuildCommands(config.DISCORD_CLIENT_ID, guildId),
|
||||
{
|
||||
body: commandsData,
|
||||
}
|
||||
);
|
||||
|
||||
console.log("Successfully reloaded commands in %s.", guildId);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {CommandInteraction} interaction
|
||||
*/
|
||||
module.exports.handleCommand = async function handleCommand(interaction) {
|
||||
try {
|
||||
/** @type {{commandName: keyof commands}} */
|
||||
const { commandName } = interaction;
|
||||
console.log("Handle command %s in %s", commandName, interaction.guildId)
|
||||
if (commands[commandName]) {
|
||||
commands[commandName].execute(interaction);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
14
docker-compose.yml
Normal file
14
docker-compose.yml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
version: '3.5'
|
||||
|
||||
services:
|
||||
imaptodiscord:
|
||||
container_name: roleautoremover
|
||||
image: kayleesachs/roleautoremover:latest
|
||||
volumes:
|
||||
- /root/roleautoremover/env:/roleautoremover/.env.local
|
||||
- /root/roleautoremover/db:/roleautoremover/db
|
||||
logging:
|
||||
driver: journald
|
||||
options:
|
||||
tag: "{{.ImageName}}/{{.Name}}/{{.ID}}"
|
||||
restart: unless-stopped
|
||||
40
index.js
Normal file
40
index.js
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
const { Client, GatewayIntentBits } = require("discord.js");
|
||||
const { deployCommands, handleCommand } = require("./deploy-commands");
|
||||
const config = require("./config");
|
||||
const { maybeUpdateRoles } = require("./logic");
|
||||
|
||||
const client = new Client({
|
||||
intents: [
|
||||
GatewayIntentBits.Guilds,
|
||||
GatewayIntentBits.GuildMembers,
|
||||
],
|
||||
});
|
||||
|
||||
client.once("clientReady", () => {
|
||||
console.log("Discord bot is ready! 🤖");
|
||||
});
|
||||
|
||||
client.on("guildAvailable", async (guild) => {
|
||||
await deployCommands({ guildId: guild.id });
|
||||
});
|
||||
|
||||
client.on('messageCreate', async (message) => {
|
||||
if (message.channel != null) {
|
||||
maybeRepost(message.channel, message).catch(console.error);
|
||||
}
|
||||
});
|
||||
|
||||
client.on("guildMemberUpdate", async (oldMember, newMember) => {
|
||||
await maybeUpdateRoles(oldMember, newMember);
|
||||
});
|
||||
|
||||
client.on("interactionCreate", async (interaction) => {
|
||||
if (interaction.isCommand()) {
|
||||
try {
|
||||
await handleCommand(interaction);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
client.login(config.DISCORD_TOKEN);
|
||||
42
logic.js
Normal file
42
logic.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
const { GuildMember } = require("discord.js");
|
||||
const { dbGetAll } = require("./db");
|
||||
|
||||
/**
|
||||
* Checks and removes roles.
|
||||
* @param {GuildMember} oldMember The old member.
|
||||
* @param {GuildMember?} newMember The new member.
|
||||
* @returns {Promise<void>} Once done
|
||||
*/
|
||||
async function maybeUpdateRoles(oldMember, newMember) {
|
||||
const settings = dbGetAll("roles")
|
||||
for (const setting of settings) {
|
||||
if (setting.guildId !== newMember.guild.id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Still has the role
|
||||
if (newMember.roles.cache.has(setting.roleId)) {
|
||||
continue;
|
||||
}
|
||||
// The user never had the role
|
||||
if (!oldMember.roles.cache.has(setting.roleId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const removeSetting in setting.remove) {
|
||||
const role = newMember.roles.cache.get(removeSetting);
|
||||
if (!role) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
await newMember.roles.remove(role, "Auto remover: " + setting.roleName);
|
||||
} catch(error) {
|
||||
console.log(`Failed to remove ${role} from ${newMember}`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = { maybeUpdateRoles };
|
||||
321
package-lock.json
generated
Normal file
321
package-lock.json
generated
Normal file
|
|
@ -0,0 +1,321 @@
|
|||
{
|
||||
"name": "DiscordRoleAutoRemover",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"discord.js": "^14.16.2",
|
||||
"dotenv": "^17.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@discordjs/builders": {
|
||||
"version": "1.11.3",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.11.3.tgz",
|
||||
"integrity": "sha512-p3kf5eV49CJiRTfhtutUCeivSyQ/l2JlKodW1ZquRwwvlOWmG9+6jFShX6x8rUiYhnP6wKI96rgN/SXMy5e5aw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@discordjs/formatters": "^0.6.1",
|
||||
"@discordjs/util": "^1.1.1",
|
||||
"@sapphire/shapeshift": "^4.0.0",
|
||||
"discord-api-types": "^0.38.16",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"ts-mixer": "^6.0.4",
|
||||
"tslib": "^2.6.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.11.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/discordjs/discord.js?sponsor"
|
||||
}
|
||||
},
|
||||
"node_modules/@discordjs/collection": {
|
||||
"version": "1.5.3",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz",
|
||||
"integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=16.11.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@discordjs/formatters": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.6.1.tgz",
|
||||
"integrity": "sha512-5cnX+tASiPCqCWtFcFslxBVUaCetB0thvM/JyavhbXInP1HJIEU+Qv/zMrnuwSsX3yWH2lVXNJZeDK3EiP4HHg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"discord-api-types": "^0.38.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.11.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/discordjs/discord.js?sponsor"
|
||||
}
|
||||
},
|
||||
"node_modules/@discordjs/rest": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.6.0.tgz",
|
||||
"integrity": "sha512-RDYrhmpB7mTvmCKcpj+pc5k7POKszS4E2O9TYc+U+Y4iaCP+r910QdO43qmpOja8LRr1RJ0b3U+CqVsnPqzf4w==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@discordjs/collection": "^2.1.1",
|
||||
"@discordjs/util": "^1.1.1",
|
||||
"@sapphire/async-queue": "^1.5.3",
|
||||
"@sapphire/snowflake": "^3.5.3",
|
||||
"@vladfrangu/async_event_emitter": "^2.4.6",
|
||||
"discord-api-types": "^0.38.16",
|
||||
"magic-bytes.js": "^1.10.0",
|
||||
"tslib": "^2.6.3",
|
||||
"undici": "6.21.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/discordjs/discord.js?sponsor"
|
||||
}
|
||||
},
|
||||
"node_modules/@discordjs/rest/node_modules/@discordjs/collection": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.1.1.tgz",
|
||||
"integrity": "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/discordjs/discord.js?sponsor"
|
||||
}
|
||||
},
|
||||
"node_modules/@discordjs/util": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.1.1.tgz",
|
||||
"integrity": "sha512-eddz6UnOBEB1oITPinyrB2Pttej49M9FZQY8NxgEvc3tq6ZICZ19m70RsmzRdDHk80O9NoYN/25AqJl8vPVf/g==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/discordjs/discord.js?sponsor"
|
||||
}
|
||||
},
|
||||
"node_modules/@discordjs/ws": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.2.3.tgz",
|
||||
"integrity": "sha512-wPlQDxEmlDg5IxhJPuxXr3Vy9AjYq5xCvFWGJyD7w7Np8ZGu+Mc+97LCoEc/+AYCo2IDpKioiH0/c/mj5ZR9Uw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@discordjs/collection": "^2.1.0",
|
||||
"@discordjs/rest": "^2.5.1",
|
||||
"@discordjs/util": "^1.1.0",
|
||||
"@sapphire/async-queue": "^1.5.2",
|
||||
"@types/ws": "^8.5.10",
|
||||
"@vladfrangu/async_event_emitter": "^2.2.4",
|
||||
"discord-api-types": "^0.38.1",
|
||||
"tslib": "^2.6.2",
|
||||
"ws": "^8.17.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.11.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/discordjs/discord.js?sponsor"
|
||||
}
|
||||
},
|
||||
"node_modules/@discordjs/ws/node_modules/@discordjs/collection": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.1.1.tgz",
|
||||
"integrity": "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/discordjs/discord.js?sponsor"
|
||||
}
|
||||
},
|
||||
"node_modules/@sapphire/async-queue": {
|
||||
"version": "1.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.5.tgz",
|
||||
"integrity": "sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=v14.0.0",
|
||||
"npm": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@sapphire/shapeshift": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-4.0.0.tgz",
|
||||
"integrity": "sha512-d9dUmWVA7MMiKobL3VpLF8P2aeanRTu6ypG2OIaEv/ZHH/SUQ2iHOVyi5wAPjQ+HmnMuL0whK9ez8I/raWbtIg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"lodash": "^4.17.21"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=v16"
|
||||
}
|
||||
},
|
||||
"node_modules/@sapphire/snowflake": {
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.3.tgz",
|
||||
"integrity": "sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=v14.0.0",
|
||||
"npm": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "24.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.5.2.tgz",
|
||||
"integrity": "sha512-FYxk1I7wPv3K2XBaoyH2cTnocQEu8AOZ60hPbsyukMPLv5/5qr7V1i8PLHdl6Zf87I+xZXFvPCXYjiTFq+YSDQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~7.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/ws": {
|
||||
"version": "8.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
|
||||
"integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@vladfrangu/async_event_emitter": {
|
||||
"version": "2.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.4.6.tgz",
|
||||
"integrity": "sha512-RaI5qZo6D2CVS6sTHFKg1v5Ohq/+Bo2LZ5gzUEwZ/WkHhwtGTCB/sVLw8ijOkAUxasZ+WshN/Rzj4ywsABJ5ZA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=v14.0.0",
|
||||
"npm": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/discord-api-types": {
|
||||
"version": "0.38.26",
|
||||
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.38.26.tgz",
|
||||
"integrity": "sha512-xpmPviHjIJ6dFu1eNwNDIGQ3N6qmPUUYFVAx/YZ64h7ZgPkTcKjnciD8bZe8Vbeji7yS5uYljyciunpq0J5NSw==",
|
||||
"license": "MIT",
|
||||
"workspaces": [
|
||||
"scripts/actions/documentation"
|
||||
]
|
||||
},
|
||||
"node_modules/discord.js": {
|
||||
"version": "14.22.1",
|
||||
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.22.1.tgz",
|
||||
"integrity": "sha512-3k+Kisd/v570Jr68A1kNs7qVhNehDwDJAPe4DZ2Syt+/zobf9zEcuYFvsfIaAOgCa0BiHMfOOKQY4eYINl0z7w==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@discordjs/builders": "^1.11.2",
|
||||
"@discordjs/collection": "1.5.3",
|
||||
"@discordjs/formatters": "^0.6.1",
|
||||
"@discordjs/rest": "^2.6.0",
|
||||
"@discordjs/util": "^1.1.1",
|
||||
"@discordjs/ws": "^1.2.3",
|
||||
"@sapphire/snowflake": "3.5.3",
|
||||
"discord-api-types": "^0.38.16",
|
||||
"fast-deep-equal": "3.1.3",
|
||||
"lodash.snakecase": "4.1.1",
|
||||
"magic-bytes.js": "^1.10.0",
|
||||
"tslib": "^2.6.3",
|
||||
"undici": "6.21.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/discordjs/discord.js?sponsor"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "17.2.2",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.2.tgz",
|
||||
"integrity": "sha512-Sf2LSQP+bOlhKWWyhFsn0UsfdK/kCWRv1iuA2gXAwt3dyNabr6QSj00I2V10pidqz69soatm9ZwZvpQMTIOd5Q==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://dotenvx.com"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.snakecase": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz",
|
||||
"integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/magic-bytes.js": {
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.12.1.tgz",
|
||||
"integrity": "sha512-ThQLOhN86ZkJ7qemtVRGYM+gRgR8GEXNli9H/PMvpnZsE44Xfh3wx9kGJaldg314v85m+bFW6WBMaVHJc/c3zA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ts-mixer": {
|
||||
"version": "6.0.4",
|
||||
"resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz",
|
||||
"integrity": "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "6.21.3",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-6.21.3.tgz",
|
||||
"integrity": "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18.17"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "7.12.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.12.0.tgz",
|
||||
"integrity": "sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.18.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
|
||||
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
6
package.json
Normal file
6
package.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"discord.js": "^14.16.2",
|
||||
"dotenv": "^17.2.2"
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue