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