Migrate to revolt.js 7.0

master
Lea 2023-04-12 21:17:34 +02:00
parent 9685bc5608
commit b3ee6094ce
Signed by: Lea
GPG Key ID: 1BAFFE8347019C42
55 changed files with 873 additions and 879 deletions

4
.gitmodules vendored Normal file
View File

@ -0,0 +1,4 @@
[submodule "revolt.js"]
path = revolt.js
url = https://github.com/revoltchat/revolt.js
branch = insert/feat/store-rewrite

View File

@ -13,7 +13,6 @@
"author": "",
"license": "ISC",
"dependencies": {
"@janderedev/revolt.js": "latest",
"@types/monk": "^6.0.0",
"automod": "^0.1.0",
"axios": "^0.22.0",
@ -24,7 +23,8 @@
"log75": "^2.2.0",
"monk": "^7.3.4",
"prom-client": "^14.0.1",
"revolt-api": "^0.5.16",
"revolt-api": "latest",
"revolt.js": "^7.0.0",
"ulid": "^2.3.0",
"xlsx": "^0.17.3"
},
@ -33,6 +33,7 @@
},
"packageManager": "yarn@3.2.1",
"resolutions": {
"automod": "portal:../lib"
"automod": "portal:../lib",
"revolt.js": "portal:../revolt.js"
}
}

View File

@ -5,7 +5,7 @@ import { commands, DEFAULT_PREFIX, ownerIDs } from "../../modules/command_handle
import child_process from 'child_process';
import fs from 'fs';
import path from 'path';
import { User } from "@janderedev/revolt.js/dist/maps/Users";
import { User } from "revolt.js";
import { adminBotLog } from "../../logging";
import CommandCategory from "../../../struct/commands/CommandCategory";
import { getMutualServers, parseUserOrId } from "../../util";
@ -17,11 +17,11 @@ const BLACKLIST_MESSAGE = (username: string) => `\`@${username}\` has been banne
const sudoOverrides: { [key: string]: number|null } = {}
const isSudo = (user: User): boolean => {
return !!(sudoOverrides[user._id] && sudoOverrides[user._id]! > Date.now());
return !!(sudoOverrides[user.id] && sudoOverrides[user.id]! > Date.now());
}
const updateSudoTimeout = (user: User) => {
sudoOverrides[user._id] = Date.now() + (1000 * 60 * 5);
sudoOverrides[user.id] = Date.now() + (1000 * 60 * 5);
}
const getCommitHash = (): Promise<string|null> => new Promise((resolve) => {
@ -57,23 +57,22 @@ export default {
const pjson = JSON.parse((await fs.promises.readFile(path.join(process.cwd(), 'package.json'))).toString());
let msg = `# AutoMod stats\n`
+ `### Cache\n`
+ `Servers: \`${client.servers.size}\`\n`
+ `Channels: \`${client.channels.size}\`\n`
+ `Users: \`${client.users.size}\`\n`
+ `Servers: \`${client.servers.size()}\`\n`
+ `Channels: \`${client.channels.size()}\`\n`
+ `Users: \`${client.users.size()}\`\n`
+ `### Misc\n`
+ `Command count: \`${commands.length}\`\n`
+ `Environment: \`${process.env.NODE_ENV || 'testing'}\`\n`
+ `Commit hash: \`${await getCommitHash() || 'Unknown'}\`\n`
+ `### Packages\n`
+ `revolt.js: \`${pjson.dependencies['@janderedev/revolt.js']}\`\n`
+ `revolt.js: \`${pjson.dependencies['revolt.js']}\`\n`
+ `discord.js: \`${pjson.dependencies['discord.js']}\`\n`
+ `axios: \`${pjson.dependencies['axios']}\`\n`
+ `log75: \`${pjson.dependencies['log75']}\`\n`
+ `typescript: \`${pjson.devDependencies['typescript']}\`\n`
+ `### Connection\n`
+ `API Endpoint: \`${client.apiURL}\`\n`
+ `Heartbeat: \`${client.heartbeat}\`\n`
+ `Ping: \`${client.websocket.ping ?? 'Unknown'}\`\n`
+ `API Endpoint: \`${client.options.baseURL}\`\n`
+ `Ping: \`${client.events.ping() ?? 'Unknown'}\`\n`
+ `### Bot configuration\n`
+ `Owners: \`${ownerIDs.length}\` (${ownerIDs.join(', ')})\n`;
@ -87,7 +86,7 @@ export default {
case 'on': {
if (isSudo(message.author!)) return message.reply('You are already in sudo mode!');
sudoOverrides[message.author_id] = Date.now() + (1000 * 60 * 5);
sudoOverrides[message.authorId!] = Date.now() + (1000 * 60 * 5);
let msg = `# %emoji% Sudo mode enabled\n`
+ `In sudo mode, you will be able to run any command regardless of your server permissions.\n`
@ -106,7 +105,7 @@ export default {
case 'off': {
if (!isSudo(message.author!)) return message.reply('You currently not in sudo mode.');
sudoOverrides[message.author_id] = null;
sudoOverrides[message.authorId!] = null;
let msg = `# %emoji% Sudo mode disabled.`;
const sentMsg = await message.reply(msg.replace('%emoji%', ':unlock:'), false);
@ -138,7 +137,7 @@ export default {
const target = await parseUserOrId(args.shift() || '');
if (!target) return message.reply('Specified user could not be found.');
const res = await dbs.USERS.findOne({ id: target._id });
const res = await dbs.USERS.findOne({ id: target.id });
if (!res) await message.reply(`Nothing stored about this user.`);
else await message.reply(`\`\`\`json\n${JSON.stringify(res, null, 4)}\n\`\`\``);
@ -149,12 +148,12 @@ export default {
case 'blacklist': {
const target = await parseUserOrId(args.shift() || '');
if (!target) return message.reply('Specified user could not be found.');
if (target._id == message.author_id) return message.reply(`no`);
if (target.id == message.authorId) return message.reply(`no`);
await dbs.USERS.update({
id: target._id,
id: target.id,
}, {
$setOnInsert: { id: target._id },
$setOnInsert: { id: target.id },
$set: { globalBlacklist: true }
}, { upsert: true });
@ -167,23 +166,23 @@ export default {
const mutuals = getMutualServers(target);
for (const server of mutuals) {
if (server.havePermission('BanMembers')) {
const config = await dbs.SERVERS.findOne({ id: server._id });
const config = await dbs.SERVERS.findOne({ id: server.id });
if (config?.allowBlacklistedUsers) continue;
try {
await server.banUser(target._id, {
await server.banUser(target.id, {
reason: BLACKLIST_BAN_REASON,
});
bannedServers++;
if (server.system_messages?.user_banned) {
const channel = server.channels.find(c => c!._id == server.system_messages!.user_banned);
if (server.systemMessages?.user_banned) {
const channel = server.channels.find(c => c!.id == server.systemMessages!.user_banned);
if (channel && channel.havePermission('SendMessage')) {
await channel.sendMessage(BLACKLIST_MESSAGE(target.username));
}
}
} catch(e) {
console.error(`Failed to ban in ${server._id}: ${e}`);
console.error(`Failed to ban in ${server.id}: ${e}`);
}
}
}
@ -205,9 +204,9 @@ export default {
if (!target) return message.reply('Specified user could not be found.');
await dbs.USERS.update({
id: target._id,
id: target.id,
}, {
$setOnInsert: { id: target._id },
$setOnInsert: { id: target.id },
$set: { globalBlacklist: false }
}, { upsert: true });
@ -221,9 +220,9 @@ export default {
if (!target) return message.reply('Specified user could not be found.');
await dbs.USERS.update({
id: target._id,
id: target.id,
}, {
$setOnInsert: { id: target._id },
$setOnInsert: { id: target.id },
$set: { blacklistReason: args.join(' ') || undefined }
}, { upsert: true });
@ -235,12 +234,12 @@ export default {
case 'ignore': {
const target = await parseUserOrId(args.shift() || '');
if (!target) return message.reply('Specified user could not be found.');
if (target._id == message.author_id) return message.reply(`no`);
if (target.id == message.authorId) return message.reply(`no`);
await dbs.USERS.update(
{ id: target._id },
{ id: target.id },
{
$setOnInsert: { id: target._id },
$setOnInsert: { id: target.id },
$set: { ignore: true },
},
{ upsert: true }
@ -254,12 +253,12 @@ export default {
case 'unignore': {
const target = await parseUserOrId(args.shift() || '');
if (!target) return message.reply('Specified user could not be found.');
if (target._id == message.author_id) return message.reply(`no`);
if (target.id == message.authorId) return message.reply(`no`);
await dbs.USERS.update(
{ id: target._id },
{ id: target.id },
{
$setOnInsert: { id: target._id },
$setOnInsert: { id: target.id },
$set: { ignore: false },
},
{ upsert: true }

View File

@ -1,7 +1,7 @@
import SimpleCommand from "../../../struct/commands/SimpleCommand";
import { hasPerm, parseUser } from "../../util";
import { parseUser } from "../../util";
import { client, dbs } from "../../..";
import { User } from "@janderedev/revolt.js/dist/maps/Users";
import { User } from "revolt.js";
import MessageCommandContext from "../../../struct/MessageCommandContext";
import CommandCategory from "../../../struct/commands/CommandCategory";
@ -14,10 +14,10 @@ export default {
syntax: SYNTAX,
category: CommandCategory.Config,
run: async (message: MessageCommandContext, args: string[]) => {
if (!hasPerm(message.member!, 'ManageServer'))
if (!message.member?.hasPermission(message.member.server!, 'ManageServer'))
return message.reply('You need **ManageServer** permission to use this command.');
let config = await dbs.SERVERS.findOne({ id: message.serverContext._id });
let config = await dbs.SERVERS.findOne({ id: message.serverContext.id });
let admins = config?.botManagers ?? [];
let user: User|null;
@ -28,12 +28,12 @@ export default {
user = await parseUser(args[1]);
if (!user) return message.reply('I can\'t find that user.');
if (admins.indexOf(user._id) > -1) return message.reply('This user is already added as bot admin.');
if (admins.indexOf(user.id) > -1) return message.reply('This user is already added as bot admin.');
admins.push(user._id);
await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { botManagers: admins } });
admins.push(user.id);
await dbs.SERVERS.update({ id: message.serverContext.id }, { $set: { botManagers: admins } });
message.reply(`✅ Added [@${user.username}](/@${user._id}) to bot admins.`);
message.reply(`✅ Added [@${user.username}](/@${user.id}) to bot admins.`);
break;
case 'remove':
case 'delete':
@ -43,12 +43,12 @@ export default {
user = await parseUser(args[1]);
if (!user) return message.reply('I can\'t find that user.');
if (admins.indexOf(user._id) == -1) return message.reply('This user is not added as bot admin.');
if (admins.indexOf(user.id) == -1) return message.reply('This user is not added as bot admin.');
admins = admins.filter(a => a != user?._id);
await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { botManagers: admins } });
admins = admins.filter(a => a != user?.id);
await dbs.SERVERS.update({ id: message.serverContext.id }, { $set: { botManagers: admins } });
message.reply(`✅ Removed [@${user.username}](/@${user._id}) from bot admins.`);
message.reply(`✅ Removed [@${user.username}](/@${user.id}) from bot admins.`);
break;
case 'list':
case 'ls':

View File

@ -7,7 +7,7 @@ import SimpleCommand from "../../../struct/commands/SimpleCommand";
import MessageCommandContext from "../../../struct/MessageCommandContext";
import { checkMessageForFilteredWords } from "../../modules/antispam";
import { DEFAULT_PREFIX } from "../../modules/command_handler";
import { embed, EmbedColor, getAutumnURL, getDmChannel, isBotManager, NO_MANAGER_MSG, sanitizeMessageContent } from "../../util";
import { embed, EmbedColor, getDmChannel, isBotManager, NO_MANAGER_MSG, sanitizeMessageContent } from "../../util";
const WORDLIST_DEFAULT_MESSAGE = '<@{{user_id}}>, the message you sent contained a blocked word.';
@ -28,10 +28,10 @@ export default {
return message.reply('Your server is currently listed in server discovery. As part of Revolt\'s [Discover Guidelines](<https://support.revolt.chat/kb/safety/discover-guidelines>), all servers on Discover are enrolled to AutoMod\'s antispam features.');
}
await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { allowBlacklistedUsers: true } });
await dbs.SERVERS.update({ id: message.serverContext.id }, { $set: { allowBlacklistedUsers: true } });
await message.reply('Globally blacklisted users will no longer get banned in this server. Previously banned users will need to be unbanned manually.');
} else if (args[0] == 'no') {
await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { allowBlacklistedUsers: false } });
await dbs.SERVERS.update({ id: message.serverContext.id }, { $set: { allowBlacklistedUsers: false } });
await message.reply('Globally blacklisted users will now get banned in this server.');
} else {
await message.reply(`Please specify either 'yes' or 'no' to toggle this setting.`);
@ -41,7 +41,7 @@ export default {
case 'spam_detection': {
if (args[0] == 'on') {
await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { antispamEnabled: true } });
await dbs.SERVERS.update({ id: message.serverContext.id }, { $set: { antispamEnabled: true } });
await message.reply('Spam detection is now enabled in this server.\nIf a user is wrongfully kicked '
+ 'or banned, please report it here: https://rvlt.gg/jan\n\n'
+ 'Please make sure to grant AutoMod permission to **Kick**, **Ban** and **Manage Messages**!');
@ -50,11 +50,11 @@ export default {
return message.reply('Your server is currently listed in server discovery. As part of Revolt\'s [Discover Guidelines](<https://support.revolt.chat/kb/safety/discover-guidelines>), all servers on Discover are enrolled to AutoMod\'s antispam features.');
}
await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { antispamEnabled: false } });
await dbs.SERVERS.update({ id: message.serverContext.id }, { $set: { antispamEnabled: false } });
await message.reply('Spam detection is now disabled in this server.');
} else {
const cfg = await dbs.SERVERS.findOne({ id: message.serverContext._id });
const cfg = await dbs.SERVERS.findOne({ id: message.serverContext.id });
await message.reply(`Spam detection is currently **${cfg?.antispamEnabled ? 'enabled' : 'disabled'}**. `
+ `Please specify either 'on' or 'off' to toggle this setting.`);
}
@ -80,48 +80,48 @@ export default {
const channel = client.channels.get(channelInput);
if (!channel) return message.reply('I can\'t find that channel.');
if (channel.server_id != message.channel?.server_id) return message.reply('That channel is not part of this server!');
if (channel.serverId != message.channel?.serverId) return message.reply('That channel is not part of this server!');
if (!channel.havePermission('SendMessage')) return message.reply('I don\'t have permission to **send messages** in that channel.');
if (!channel.havePermission('SendEmbeds')) return message.reply('I don\'t have permission to **send embeds** in that channel.');
switch(args[0]?.toLowerCase()) {
case 'messageupdate': {
await dbs.SERVERS.update(
{ id: message.channel!.server_id! },
{ id: message.channel!.serverId! },
{
$set: {
'logs.messageUpdate.revolt': {
channel: channel._id,
channel: channel.id,
type: 'EMBED',
},
},
$setOnInsert: {
id: message.channel!.server_id!,
id: message.channel!.serverId!,
}
},
{ upsert: true },
);
await message.reply(`Bound message update logs to <#${channel._id}>!`);
await message.reply(`Bound message update logs to <#${channel.id}>!`);
break;
}
case 'modaction': {
await dbs.SERVERS.update(
{ id: message.channel!.server_id! },
{ id: message.channel!.serverId! },
{
$set: {
'logs.modAction.revolt': {
channel: channel._id,
channel: channel.id,
type: 'EMBED',
},
},
$setOnInsert: {
id: message.channel!.server_id!,
id: message.channel!.serverId!,
}
},
{ upsert: true },
);
await message.reply(`Bound moderation logs to <#${channel._id}>!`);
await message.reply(`Bound moderation logs to <#${channel.id}>!`);
break;
}
@ -133,11 +133,11 @@ export default {
}
case 'filter': {
const config = await dbs.SERVERS.findOne({ id: message.channel!.server_id! });
const config = await dbs.SERVERS.findOne({ id: message.channel!.serverId! });
switch(args.shift()?.toLowerCase()) {
case 'enable': {
await dbs.SERVERS.update(
{ id: message.channel!.server_id! },
{ id: message.channel!.serverId! },
{ $set: { wordlistEnabled: true } },
{ upsert: true },
);
@ -152,7 +152,7 @@ export default {
}
case 'disable': {
await dbs.SERVERS.update(
{ id: message.channel!.server_id! },
{ id: message.channel!.serverId! },
{ $set: { wordlistEnabled: false } },
{ upsert: true },
);
@ -172,7 +172,7 @@ export default {
if (config?.wordlist?.find(w => w.word == word)) return await message.reply('That word is already on the list!');
await dbs.SERVERS.update(
{ id: message.channel!.server_id! },
{ id: message.channel!.serverId! },
{ $push: { wordlist: { strictness, word } } },
{ upsert: true },
);
@ -187,7 +187,7 @@ export default {
if (!config?.wordlist?.find(w => w.word == word)) return await message.reply('That word is not on the list.');
await dbs.SERVERS.update(
{ id: message.channel!.server_id! },
{ id: message.channel!.serverId! },
{ $pull: { wordlist: { word } } },
{ upsert: true },
);
@ -199,15 +199,15 @@ export default {
case 'show': {
const formData = new FormData();
formData.append(
`wordlist_${message.channel?.server_id}`,
`wordlist_${message.channel?.serverId}`,
config?.wordlist?.map(w => `${w.strictness}\t${w.word}`).join('\n') ?? '',
`wordlist_${message.channel?.server_id}.txt`
`wordlist_${message.channel?.serverId}.txt`
);
try {
const channel = await getDmChannel(message.author_id);
const channel = await getDmChannel(message.authorId!);
const res = await axios.post(
`${await getAutumnURL()}/attachments`,
`${client.configuration?.features.autumn.url}/attachments`,
formData,
{ headers: formData.getHeaders(), responseType: 'json' }
);
@ -244,7 +244,7 @@ export default {
}
await dbs.SERVERS.update(
{ id: message.channel!.server_id! },
{ id: message.channel!.serverId! },
{ $set: { wordlistAction: { action: config?.wordlistAction?.action ?? 'LOG', message: msg } } },
{ upsert: true },
);
@ -281,7 +281,7 @@ export default {
}
await dbs.SERVERS.update(
{ id: message.channel!.server_id! },
{ id: message.channel!.serverId! },
{ $set: { wordlistAction: {
action: action as any,
message: config?.wordlistAction?.message ?? WORDLIST_DEFAULT_MESSAGE

View File

@ -1,4 +1,4 @@
import { Message } from "@janderedev/revolt.js";
import { Message } from "revolt.js";
import { ulid } from "ulid";
import { SendableEmbed } from "revolt-api";
import { CONFIG_KEYS } from "automod/dist/misc/bridge_config_keys";
@ -30,20 +30,20 @@ export default {
return message.reply(NO_MANAGER_MSG);
const count = await dbs.BRIDGE_CONFIG.count({
revolt: message.channel_id,
revolt: message.channelId,
});
if (count)
return message.reply(`This channel is already bridged.`);
// Invalidate previous bridge request
await dbs.BRIDGE_REQUESTS.remove({
revolt: message.channel_id,
revolt: message.channelId,
});
const reqId = ulid();
await dbs.BRIDGE_REQUESTS.insert({
id: reqId,
revolt: message.channel_id,
revolt: message.channelId,
expires: Date.now() + 1000 * 60 * 15,
});
@ -74,7 +74,7 @@ export default {
return message.reply(NO_MANAGER_MSG);
const res = await dbs.BRIDGE_CONFIG.remove({
revolt: message.channel_id,
revolt: message.channelId,
});
if (res.deletedCount) await message.reply(`Channel unlinked!`);
else
@ -86,7 +86,7 @@ export default {
return message.reply(NO_MANAGER_MSG);
const query = {
revolt: { $in: message.channel?.server?.channel_ids || [] },
revolt: { $in: Array.from(message.channel?.server?.channelIds.values() ?? []) },
};
if (args[1] == "CONFIRM") {
const res = await dbs.BRIDGE_CONFIG.remove(query);
@ -119,7 +119,7 @@ export default {
return message.reply(NO_MANAGER_MSG);
const links = await dbs.BRIDGE_CONFIG.find({
revolt: { $in: message.channel?.server?.channel_ids || [] },
revolt: { $in: Array.from(message.channel?.server?.channelIds.values() ?? []) },
});
await message.reply({
@ -142,14 +142,14 @@ export default {
}
case "info": {
try {
if (!message.reply_ids) {
if (!message.replyIds) {
return await message.reply(
"Please run this command again while replying to a message."
);
}
if (
message.reply_ids.length > 1 &&
message.replyIds.length > 1 &&
!(await isModerator(message, false))
) {
return await message.reply(
@ -159,7 +159,7 @@ export default {
const messages = (
await Promise.allSettled(
message.reply_ids?.map((m) =>
message.replyIds.map((m) =>
message.channel!.fetchMessage(m)
) || []
)
@ -179,7 +179,7 @@ export default {
messages.map(async (msg) => {
const bridgeData =
await dbs.BRIDGED_MESSAGES.findOne({
"revolt.messageId": msg._id,
"revolt.messageId": msg.id,
});
const embed: SendableEmbed = bridgeData
@ -237,7 +237,7 @@ export default {
}
case "status": {
const link = await dbs.BRIDGE_CONFIG.findOne({
revolt: message.channel_id,
revolt: message.channelId,
});
if (!link)
@ -291,7 +291,7 @@ export default {
if (!newVal) {
const bridgeConfig = await dbs.BRIDGE_CONFIG.findOne({
revolt: message.channel_id,
revolt: message.channelId,
});
return await message.reply({
embeds: [
@ -316,10 +316,10 @@ export default {
}
await dbs.BRIDGE_CONFIG.update(
{ revolt: message.channel_id },
{ revolt: message.channelId },
{
$set: { [`config.${configKey}`]: newVal == "true" },
$setOnInsert: { revolt: message.channel_id },
$setOnInsert: { revolt: message.channelId },
},
{ upsert: true }
);

View File

@ -23,7 +23,7 @@ export default {
const login: FindOneResult<PendingLogin> = await dbs.PENDING_LOGINS.findOne({
code,
user: message.author_id,
user: message.authorId,
confirmed: false,
exchanged: false,
invalid: false,
@ -35,7 +35,7 @@ export default {
if (!login) return message.reply(`Unknown code. Make sure you're logged into the correct account.`);
if (login.requirePhishingConfirmation) {
logger.info(`Showing phishing warning to ${message.author_id}`);
logger.info(`Showing phishing warning to ${message.authorId}`);
await Promise.all([
message.reply(
`# If someone told you to run this, stop!\n` +

View File

@ -20,8 +20,8 @@ export default {
if (code.toLowerCase() == 'all') {
const [resA, resB] = await Promise.all([
dbs.PENDING_LOGINS.update({ user: message.author_id, invalid: false }, { $set: { invalid: true } }),
dbs.SESSIONS.update({ user: message.author_id, invalid: false }, { $set: { invalid: true } }),
dbs.PENDING_LOGINS.update({ user: message.authorId, invalid: false }, { $set: { invalid: true } }),
dbs.SESSIONS.update({ user: message.authorId, invalid: false }, { $set: { invalid: true } }),
]);
if (resA.nModified == 0 && resB.nModified == 0) return message.reply('There are no sessions to invalidate.');
@ -30,7 +30,7 @@ export default {
} else {
const loginAttempt = await dbs.PENDING_LOGINS.findOne({
code: code.toUpperCase(),
user: message.author_id,
user: message.authorId,
});
if (!loginAttempt || loginAttempt.invalid) {

View File

@ -1,7 +1,7 @@
import SimpleCommand from "../../../struct/commands/SimpleCommand";
import { isBotManager, NO_MANAGER_MSG, parseUser } from "../../util";
import { client, dbs } from "../../..";
import { User } from "@janderedev/revolt.js/dist/maps/Users";
import { User } from "revolt.js";
import MessageCommandContext from "../../../struct/MessageCommandContext";
import CommandCategory from "../../../struct/commands/CommandCategory";
@ -18,7 +18,7 @@ export default {
run: async (message: MessageCommandContext, args: string[]) => {
if (!await isBotManager(message)) return message.reply(NO_MANAGER_MSG);
let config = await dbs.SERVERS.findOne({ id: message.serverContext._id });
let config = await dbs.SERVERS.findOne({ id: message.serverContext.id });
let mods = config?.moderators ?? [];
let user: User|null;
@ -29,12 +29,12 @@ export default {
user = await parseUser(args[1]);
if (!user) return message.reply('I can\'t find that user.');
if (mods.indexOf(user._id) > -1) return message.reply('This user is already added as moderator.');
if (mods.indexOf(user.id) > -1) return message.reply('This user is already added as moderator.');
mods.push(user._id);
await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { moderators: mods } });
mods.push(user.id);
await dbs.SERVERS.update({ id: message.serverContext.id }, { $set: { moderators: mods } });
message.reply(`✅ Added [@${user.username}](/@${user._id}) to moderators.`);
message.reply(`✅ Added [@${user.username}](/@${user.id}) to moderators.`);
break;
case 'remove':
case 'delete':
@ -44,12 +44,12 @@ export default {
user = await parseUser(args[1]);
if (!user) return message.reply('I can\'t find that user.');
if (mods.indexOf(user._id) == -1) return message.reply('This user is not added as moderator.');
if (mods.indexOf(user.id) == -1) return message.reply('This user is not added as moderator.');
mods = mods.filter(a => a != user?._id);
await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { moderators: mods } });
mods = mods.filter(a => a != user?.id);
await dbs.SERVERS.update({ id: message.serverContext.id }, { $set: { moderators: mods } });
message.reply(`✅ Removed [@${user.username}](/@${user._id}) from moderators.`);
message.reply(`✅ Removed [@${user.username}](/@${user.id}) from moderators.`);
break;
case 'list':
case 'ls':

View File

@ -15,7 +15,7 @@ export default {
syntax: SYNTAX,
category: CommandCategory.Config,
run: async (message: MessageCommandContext, args: string[]) => {
let config = await dbs.SERVERS.findOne({ id: message.channel!.server_id! });
let config = await dbs.SERVERS.findOne({ id: message.channel!.serverId! });
switch(args[0]?.toLowerCase()) {
case 'set':
@ -31,7 +31,7 @@ export default {
return message.reply(val);
}
await dbs.SERVERS.update({ id: message.channel!.server_id! }, { $set: { 'prefix': newPrefix } });
await dbs.SERVERS.update({ id: message.channel!.serverId! }, { $set: { 'prefix': newPrefix } });
message.reply(`✅ Prefix has been changed from \`${oldPrefix}\` to \`${newPrefix}\`.\n${MENTION_TEXT}`);
break;
@ -45,7 +45,7 @@ export default {
if (!await isBotManager(message)) return message.reply(NO_MANAGER_MSG);
if (config?.prefix != null) {
await dbs.SERVERS.update({ id: message.channel!.server_id! }, { $set: { prefix: undefined } });
await dbs.SERVERS.update({ id: message.channel!.serverId! }, { $set: { prefix: undefined } });
}
message.reply(`✅ Prefix has been reset to the default: \`${DEFAULT_PREFIX}\`.`);

View File

@ -1,4 +1,4 @@
import { User } from "@janderedev/revolt.js/dist/maps/Users";
import { User } from "revolt.js";
import { client, dbs } from "../../..";
import CommandCategory from "../../../struct/commands/CommandCategory";
import SimpleCommand from "../../../struct/commands/SimpleCommand";
@ -15,8 +15,8 @@ export default {
syntax: SYNTAX,
category: CommandCategory.Config,
run: async (message: MessageCommandContext, args: string[]) => {
let config: ServerConfig|null = await dbs.SERVERS.findOne({ id: message.serverContext._id })
if (!config) config = { id: message.channel!.server_id! };
let config: ServerConfig|null = await dbs.SERVERS.findOne({ id: message.serverContext.id })
if (!config) config = { id: message.channel!.serverId! };
if (!config.whitelist) config.whitelist = { users: [], roles: [], managers: true }
if (!isBotManager(message)) return message.reply(NO_MANAGER_MSG);
@ -37,18 +37,18 @@ export default {
return message.reply('That role is already whitelisted.');
config.whitelist!.roles = [role, ...(config.whitelist!.roles ?? [])];
await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { whitelist: config.whitelist } });
await dbs.SERVERS.update({ id: message.serverContext.id }, { $set: { whitelist: config.whitelist } });
return message.reply(`Added role to whitelist!`);
}
user = await parseUser(args[1])
if (user == null) return message.reply('I can\'t find that user or role.');
if (user.bot != null) return message.reply('Bots cannot be whitelisted.');
if (config.whitelist!.users?.includes(user._id))
if (config.whitelist!.users?.includes(user.id))
return message.reply('That user is already whitelisted.');
config.whitelist!.users = [user._id, ...(config.whitelist!.users ?? [])];
await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { whitelist: config.whitelist } });
config.whitelist!.users = [user.id, ...(config.whitelist!.users ?? [])];
await dbs.SERVERS.update({ id: message.serverContext.id }, { $set: { whitelist: config.whitelist } });
return message.reply('Added user to whitelist!');
break;
case 'rm':
@ -67,17 +67,17 @@ export default {
return message.reply('That role is not whitelisted.');
config.whitelist!.roles = config.whitelist!.roles.filter(r => r != role);
await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { whitelist: config.whitelist } });
await dbs.SERVERS.update({ id: message.serverContext.id }, { $set: { whitelist: config.whitelist } });
return message.reply(`Removed role from whitelist!`);
}
user = await parseUser(args[1])
if (user == null) return message.reply('I can\'t find that user or role.');
if (!config.whitelist!.users?.includes(user._id))
if (!config.whitelist!.users?.includes(user.id))
return message.reply('That user is not whitelisted.');
config.whitelist!.users = config.whitelist!.users.filter(u => u != user?._id);
await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { whitelist: config.whitelist } });
config.whitelist!.users = config.whitelist!.users.filter(u => u != user?.id);
await dbs.SERVERS.update({ id: message.serverContext.id }, { $set: { whitelist: config.whitelist } });
return message.reply('Removed user from whitelist!');
break;
case 'l':
@ -98,7 +98,7 @@ export default {
if (config.whitelist.roles?.length) {
config.whitelist.roles
?.map(r => message.serverContext.roles?.[r]?.name || `Unknown role (${r})`)
?.map(r => message.serverContext.roles.get(r)?.name || `Unknown role (${r})`)
.forEach((r, index) => {
if (index < 15) str += `* ${r}\n`;
if (index == 15) str += `**${config!.whitelist!.roles!.length - 15} more role${config?.whitelist?.roles?.length == 16 ? '' : 's'}**\n`;

View File

@ -31,11 +31,11 @@ export default {
);
} else {
await message.reply(
`Server ID: ${message.channel?.server_id || 'None'}\n`
+ `Server context: ${message.serverContext._id} `
+ `(${message.serverContext._id == message.channel?.server_id ? 'This server' : message.serverContext.name})\n`
+ `Channel ID: ${message.channel_id}\n`
+ `User ID: ${message.author_id}`,
`Server ID: ${message.channel?.serverId || 'None'}\n`
+ `Server context: ${message.serverContext.id} `
+ `(${message.serverContext.id == message.channel?.serverId ? 'This server' : message.serverContext.name})\n`
+ `Channel ID: ${message.channelId}\n`
+ `User ID: ${message.authorId}`,
false
);
}

View File

@ -42,7 +42,7 @@ export default {
removeEmptyArgs: true,
category: CommandCategory.Misc,
run: async (message: MessageCommandContext, args: string[]) => {
const isBotOwner = ownerIDs.includes(message.author_id);
const isBotOwner = ownerIDs.includes(message.authorId!);
const prefix = DEFAULT_PREFIX; // TODO: fetch prefix from server config
let searchInput = args.shift()?.toLowerCase();
@ -50,7 +50,7 @@ export default {
let msg = `## AutoMod help\n` +
`Type **${prefix}help [category]** to view see all commands or **${prefix}help [command]** to learn more about a command.\n\n`
+ `### [Open Server Settings]`
+ `(<${process.env.WEB_UI_URL || 'https://automod.janderedev.xyz'}/dashboard/${message.channel?.server_id}>)\n\n`;
+ `(<${process.env.WEB_UI_URL || 'https://automod.janderedev.xyz'}/dashboard/${message.channel?.serverId}>)\n\n`;
let total = 0;

View File

@ -14,8 +14,8 @@ export default {
?.catch(console.error)
.then(msg => {
if (msg) msg.edit({ content: `## Ping Pong!\n`
+ `WS: \`${client.websocket.ping ?? '--'}ms\`\n`
+ `Msg: \`${Math.round(Date.now() - now) / 2}ms\`` });
+ `WS: \`${client.events.ping() ?? '--'}ms\`\n`
+ `Msg: \`${Math.round(Date.now() - now)}ms\`` });
});
}
} as SimpleCommand;

View File

@ -1,9 +1,11 @@
import { Member } from "@janderedev/revolt.js/dist/maps/Members";
import { ServerMember } from "revolt.js";
import axios from "axios";
import CommandCategory from "../../../struct/commands/CommandCategory";
import SimpleCommand from "../../../struct/commands/SimpleCommand";
import MessageCommandContext from "../../../struct/MessageCommandContext";
import { hasPerm, isModerator, NO_MANAGER_MSG, parseUser } from "../../util";
import { isModerator, NO_MANAGER_MSG, parseUser } from "../../util";
import AutomodClient from "../../../struct/AutomodClient";
import { client } from "../../..";
export default {
name: 'avatar',
@ -23,13 +25,13 @@ export default {
|| args[0]?.toLowerCase() == 'clear') {
// Clear server avatar
if (!message.member) return;
if (!hasPerm(message.member, 'RemoveAvatars')
if (!message.member.hasPermission(message.member.server!, 'RemoveAvatars')
&& !await isModerator(message)) return message.reply(NO_MANAGER_MSG);
if (!target.avatar) {
await message.reply(`\`@${targetUser.username}\` does not currently have an avatar set for this server.`);
} else {
await clearAvatar(target);
await target.edit({ remove: ['Avatar'] });
await message.reply(`\`@${targetUser.username}\`'s server avatar has been cleared.`);
}
} else {
@ -37,9 +39,9 @@ export default {
await message.reply(
`### \`@${targetUser.username}\`'s avatar\n` +
(targetUser.avatar ? `[\\[Global\\]](<${targetUser.generateAvatarURL()}>)` : '[No global avatar]') +
(targetUser.avatar ? `[\\[Global\\]](<${targetUser.avatarURL}>)` : '[No global avatar]') +
' | ' +
(target.avatar ? `[\\[Server\\]](<${target.generateAvatarURL()}>)` : '[No server avatar]')
(target.avatar ? `[\\[Server\\]](<${target.avatarURL}>)` : '[No server avatar]')
);
}
} catch(e) {
@ -48,17 +50,3 @@ export default {
}
}
} as SimpleCommand;
async function clearAvatar(member: Member) {
await axios.patch(
`${member.client.apiURL}/servers/${member.server!._id}/members/${member._id.user}`,
{
remove: [ "Avatar" ],
},
{
headers: {
'x-bot-token': process.env['BOT_TOKEN']!
}
}
);
}

View File

@ -13,6 +13,7 @@ import {
getDmChannel,
getMembers,
isModerator,
memberRanking,
NO_MANAGER_MSG,
parseUserOrId,
sanitizeMessageContent,
@ -23,7 +24,7 @@ import Day from "dayjs";
import RelativeTime from "dayjs/plugin/relativeTime";
import CommandCategory from "../../../struct/commands/CommandCategory";
import { SendableEmbed } from "revolt-api";
import { User } from "@janderedev/revolt.js";
import { User } from "revolt.js";
import logger from "../../logger";
Day.extend(RelativeTime);
@ -49,10 +50,10 @@ export default {
});
}
const userInput = !message.reply_ids?.length
const userInput = !message.replyIds?.length
? args.shift() || ""
: undefined;
if (!userInput && !message.reply_ids?.length)
if (!userInput && !message.replyIds?.length)
return message.reply({
embeds: [
embed(
@ -121,13 +122,13 @@ export default {
const embeds: SendableEmbed[] = [];
const handledUsers: string[] = [];
const targetUsers: User | { _id: string }[] = [];
const targetUsers: User | { id: string }[] = [];
const targetInput = dedupeArray(
message.reply_ids?.length
message.replyIds?.length
? (
await Promise.allSettled(
message.reply_ids.map((msg) =>
message.replyIds.map((msg) =>
message.channel?.fetchMessage(msg)
)
)
@ -154,10 +155,10 @@ export default {
}
// Silently ignore duplicates
if (handledUsers.includes(user._id)) continue;
handledUsers.push(user._id);
if (handledUsers.includes(user.id)) continue;
handledUsers.push(user.id);
if (user._id == message.author_id) {
if (user.id == message.authorId!) {
embeds.push(
embed(
"I recommend against banning yourself :yeahokayyy:",
@ -168,7 +169,7 @@ export default {
continue;
}
if (user._id == client.user!._id) {
if (user.id == client.user!.id) {
embeds.push(
embed(
"I'm not going to ban myself :flushee:",
@ -194,21 +195,21 @@ export default {
}
}
if (message.reply_ids?.length && targetUsers.length) {
if (message.replyIds?.length && targetUsers.length) {
let res = await yesNoMessage(
message.channel!,
message.author_id,
message.authorId!,
`This will ban the author${targetUsers.length > 1 ? 's' : ''} `
+ `of the message${message.reply_ids.length > 1 ? 's' : ''} you replied to.\n`
+ `of the message${message.replyIds.length > 1 ? 's' : ''} you replied to.\n`
+ `The following user${targetUsers.length > 1 ? 's' : ''} will be affected: `
+ `${targetUsers.map(u => `<@${u._id}>`).join(', ')}.\n`
+ `${targetUsers.map(u => `<@${u.id}>`).join(', ')}.\n`
+ `Are you sure?`,
'Confirm action'
);
if (!res) return;
}
const members = getMembers(message.serverContext._id);
const members = getMembers(message.serverContext.id);
for (const user of targetUsers) {
try {
@ -216,18 +217,18 @@ export default {
const infId = ulid();
const infraction: Infraction = {
_id: infId,
createdBy: message.author_id,
createdBy: message.authorId!,
date: Date.now(),
reason: reason || "No reason provided",
server: message.serverContext._id,
server: message.serverContext.id,
type: InfractionType.Manual,
user: user._id,
user: user.id,
actionType: "ban",
expires: Infinity,
};
const { userWarnCount } = await storeInfraction(infraction);
const member = members.find((m) => m._id.user == user._id);
const member = members.find((m) => m.id.user == user.id);
if (
member &&
@ -244,11 +245,11 @@ export default {
continue;
}
if (member && !member.bannable) {
if (member && !memberRanking(member).bannable) {
embeds.push(
embed(
`I don't have permission to ban \`${
member?.user?.username || user._id
member?.user?.username || user.id
}\`.`,
null,
EmbedColor.SoftError
@ -281,11 +282,11 @@ export default {
}
}
await message.serverContext.banUser(user._id, {
await message.serverContext.banUser(user.id, {
reason:
reason +
` (by ${await fetchUsername(message.author_id)} ${
message.author_id
` (by ${await fetchUsername(message.authorId!)} ${
message.authorId
})`,
});
@ -293,7 +294,7 @@ export default {
"ban",
message.serverContext,
message.member!,
user._id,
user.id,
reason,
infraction._id,
`Ban duration: **Permanent**`
@ -305,7 +306,7 @@ export default {
}`,
icon_url:
user instanceof User
? user.generateAvatarURL()
? user.avatarURL
: undefined,
colour: EmbedColor.Success,
description:
@ -314,8 +315,8 @@ export default {
? "**the first infraction**"
: `infraction number **${userWarnCount}**`
}` +
` for ${await fetchUsername(user._id)}.\n` +
`**User ID:** \`${user._id}\`\n` +
` for ${await fetchUsername(user.id)}.\n` +
`**User ID:** \`${user.id}\`\n` +
`**Infraction ID:** \`${infraction._id}\`\n` +
`**Reason:** \`${infraction.reason}\``,
});
@ -325,14 +326,14 @@ export default {
const infId = ulid();
const infraction: Infraction = {
_id: infId,
createdBy: message.author_id,
createdBy: message.authorId!,
date: Date.now(),
reason:
(reason || "No reason provided") +
` (${durationStr})`,
server: message.serverContext._id,
server: message.serverContext.id,
type: InfractionType.Manual,
user: user._id,
user: user.id,
actionType: "ban",
expires: banUntil,
};
@ -362,26 +363,26 @@ export default {
}
}
await message.serverContext.banUser(user._id, {
await message.serverContext.banUser(user.id, {
reason:
reason +
` (by ${await fetchUsername(message.author_id)} ${
message.author_id
` (by ${await fetchUsername(message.authorId!)} ${
message.authorId
}) (${durationStr})`,
});
await Promise.all([
storeTempBan({
id: infId,
bannedUser: user._id,
server: message.serverContext._id,
bannedUser: user.id,
server: message.serverContext.id,
until: banUntil,
}),
logModAction(
"ban",
message.serverContext,
message.member!,
user._id,
user.id,
reason,
infraction._id,
`Ban duration: **${banDurationFancy}**`
@ -392,7 +393,7 @@ export default {
title: `User temporarily banned`,
icon_url:
user instanceof User
? user.generateAvatarURL()
? user.avatarURL
: undefined,
colour: EmbedColor.Success,
description:
@ -401,9 +402,9 @@ export default {
? "**the first infraction**"
: `infraction number **${userWarnCount}**`
}` +
` for ${await fetchUsername(user._id)}.\n` +
` for ${await fetchUsername(user.id)}.\n` +
`**Ban duration:** ${banDurationFancy}\n` +
`**User ID:** \`${user._id}\`\n` +
`**User ID:** \`${user.id}\`\n` +
`**Infraction ID:** \`${infraction._id}\`\n` +
`**Reason:** \`${infraction.reason}\``,
});
@ -413,8 +414,8 @@ export default {
embeds.push(
embed(
`Failed to ban target \`${await fetchUsername(
user._id,
user._id
user.id,
user.id
)}\`: ${e}`,
"Failed to ban: An error has occurred",
EmbedColor.Error

View File

@ -1,4 +1,4 @@
import { User } from "@janderedev/revolt.js";
import { User } from "revolt.js";
import { SendableEmbed } from "revolt-api";
import { ulid } from "ulid";
import { client } from "../../../";
@ -39,10 +39,10 @@ export default {
);
}
const userInput = !message.reply_ids?.length
const userInput = !message.replyIds?.length
? args.shift() || ""
: undefined;
if (!userInput && !message.reply_ids?.length)
if (!userInput && !message.replyIds?.length)
return message.reply({
embeds: [
embed(
@ -72,19 +72,19 @@ export default {
const embeds: SendableEmbed[] = [];
const handledUsers: string[] = [];
const targetUsers: User | { _id: string }[] = [];
const targetUsers: User | { id: string }[] = [];
const targetInput = dedupeArray(
message.reply_ids?.length
message.replyIds?.length
? (
await Promise.allSettled(
message.reply_ids.map((msg) =>
message.replyIds.map((msg) =>
message.channel?.fetchMessage(msg)
)
)
)
.filter((m) => m.status == "fulfilled")
.map((m) => (m as any).value.author_id)
.map((m) => (m as any).value.authorId)
: userInput!.split(",")
);
@ -105,10 +105,10 @@ export default {
}
// Silently ignore duplicates
if (handledUsers.includes(user._id)) continue;
handledUsers.push(user._id);
if (handledUsers.includes(user.id)) continue;
handledUsers.push(user.id);
if (user._id == message.author_id) {
if (user.id == message.authorId) {
embeds.push(
embed(
"You might want to avoid kicking yourself...",
@ -119,7 +119,7 @@ export default {
continue;
}
if (user._id == client.user!._id) {
if (user.id == client.user!.id) {
embeds.push(
embed(
"I won't allow you to get rid of me this easily :trol:",
@ -145,30 +145,30 @@ export default {
}
}
if (message.reply_ids?.length && targetUsers.length) {
if (message.replyIds?.length && targetUsers.length) {
let res = await yesNoMessage(
message.channel!,
message.author_id,
message.authorId!,
`This will kick the author${targetUsers.length > 1 ? 's' : ''} `
+ `of the message${message.reply_ids.length > 1 ? 's' : ''} you replied to.\n`
+ `of the message${message.replyIds.length > 1 ? 's' : ''} you replied to.\n`
+ `The following user${targetUsers.length > 1 ? 's' : ''} will be affected: `
+ `${targetUsers.map(u => `<@${u._id}>`).join(', ')}.\n`
+ `${targetUsers.map(u => `<@${u.id}>`).join(', ')}.\n`
+ `Are you sure?`,
'Confirm action'
);
if (!res) return;
}
const members = getMembers(message.serverContext._id);
const members = getMembers(message.serverContext.id);
for (const user of targetUsers) {
try {
const member = members.find((m) => m._id.user == user._id);
const member = members.find((m) => m.id.user == user.id);
if (!member) {
embeds.push(
embed(
`\`${await fetchUsername(
user._id
user.id
)}\` is not a member of this server.`
)
);
@ -178,12 +178,12 @@ export default {
let infId = ulid();
let infraction: Infraction = {
_id: infId,
createdBy: message.author_id,
createdBy: message.authorId!,
date: Date.now(),
reason: reason || "No reason provided",
server: message.serverContext._id,
server: message.serverContext.id,
type: InfractionType.Manual,
user: user._id,
user: user.id,
actionType: "kick",
};
@ -214,7 +214,7 @@ export default {
"kick",
message.serverContext,
message.member!,
user._id,
user.id,
reason,
infraction._id
),
@ -225,7 +225,7 @@ export default {
title: `User kicked`,
icon_url:
user instanceof User
? user.generateAvatarURL()
? user.avatarURL
: undefined,
colour: EmbedColor.Success,
description:
@ -234,8 +234,8 @@ export default {
? "**the first infraction**"
: `infraction number **${userWarnCount}**`
}` +
` for ${await fetchUsername(user._id)}.\n` +
`**User ID:** \`${user._id}\`\n` +
` for ${await fetchUsername(user.id)}.\n` +
`**User ID:** \`${user.id}\`\n` +
`**Infraction ID:** \`${infraction._id}\`\n` +
`**Reason:** \`${infraction.reason}\``,
});
@ -243,7 +243,7 @@ export default {
embeds.push(
embed(
`Failed to kick user ${await fetchUsername(
user._id
user.id
)}: ${e}`,
"Failed to kick user",
EmbedColor.Error

View File

@ -1,9 +1,10 @@
import { Member } from "@janderedev/revolt.js/dist/maps/Members";
import { ServerMember } from "revolt.js";
import axios from "axios";
import CommandCategory from "../../../struct/commands/CommandCategory";
import SimpleCommand from "../../../struct/commands/SimpleCommand";
import MessageCommandContext from "../../../struct/MessageCommandContext";
import { hasPerm, isModerator, NO_MANAGER_MSG, parseUser } from "../../util";
import { isModerator, NO_MANAGER_MSG, parseUser } from "../../util";
import { client } from "../../..";
export default {
name: 'nick',
@ -13,7 +14,7 @@ export default {
run: async (message: MessageCommandContext, args: string[]) => {
try {
if (!message.member) return;
if (!hasPerm(message.member, 'ManageNicknames')
if (!message.member.hasPermission(message.member.server!, 'ManageNicknames')
&& !await isModerator(message)) return message.reply(NO_MANAGER_MSG);
const targetStr = args.shift();
@ -42,9 +43,9 @@ export default {
}
} as SimpleCommand;
async function setNick(member: Member, newName: string|null) {
async function setNick(member: ServerMember, newName: string|null) {
await axios.patch(
`${member.client.apiURL}/servers/${member.server!._id}/members/${member._id.user}`,
`${client.options.baseURL}/servers/${member.server!.id}/members/${member.id.user}`,
{
nickname: newName || undefined,
remove: !newName ? [ "Nickname" ] : undefined,

View File

@ -1,5 +1,5 @@
import SimpleCommand from "../../../struct/commands/SimpleCommand";
import { Message } from "@janderedev/revolt.js/dist/maps/Messages";
import { Message } from "revolt.js";
import { decodeTime } from 'ulid';
import { isModerator, parseUserOrId } from "../../util";
import MessageCommandContext from "../../../struct/MessageCommandContext";
@ -31,7 +31,7 @@ export default {
messages = await message.channel!.fetchMessages({
limit: amount,
before: message._id,
before: message.id,
});
}
// delete messages between [id] and [id]
@ -49,7 +49,7 @@ export default {
]);
// Make sure the msg1 and msg2 are in the correct order
if (decodeTime(msg1._id) < decodeTime(msg2._id)) {
if (decodeTime(msg1.id) < decodeTime(msg2.id)) {
[msg1, msg2] = [msg2, msg1];
}
@ -60,17 +60,17 @@ export default {
sort: "Latest",
});
if (!messages.find((m) => m._id == msg1._id))
if (!messages.find((m) => m.id == msg1.id))
messages = [msg1, ...messages];
if (!messages.find((m) => m._id == msg2._id))
if (!messages.find((m) => m.id == msg2.id))
messages = [...messages, msg2];
// Discard messages that are not in the selected range,
// because Revolt returns more messages than expected for some reason
messages = messages.filter(
(m) =>
decodeTime(m._id) <= decodeTime(id2) &&
decodeTime(m._id) >= decodeTime(id1)
decodeTime(m.id) <= decodeTime(id2) &&
decodeTime(m.id) >= decodeTime(id1)
);
}
// allow single messages too, because why not?
@ -92,11 +92,11 @@ export default {
);
messages = messages.filter((m) =>
users.find((u) => u?._id == m.author_id)
users.find((u) => u?.id == m.authorId)
);
}
await message.channel?.deleteMessages(messages.map((m) => m._id));
await message.channel?.deleteMessages(messages.map((m) => m.id));
const replyMsg = await message.channel
?.sendMessage({
@ -107,8 +107,8 @@ export default {
setTimeout(async () => {
try {
await message.channel?.deleteMessages([
replyMsg!._id,
message._id,
replyMsg!.id,
message.id,
]);
} catch (e) {
console.error(e);

View File

@ -45,13 +45,13 @@ export default {
const duration = parseTimeInput(args[1] ?? '');
if (!duration) {
await client.api.patch(`/servers/${message.serverContext._id}/members/${target._id}` as '/servers/{server}/members/{target}', {
await client.api.patch(`/servers/${message.serverContext.id}/members/${target.id}` as '/servers/{server}/members/{target}', {
timeout: new Date(0).toISOString()
} as any);
await message.reply(`Timeout cleared on @${target.username}`);
}
else {
await client.api.patch(`/servers/${message.serverContext._id}/members/${target._id}` as '/servers/{server}/members/{target}', {
await client.api.patch(`/servers/${message.serverContext.id}/members/${target.id}` as '/servers/{server}/members/{target}', {
timeout: new Date(Date.now() + duration).toISOString()
} as any);
await message.reply(`Successfully timed out @${target.username}`);

View File

@ -18,7 +18,7 @@ export default {
}
let checkTempBans = async (id: string): Promise<number> => {
let tempbans = await dbs.TEMPBANS.find({ bannedUser: id, server: message.serverContext._id });
let tempbans = await dbs.TEMPBANS.find({ bannedUser: id, server: message.serverContext.id });
if (tempbans.length > 0) {
for (const ban of tempbans) {
await removeTempBan(ban.id);
@ -37,7 +37,7 @@ export default {
let id: string|undefined = undefined;
try {
id = (await parseUser(target))?._id;
id = (await parseUser(target))?.id;
} catch(e) {
if (USER_MENTION_REGEX.test(target)) {
id = target
@ -46,8 +46,8 @@ export default {
} else if (ULID_REGEX.test(target)) {
id = target;
} else {
let user = bans.users.find(u => u.username.toLowerCase() == target.toLowerCase());
if (user) id = user._id;
let ban = bans.find(b => b.user?.username.toLowerCase() == target.toLowerCase());
if (ban) id = ban.id.user;
}
}
@ -58,9 +58,9 @@ export default {
} else return msg.edit({ content: 'The user could not be found.' });
}
let bannedUser = bans.users.find(u => u._id == id);
let ban = bans.find(b => b.id.user == id);
if (!bannedUser) {
if (!ban) {
let tempnum = await checkTempBans(id);
if (tempnum > 0) {
return msg.edit({ content: 'This user is not banned, but leftover database entries have been cleaned up.' });
@ -68,12 +68,12 @@ export default {
}
await Promise.all([
msg.edit({ content: `User found: @${bannedUser.username}, unbanning...` }),
msg.edit({ content: `User found: @${ban.user?.username ?? ban.id.user}, unbanning...` }),
message.serverContext.unbanUser(id),
checkTempBans(id),
]);
await msg.edit({ content: `@${bannedUser.username} has been unbanned.` });
await msg.edit({ content: `@${ban.user?.username ?? ban.id.user} has been unbanned.` });
} catch(e) { console.error(e) }
}
} as SimpleCommand;

View File

@ -24,7 +24,7 @@ export default {
category: CommandCategory.Moderation,
run: async (message: MessageCommandContext, args: string[]) => {
try {
const serverConfig = await dbs.SERVERS.findOne({ id: message.serverContext._id });
const serverConfig = await dbs.SERVERS.findOne({ id: message.serverContext.id });
if (!serverConfig?.votekick?.enabled) return message.reply('Vote kick is not enabled for this server.');
if (!message.member!.roles?.filter(r => serverConfig.votekick?.trustedRoles.includes(r)).length
&& !(await isModerator(message))) {
@ -47,23 +47,23 @@ export default {
const vote: VoteEntry = {
id: ulid(),
target: target._id,
user: message.author_id,
server: message.serverContext._id,
target: target.id,
user: message.authorId!,
server: message.serverContext.id,
time: Date.now(),
ignore: false,
}
const votes = await dbs.VOTEKICKS.find({
server: message.serverContext._id,
target: target._id,
server: message.serverContext.id,
target: target.id,
time: {
$gt: Date.now() - 1000 * 60 * 30, // Last 30 minutes
},
ignore: false,
});
if (votes.find(v => v.user == message.author_id)) return message.reply('You can\'t vote twice for this user.');
if (votes.find(v => v.user == message.authorId)) return message.reply('You can\'t vote twice for this user.');
await dbs.VOTEKICKS.insert(vote);
votes.push({ _id: '' as any, ...vote });
@ -72,7 +72,7 @@ export default {
"votekick",
message.serverContext,
message.member!,
target._id,
target.id,
`n/a`,
vote.id,
`This is vote ${votes.length}/${serverConfig.votekick.votesRequired} for this user.`,
@ -82,15 +82,15 @@ export default {
if (serverConfig.votekick.banDuration == -1) {
targetMember.kick();
} else if (serverConfig.votekick.banDuration == 0) {
message.serverContext.banUser(target._id, { reason: 'Automatic permanent ban triggered by /votekick' });
message.serverContext.banUser(target.id, { reason: 'Automatic permanent ban triggered by /votekick' });
} else {
message.serverContext.banUser(target._id, { reason: `Automatic temporary ban triggered by /votekick `
message.serverContext.banUser(target.id, { reason: `Automatic temporary ban triggered by /votekick `
+ `(${serverConfig.votekick.banDuration} minutes)` });
await storeTempBan({
id: ulid(),
bannedUser: target._id,
server: message.serverContext._id,
bannedUser: target.id,
server: message.serverContext.id,
until: Date.now() + (1000 * 60 * serverConfig.votekick.banDuration),
});
}
@ -99,8 +99,8 @@ export default {
+ `Banned @${target.username} for ${serverConfig.votekick.banDuration} minutes.`); // Todo: display ban duration properly (Permban, kick, etc)
await dbs.VOTEKICKS.update({
server: message.serverContext._id,
target: target._id,
server: message.serverContext.id,
target: target.id,
time: { $gt: Date.now() - 1000 * 60 * 30 },
ignore: false,
}, { $set: { ignore: true } });

View File

@ -6,7 +6,7 @@ import InfractionType from "automod/dist/types/antispam/InfractionType";
import { fetchUsername, logModAction } from "../../modules/mod_logs";
import CommandCategory from "../../../struct/commands/CommandCategory";
import { SendableEmbed } from "revolt-api";
import { User } from "@janderedev/revolt.js";
import { User } from "revolt.js";
import logger from "../../logger";
export default {
@ -19,7 +19,7 @@ export default {
if (!await isModerator(message)) return message.reply(NO_MANAGER_MSG);
const userInput = args.shift() || '';
if (!userInput && !message.reply_ids?.length) return message.reply({ embeds: [
if (!userInput && !message.replyIds?.length) return message.reply({ embeds: [
embed(
`Please specify one or more users by replying to their message while running this command or ` +
`by specifying a comma-separated list of usernames.`,
@ -38,12 +38,12 @@ export default {
const embeds: SendableEmbed[] = [];
const handledUsers: string[] = [];
const targetUsers: User|{ _id: string }[] = [];
const targetUsers: User|{ id: string }[] = [];
const targetInput = dedupeArray(
// Replied messages
(await Promise.allSettled(
(message.reply_ids ?? []).map(msg => message.channel?.fetchMessage(msg))
(message.replyIds ?? []).map(msg => message.channel?.fetchMessage(msg))
))
.filter(m => m.status == 'fulfilled').map(m => (m as any).value.author_id),
// Provided users
@ -54,7 +54,7 @@ export default {
try {
let user = await parseUserOrId(userStr);
if (!user) {
if (message.reply_ids?.length && userStr == userInput) {
if (message.replyIds?.length && userStr == userInput) {
reason = reason ? `${userInput} ${reason}` : userInput;
}
else {
@ -64,8 +64,8 @@ export default {
}
// Silently ignore duplicates
if (handledUsers.includes(user._id)) continue;
handledUsers.push(user._id);
if (handledUsers.includes(user.id)) continue;
handledUsers.push(user.id);
if ((user as any)?.bot != null) return await message.reply({ embeds: [
embed('You cannot warn bots.', null, EmbedColor.SoftError)
@ -85,10 +85,10 @@ export default {
for (const user of targetUsers) {
let infraction = {
_id: ulid(),
createdBy: message.author_id,
user: user._id,
createdBy: message.authorId,
user: user.id,
reason: reason || 'No reason provided',
server: message.serverContext._id,
server: message.serverContext.id,
type: InfractionType.Manual,
date: Date.now(),
} as Infraction;
@ -99,7 +99,7 @@ export default {
'warn',
message.serverContext,
message.member!,
user._id,
user.id,
reason || 'No reason provided',
infraction._id,
`This is warn number ${userWarnCount} for this user.`
@ -123,10 +123,10 @@ export default {
embeds.push({
title: `User warned`,
icon_url: user instanceof User ? user.generateAvatarURL() : undefined,
icon_url: user instanceof User ? user.avatarURL : undefined,
colour: EmbedColor.Success,
description: `This is ${userWarnCount == 1 ? '**the first warn**' : `warn number **${userWarnCount}**`}` +
` for ${await fetchUsername(user._id)}.\n` +
` for ${await fetchUsername(user.id)}.\n` +
`**Infraction ID:** \`${infraction._id}\`\n` +
`**Reason:** \`${infraction.reason}\``
});

View File

@ -23,7 +23,7 @@ export default {
category: CommandCategory.Moderation,
run: async (message: MessageCommandContext, args: string[]) => {
let infractions: Array<Infraction> = await dbs.INFRACTIONS.find({
server: message.serverContext._id,
server: message.serverContext.id,
});
let userInfractions: Map<string, Infraction[]> = new Map();
infractions.forEach(i => {
@ -56,7 +56,7 @@ export default {
if (!id) return message.reply('No infraction ID provided.');
let inf = await dbs.INFRACTIONS.findOneAndDelete({
_id: { $eq: id.toUpperCase() },
server: message.serverContext._id
server: message.serverContext.id
});
if (!inf) return message.reply('I can\'t find that ID.');
@ -69,18 +69,18 @@ export default {
break;
default:
let user = await parseUserOrId(args[0]);
if (!user?._id) return message.reply('I can\'t find this user.');
if (!user?.id) return message.reply('I can\'t find this user.');
if (user._id != message.author_id && !await isModerator(message)) return message.reply(NO_MANAGER_MSG);
if (user.id != message.authorId && !await isModerator(message)) return message.reply(NO_MANAGER_MSG);
const infs = userInfractions.get(user._id);
const userConfig = await dbs.USERS.findOne({ id: user._id });
const infs = userInfractions.get(user.id);
const userConfig = await dbs.USERS.findOne({ id: user.id });
if (!infs) return message.reply(`There are no infractions stored for \`${await fetchUsername(user._id)}\`.`
if (!infs) return message.reply(`There are no infractions stored for \`${await fetchUsername(user.id)}\`.`
+ (userConfig?.globalBlacklist ? '\n' + GLOBAL_BLACKLIST_TEXT(userConfig.blacklistReason) : ''), false);
else {
let msg = `## ${infs.length} infractions stored for ${await fetchUsername(user._id)}\n`;
let msg = `## ${infs.length} infractions stored for ${await fetchUsername(user.id)}\n`;
if (userConfig?.globalBlacklist) {
msg += GLOBAL_BLACKLIST_TEXT(userConfig.blacklistReason);
@ -108,7 +108,7 @@ export default {
if (attachSpreadsheet) {
try {
let csv_data = [
[`Warns for ${await fetchUsername(user._id)} (${user._id}) - ${Day().toString()}`],
[`Warns for ${await fetchUsername(user.id)} (${user.id}) - ${Day().toString()}`],
[],
['Date', 'Reason', 'Created By', 'Type', 'Action Type', 'ID'],
];
@ -127,7 +127,7 @@ export default {
let sheet = Xlsx.utils.aoa_to_sheet(csv_data);
let csv = Xlsx.utils.sheet_to_csv(sheet);
message.reply({ content: msg, attachments: [ await uploadFile(csv, `${user._id}.csv`) ] }, false);
message.reply({ content: msg, attachments: [ await uploadFile(csv, `${user.id}.csv`) ] }, false);
} catch(e) {
console.error(e);
message.reply(msg, false);

View File

@ -29,7 +29,7 @@ async function adminBotLog(data: { message: string, type: 'INFO'|'WARN'|'ERROR'
await client?.send({
embeds: [ embed ],
username: bot.user?.username,
avatarURL: bot.user?.generateAvatarURL({ size: 128 })
avatarURL: bot.user?.avatarURL,
});
} catch(e) {
logger.error(`Failed to log: ${e}`);

View File

@ -1,4 +1,4 @@
import { Message } from "@janderedev/revolt.js/dist/maps/Messages";
import { Message } from "revolt.js";
import { ulid } from "ulid";
import { client, dbs } from "../..";
import AntispamRule from "automod/dist/types/antispam/AntispamRule";
@ -23,7 +23,7 @@ const SENT_FILTER_MESSAGE: string[] = [];
*/
async function antispam(message: Message): Promise<boolean> {
try {
let serverRules = await dbs.SERVERS.findOne({ id: message.channel!.server_id! });
let serverRules = await dbs.SERVERS.findOne({ id: message.channel!.serverId! });
if (!serverRules?.automodSettings) return true;
let ruleTriggered = false;
@ -34,14 +34,14 @@ async function antispam(message: Message): Promise<boolean> {
}
if (message.author?.bot != null) break;
if (serverRules.whitelist?.users?.includes(message.author_id)) break;
if (serverRules.whitelist?.users?.includes(message.authorId!)) break;
if (message.member?.roles?.filter(r => serverRules!.whitelist?.roles?.includes(r)).length) break;
if (serverRules.whitelist?.managers !== false && await isModerator(message, false)) break;
if (rule.channels?.length && rule.channels.indexOf(message.channel_id) == -1) break;
if (rule.channels?.length && rule.channels.indexOf(message.channelId) == -1) break;
let store = msgCountStore.get(rule.id)!;
if (!store.users[message.channel_id]) store.users[message.channel_id] = {}
let userStore = store.users[message.channel_id];
if (!store.users[message.channelId]) store.users[message.channelId] = {}
let userStore = store.users[message.channelId];
if (!userStore.count) userStore.count = 1;
else userStore.count++;
@ -75,9 +75,9 @@ async function antispam(message: Message): Promise<boolean> {
createdBy: null,
date: Date.now(),
reason: `Automatic moderation rule triggered: More than ${rule.max_msg} messages per ${rule.timeframe} seconds.`,
server: message.channel?.server_id,
server: message.channel?.serverId,
type: InfractionType.Automatic,
user: message.author_id,
user: message.authorId,
} as Infraction;
message.channel?.sendMessage('## User has been warned.\n\u200b\n' + getWarnMsg(rule, message))
@ -107,8 +107,8 @@ async function antispam(message: Message): Promise<boolean> {
function getWarnMsg(rule: AntispamRule, message: Message) {
if (rule.message != null) {
return rule.message
.replace(new RegExp('{{userid}}', 'gi'), message.author_id);
} else return `<@${message.author_id}>, please stop spamming.`;
.replace(new RegExp('{{userid}}', 'gi'), message.authorId!);
} else return `<@${message.authorId}>, please stop spamming.`;
}
/**
@ -133,9 +133,9 @@ async function wordFilterCheck(message: Message, config: ServerConfig) {
createdBy: null,
date: Date.now(),
reason: 'Word filter triggered',
server: message.channel!.server_id!,
server: message.channel!.serverId!,
type: InfractionType.Automatic,
user: message.author_id,
user: message.authorId!,
}
await storeInfraction(infraction);
@ -155,14 +155,14 @@ async function wordFilterCheck(message: Message, config: ServerConfig) {
}
case 'DELETE': {
if (message.channel?.havePermission('ManageMessages')) {
const key = `${message.author_id}:${message.channel_id}`;
const key = `${message.authorId}:${message.channelId}`;
await message.delete();
if (!SENT_FILTER_MESSAGE.includes(key)) {
SENT_FILTER_MESSAGE.push(key);
setTimeout(() => SENT_FILTER_MESSAGE.splice(SENT_FILTER_MESSAGE.indexOf(key), 1), 30000);
await message.channel.sendMessage((config.wordlistAction.message || WORDLIST_DEFAULT_MESSAGE)
.replaceAll('{{user_id}}', message.author_id));
.replaceAll('{{user_id}}', message.authorId!));
}
}
}
@ -171,7 +171,7 @@ async function wordFilterCheck(message: Message, config: ServerConfig) {
if (!config.logs?.modAction) break;
await sendLogMessage(config.logs.modAction, {
title: 'Message triggered word filter',
description: `**Author:** @${message.author?.username} (${message.author_id})\n` +
description: `**Author:** @${message.author?.username} (${message.authorId})\n` +
`**Action:** ${config.wordlistAction?.action || 'LOG'}\n` +
`#### Content\n` +
`>${sanitizeMessageContent(message.content.substring(0, 1000)).trim().replace(/\n/g, '\n>')}`,
@ -259,7 +259,7 @@ const notifyPublicServers = async () => {
.filter(server => server.discoverable);
const res = await dbs.SERVERS.find({
id: { $in: servers.map(s => s._id) },
id: { $in: servers.map(s => s.id) },
discoverAutospamNotify: { $in: [ undefined, false ] },
});
@ -273,7 +273,7 @@ const notifyPublicServers = async () => {
);
const server = client.servers.get(serverConfig.id);
const channel = await getDmChannel(server!.owner);
const channel = await getDmChannel(server!.ownerId);
await channel.sendMessage(`Hi there,
It looks like your server, **${sanitizeMessageContent(server!.name).trim()}**, has been added to server discovery. Congratulations!

View File

@ -1,5 +1,5 @@
import { Member } from "@janderedev/revolt.js/dist/maps/Members";
import { User } from "@janderedev/revolt.js/dist/maps/Users";
import { ServerMember } from "revolt.js";
import { User } from "revolt.js";
import { client, dbs } from "../../..";
import ServerConfig from "automod/dist/types/ServerConfig";
import { getPermissionLevel } from "../../util";
@ -37,7 +37,7 @@ wsEvents.on('req:getUserServerDetails', async (data: ReqData, cb: (data: WSRespo
return;
}
let member: Member;
let member: ServerMember;
try {
member = await server.fetchMember(user);
} catch(e) {
@ -45,7 +45,7 @@ wsEvents.on('req:getUserServerDetails', async (data: ReqData, cb: (data: WSRespo
return;
}
const serverConfig = await dbs.SERVERS.findOne({ id: server._id });
const serverConfig = await dbs.SERVERS.findOne({ id: server.id });
// todo: remove unwanted keys from server config
@ -60,28 +60,28 @@ wsEvents.on('req:getUserServerDetails', async (data: ReqData, cb: (data: WSRespo
const users = await Promise.allSettled([
...(serverConfig?.botManagers?.map(u => fetchUser(u)) ?? []),
...(serverConfig?.moderators?.map(u => fetchUser(u)) ?? []),
fetchUser(user._id),
fetchUser(user.id),
]);
const response: ServerDetails = {
id: server._id,
id: server.id,
name: server.name,
perms: await getPermissionLevel(member, server),
description: server.description ?? undefined,
bannerURL: server.generateBannerURL(),
iconURL: server.generateIconURL(),
bannerURL: server.bannerURL,
iconURL: server.iconURL,
serverConfig: (serverConfig as ServerConfig|undefined),
users: users.map(
u => u.status == 'fulfilled'
? { id: u.value._id, avatarURL: u.value.generateAvatarURL(), username: u.value.username }
? { id: u.value.id, avatarURL: u.value.avatarURL, username: u.value.username }
: { id: u.reason }
),
channels: server.channels.filter(c => c != undefined).map(c => ({
id: c!._id,
id: c!.id,
name: c!.name ?? '',
nsfw: c!.nsfw ?? false,
type: c!.channel_type == 'VoiceChannel' ? 'VOICE' : 'TEXT',
icon: c!.generateIconURL(),
nsfw: false, // todo?
type: c!.type == 'VoiceChannel' ? 'VOICE' : 'TEXT',
icon: c!.iconURL,
})),
dmOnKick: serverConfig?.dmOnKick,
dmOnWarn: serverConfig?.dmOnWarn,

View File

@ -1,4 +1,4 @@
import { User } from '@janderedev/revolt.js/dist/maps/Users';
import { User } from 'revolt.js';
import { client } from '../../..';
import { getMutualServers, getPermissionLevel } from '../../util';
import { wsEvents, WSResponse } from '../api_communication';
@ -27,11 +27,11 @@ wsEvents.on('req:getUserServers', async (data: ReqData, cb: (data: WSResponse) =
if (!server) return reject('Server not found');
const perms = await getPermissionLevel(user, server);
resolve({
id: server._id,
id: server.id,
perms,
name: server.name,
bannerURL: server.generateBannerURL(),
iconURL: server.generateIconURL({}),
bannerURL: server.bannerURL,
iconURL: server.iconURL,
});
} catch(e) {
console.error(e);

View File

@ -1,4 +1,4 @@
import { User } from "@janderedev/revolt.js/dist/maps/Users";
import { User } from "revolt.js";
import { client } from "../../..";
import { getPermissionLevel, parseUser } from "../../util";
import { wsEvents, WSResponse } from "../api_communication";
@ -30,7 +30,7 @@ wsEvents.on('req:getUser', async (data: { user: string }, cb: (data: WSResponse)
if (!user)
cb({ success: false, statusCode: 404, error: 'User could not be found' });
else
cb({ success: true, user: { id: user._id, username: user.username, avatarURL: user.generateAvatarURL() } as APIUser });
cb({ success: true, user: { id: user.id, username: user.username, avatarURL: user.avatarURL } as APIUser });
} catch(e) {
console.error(e);
cb({ success: false, error: `${e}` });

View File

@ -102,18 +102,18 @@ wsEvents.on('req:requestLogin', async (data: any, cb: (data: WSResponse) => void
let code: string|null = null;
while (!code) {
const c = crypto.randomBytes(8).toString('hex');
const found = await dbs.PENDING_LOGINS.find({ code: c, user: user._id, confirmed: false });
const found = await dbs.PENDING_LOGINS.find({ code: c, user: user.id, confirmed: false });
if (found.length > 0) continue;
code = c.substring(0, 8).toUpperCase();
}
logger.info(`Attempted login for user ${user._id} with code ${code}`);
logger.info(`Attempted login for user ${user.id} with code ${code}`);
const nonce = ulid();
const [previousLogins, currentValidLogins] = await Promise.all([
dbs.PENDING_LOGINS.find({ user: user._id, confirmed: true }),
dbs.PENDING_LOGINS.find({ user: user._id, confirmed: false, expires: { $gt: Date.now() } }),
dbs.PENDING_LOGINS.find({ user: user.id, confirmed: true }),
dbs.PENDING_LOGINS.find({ user: user.id, confirmed: false, expires: { $gt: Date.now() } }),
]);
if (currentValidLogins.length >= 5) return cb({ success: false, statusCode: 403, error: 'Too many pending logins. Try again later.' });
@ -121,7 +121,7 @@ wsEvents.on('req:requestLogin', async (data: any, cb: (data: WSResponse) => void
await dbs.PENDING_LOGINS.insert({
code,
expires: Date.now() + (1000 * 60 * 15), // Expires in 15 minutes
user: user._id,
user: user.id,
nonce: nonce,
confirmed: false,
requirePhishingConfirmation: previousLogins.length == 0,
@ -129,7 +129,7 @@ wsEvents.on('req:requestLogin', async (data: any, cb: (data: WSResponse) => void
invalid: false,
} as PendingLogin);
cb({ success: true, uid: user._id, nonce, code });
cb({ success: true, uid: user.id, nonce, code });
} catch(e) {
console.error(e);
cb({ success: false, error: `${e}` });
@ -137,7 +137,7 @@ wsEvents.on('req:requestLogin', async (data: any, cb: (data: WSResponse) => void
});
wsEvents.on('req:stats', async (_data: any, cb: (data: { servers: number }) => void) => {
const servers = bot.servers.size;
const servers = bot.servers.size();
cb({ servers });
});

View File

@ -15,10 +15,10 @@ import logger from "../logger";
const update = async () => {
try {
const statusText = statuses[i]
.replace('{{servers}}', `${client.servers.size}`)
.replace('{{users}}', `${client.users.size}`)
.replace('{{servers}}', `${client.servers.size()}`)
.replace('{{users}}', `${client.users.size()}`)
.replace('{{infractions_total}}', `${await dbs.INFRACTIONS.count({})}`)
.replace('{{ping_ms}}', `${client.websocket.ping ?? -1}`);
.replace('{{ping_ms}}', `${client.events.ping() ?? -1}`);
await setStatus(statusText, 'Online');
logger.debug(`Bot status updated`);
@ -37,7 +37,7 @@ import logger from "../logger";
async function setStatus(text: string, presence: 'Online'|'Idle'|'Busy'|'Invisible') {
await axios.patch(
`${client.apiURL}/users/@me`,
`${client.options.baseURL}/users/@me`,
{
status: { text, presence }
},

View File

@ -7,7 +7,7 @@ import { antispam, wordFilterCheck } from "./antispam";
import checkCustomRules from "./custom_rules/custom_rules";
import MessageCommandContext from "../../struct/MessageCommandContext";
import { fileURLToPath } from 'url';
import { getOwnMemberInServer, hasPermForChannel } from "../util";
import { getOwnMemberInServer } from "../util";
import { isSudo, updateSudoTimeout } from "../commands/admin/botadm";
import { metrics } from "./metrics";
@ -30,20 +30,20 @@ let commands: SimpleCommand[];
.map(async file => await import(file) as SimpleCommand)
)).map(c => (c as any).default)
client.on('message/update', async msg => {
client.on('messageUpdate', async msg => {
checkCustomRules(msg, true);
});
client.on('message', async msg => {
client.on('messageCreate', async msg => {
logger.debug(`Message -> ${msg.content}`);
if (typeof msg.content != 'string' ||
msg.author_id == client.user?._id ||
msg.authorId == client.user?.id ||
!msg.channel?.server) return;
try {
if (!msg.member) await msg.channel.server.fetchMember(msg.author_id);
if (!msg.author) await client.users.fetch(msg.author_id);
if (!msg.member) await msg.channel.server.fetchMember(msg.authorId!);
if (!msg.author) await client.users.fetch(msg.authorId!);
} catch(e) {
return msg.reply('⚠ Failed to fetch message author');
}
@ -51,7 +51,8 @@ let commands: SimpleCommand[];
if (msg.author!.bot) return;
// If we can't reply to the message, return
if (!hasPermForChannel(await getOwnMemberInServer(msg.channel.server), msg.channel, 'SendMessage')) {
const member = await getOwnMemberInServer(msg.channel.server);
if (!member.hasPermission(msg.channel, 'SendMessage')) {
logger.debug('Cannot reply to message; returning');
return;
}
@ -61,8 +62,8 @@ let commands: SimpleCommand[];
checkCustomRules(msg);
let [ config, userConfig ] = await Promise.all([
dbs.SERVERS.findOne({ id: msg.channel!.server_id! }),
dbs.USERS.findOne({ id: msg.author_id }),
dbs.SERVERS.findOne({ id: msg.channel!.serverId! }),
dbs.USERS.findOne({ id: msg.authorId }),
]);
if (config) {
@ -75,8 +76,8 @@ let commands: SimpleCommand[];
let cmdName = args.shift() ?? '';
let guildPrefix = config?.prefix ?? DEFAULT_PREFIX;
if (cmdName.startsWith(`<@${client.user?._id}>`)) {
cmdName = cmdName.substring(`<@${client.user?._id}>`.length);
if (cmdName.startsWith(`<@${client.user?.id}>`)) {
cmdName = cmdName.substring(`<@${client.user?.id}>`.length);
if (!cmdName) cmdName = args.shift() ?? ''; // Space between mention and command name
} else if (cmdName.startsWith(guildPrefix)) {
cmdName = cmdName.substring(guildPrefix.length);
@ -108,7 +109,7 @@ let commands: SimpleCommand[];
if (isSudo(msg.author!)) updateSudoTimeout(msg.author!);
if (cmd.restrict == 'BOTOWNER' && ownerIDs.indexOf(msg.author_id) == -1) {
if (cmd.restrict == 'BOTOWNER' && ownerIDs.indexOf(msg.authorId!) == -1) {
logger.warn(`User ${msg.author?.username} tried to run owner-only command: ${cmdName}`);
msg.reply('🔒 Access denied');
return;
@ -130,10 +131,10 @@ let commands: SimpleCommand[];
let message: MessageCommandContext = msg as MessageCommandContext;
message.serverContext = serverCtx;
logger.info(`Command: ${message.author?.username} (${message.author?._id}) in ${message.channel?.server?.name} (${message.channel?.server?._id}): ${message.content}`);
logger.info(`Command: ${message.author?.username} (${message.author?.id}) in ${message.channel?.server?.name} (${message.channel?.serverId}): ${message.content}`);
// Create document for server in DB, if not already present
if (JSON.stringify(config) == '{}' || !config) await dbs.SERVERS.insert({ id: message.channel!.server_id! });
if (JSON.stringify(config) == '{}' || !config) await dbs.SERVERS.insert({ id: message.channel!.serverId! });
if (cmd.removeEmptyArgs !== false) {
args = args.filter(a => a.length > 0);

View File

@ -1,4 +1,4 @@
import { Message } from "@janderedev/revolt.js/dist/maps/Messages";
import { Message } from "revolt.js";
import CustomRuleAction from "automod/dist/types/antispam/CustomRuleAction";
async function execute(message: Message, action: CustomRuleAction) {

View File

@ -1,4 +1,4 @@
import { Message } from "@janderedev/revolt.js/dist/maps/Messages";
import { Message } from "revolt.js";
import { client } from "../../../..";
import CustomRuleAction from "automod/dist/types/antispam/CustomRuleAction";
@ -8,7 +8,7 @@ async function execute(message: Message, action: CustomRuleAction) {
text = text.slice(0, 1996) + ' ...';
}
if (!message.channel) await client.channels.fetch(message.channel_id);
if (!message.channel) await client.channels.fetch(message.channelId);
let msg = await message.channel!.sendMessage(text);
if (action.duration) {

View File

@ -1,4 +1,4 @@
import { Message } from "@janderedev/revolt.js/dist/maps/Messages";
import { Message } from "revolt.js";
import CustomRuleAction from "automod/dist/types/antispam/CustomRuleAction";
import { storeInfraction } from '../../../util';
import Infraction from "automod/dist/types/antispam/Infraction";
@ -7,17 +7,17 @@ import InfractionType from "automod/dist/types/antispam/InfractionType";
async function execute(message: Message, action: CustomRuleAction) {
let warnMsg = action.text
? `${action.text}\n(Triggered on ${message.channel_id} / ${message._id})`
: `Moderation rule triggered on ${message.channel_id} / ${message._id}`;
? `${action.text}\n(Triggered on ${message.channelId} / ${message.id})`
: `Moderation rule triggered on ${message.channelId} / ${message.id}`;
let infraction: Infraction = {
_id: ulid(),
date: Date.now(),
createdBy: null,
reason: warnMsg,
server: message.channel?.server_id!,
server: message.channel?.serverId!,
type: InfractionType.Automatic,
user: message.author_id
user: message.authorId!,
}
let { userWarnCount } = await storeInfraction(infraction);

View File

@ -1,4 +1,4 @@
import { Message } from "@janderedev/revolt.js/dist/maps/Messages";
import { Message } from "revolt.js";
import { dbs } from "../../..";
import logger from "../../logger";
import messageContentTrigger from "./message_content_trigger";
@ -6,11 +6,11 @@ import messageContentTrigger from "./message_content_trigger";
import custom_sendMessage from "./actions/sendMessage";
import custom_delete from "./actions/delete";
import custom_warn from "./actions/warn";
import { getOwnMemberInServer, hasPermForChannel } from "../../util";
import { getOwnMemberInServer } from "../../util";
async function checkCustomRules(message: Message, isEdit: boolean = false) {
try {
let serverConfig = await dbs.SERVERS.findOne({ id: message.channel!.server_id! });
let serverConfig = await dbs.SERVERS.findOne({ id: message.channel!.serverId! });
let rules = serverConfig?.automodSettings?.custom;
if (!rules) return;
@ -24,27 +24,28 @@ async function checkCustomRules(message: Message, isEdit: boolean = false) {
if (await messageContentTrigger(message, rule.trigger)) {
for (const action of rule.action) {
const member = await getOwnMemberInServer(message.channel!.server!);
switch(action.action) {
case 'sendMessage':
if (hasPermForChannel(await getOwnMemberInServer(message.channel!.server!), message.channel!, 'SendMessage'))
if (member.hasPermission(message.channel!, 'SendMessage'))
await custom_sendMessage(message, action);
else
logger.warn(`Custom rule ${rule._id}: 'sendMessage' action lacks permission`);
break;
case 'delete':
if (hasPermForChannel(await getOwnMemberInServer(message.channel!.server!), message.channel!, 'ManageMessages'))
if (member.hasPermission(message.channel!, 'ManageMessages'))
await custom_delete(message, action);
else
logger.warn(`Custom rule ${rule._id}: 'delete' action lacks permission`);
break;
case 'warn':
if (hasPermForChannel(await getOwnMemberInServer(message.channel!.server!), message.channel!, 'SendMessage'))
if (member.hasPermission(message.channel!, 'SendMessage'))
await custom_warn(message, action);
else
logger.warn(`Custom rule ${rule._id}: 'warn' action lacks permission`);
break;
default:
logger.warn(`Unknown action ${action.action} in custom rule ${rule._id} in server ${message.channel?.server_id}`);
logger.warn(`Unknown action ${action.action} in custom rule ${rule._id} in server ${message.channel?.serverId}`);
}
}
}

View File

@ -1,4 +1,4 @@
import { Message } from "@janderedev/revolt.js/dist/maps/Messages";
import { Message } from "revolt.js";
import { client } from "../../..";
import CustomRuleTrigger from "automod/dist/types/antispam/CustomRuleTrigger";
import VM from 'vm';
@ -12,8 +12,8 @@ async function messageContentTrigger(message: Message, trigger: CustomRuleTrigge
let matched = false;
if (trigger.matcher) {
if (trigger.channelFilter) {
if (trigger.channelFilter.mode == 'WHITELIST' && !trigger.channelFilter.channels.includes(message.channel_id)) return false;
if (trigger.channelFilter.mode == 'BLACKLIST' && trigger.channelFilter.channels.includes(message.channel_id)) return false;
if (trigger.channelFilter.mode == 'WHITELIST' && !trigger.channelFilter.channels.includes(message.channelId)) return false;
if (trigger.channelFilter.mode == 'BLACKLIST' && trigger.channelFilter.channels.includes(message.channelId)) return false;
}
if (trigger.matcher instanceof RegExp) {
@ -55,8 +55,8 @@ async function messageContentTrigger(message: Message, trigger: CustomRuleTrigge
let timeoutKeys = {
global: trigger._id,
channel: trigger._id + '/channel/' + message.channel_id,
user: trigger._id + '/user/' + message.author_id,
channel: trigger._id + '/channel/' + message.channelId,
user: trigger._id + '/user/' + message.authorId,
}
let timeoutPass = true;
@ -87,7 +87,7 @@ async function messageContentTrigger(message: Message, trigger: CustomRuleTrigge
/* User/bot filter comes last because we want to avoid fetching users if possible */
if (trigger.userFilter && trigger.userFilter != 'any') {
let user = message.author || await client.users.fetch(message.author_id);
let user = message.author || await client.users.fetch(message.authorId!);
if (trigger.userFilter == 'bot' && !user.bot) return false;
if (trigger.userFilter == 'user' && user.bot) return false;
}

View File

@ -5,71 +5,61 @@ import Infraction from "automod/dist/types/antispam/Infraction";
import InfractionType from "automod/dist/types/antispam/InfractionType";
import { BLACKLIST_BAN_REASON, BLACKLIST_MESSAGE } from "../commands/admin/botadm";
import logger from "../logger";
import { hasPermForChannel, storeInfraction } from "../util";
import { storeInfraction } from "../util";
import { DEFAULT_PREFIX } from "./command_handler";
import { SendableEmbed } from "revolt-api";
const DM_SESSION_LIFETIME = 1000 * 60 * 60 * 24 * 30;
// Listen to system messages
client.on('message', async message => {
if (typeof message.content != 'object') {
// reply to 74
if (message.author_id == '01FCXF8V6RDKHSQ3AHJ410AASX' && message.content == 'we do a little') {
try {
message.reply('shut the fuck up');
} catch(e) { console.error(e) }
}
client.on('messageCreate', async message => {
return;
}
let sysMsg = message.systemMessage;
let sysMsg = message.asSystemMessage;
switch(sysMsg.type) {
if (sysMsg) switch(sysMsg.type) {
case 'user_kicked':
case 'user_banned':
try {
let recentEvents = await dbs.INFRACTIONS.findOne({
date: { $gt: Date.now() - 30000 },
user: sysMsg.user?._id,
server: message.channel!.server_id!,
user: sysMsg.id,
server: message.channel!.serverId!,
actionType: sysMsg.type == 'user_kicked' ? 'kick' : 'ban',
});
if (!message.channel ||
!sysMsg.user ||
!sysMsg.id ||
recentEvents) return;
storeInfraction({
_id: ulid(),
createdBy: sysMsg.by?._id,
createdBy: null,
reason: 'Unknown reason (caught system message)',
date: message.createdAt,
server: message.channel!.server_id,
date: message.createdAt.getTime(),
server: message.channel!.serverId,
type: InfractionType.Manual,
user: sysMsg.user!._id,
user: sysMsg.id,
actionType: sysMsg.type == 'user_kicked' ? 'kick' : 'ban',
} as Infraction).catch(console.warn);
} catch(e) { console.error(e) }
break;
case 'user_joined': {
if (!sysMsg.user) break;
try {
const [ serverConfig, userConfig ] = await Promise.all([
dbs.SERVERS.findOne({ id: message.channel!.server_id! }),
dbs.USERS.findOne({ id: sysMsg.user._id }),
dbs.SERVERS.findOne({ id: message.channel!.serverId }),
dbs.USERS.findOne({ id: sysMsg.id }),
]);
if (userConfig?.globalBlacklist && !serverConfig?.allowBlacklistedUsers) {
const server = message.channel?.server;
if (server && server.havePermission('BanMembers')) {
await server.banUser(sysMsg.user._id, { reason: BLACKLIST_BAN_REASON });
await server.banUser(sysMsg.id, { reason: BLACKLIST_BAN_REASON });
if (server.system_messages?.user_banned) {
const channel = server.channels.find(c => c?._id == server.system_messages?.user_banned);
if (server.systemMessages?.user_banned) {
const channel = server.channels.find(c => c?.id == server.systemMessages?.user_banned);
if (channel && channel.havePermission('SendMessage')) {
await channel.sendMessage(BLACKLIST_MESSAGE(sysMsg.user.username));
const user = client.users.get(sysMsg.id);
await channel.sendMessage(BLACKLIST_MESSAGE(user?.username ?? sysMsg.id));
}
}
}
@ -85,10 +75,10 @@ client.on('message', async message => {
});
// DM message based API session token retrieval
client.on('message', async message => {
client.on('messageCreate', async message => {
try {
if (
message.channel?.channel_type == "DirectMessage" &&
message.channel?.type == "DirectMessage" &&
message.nonce?.startsWith("REQUEST_SESSION_TOKEN-") &&
message.content?.toLowerCase().startsWith("requesting session token.")
) {
@ -97,17 +87,16 @@ client.on('message', async message => {
const token = crypto.randomBytes(48).toString('base64').replace(/=/g, '');
await client.db.get('sessions').insert({
user: message.author_id,
user: message.authorId,
token: token,
nonce: message.nonce,
invalid: false,
expires: Date.now() + DM_SESSION_LIFETIME,
})
// Don't need to risk exposing the user to the token, so we'll send it in the nonce
await message.channel.sendMessage({
content: `Token request granted. **Do not send the content of this message to anyone!**\n$%${token}%$`,
replies: [ { id: message._id, mention: false } ],
replies: [ { id: message.id, mention: false } ],
});
return;
}
@ -117,26 +106,24 @@ client.on('message', async message => {
});
// Send a message when added to a server
client.on('member/join', (member) => {
if (member._id.user != client.user?._id) return;
let url = `https://rvembed.janderedev.xyz/embed`
+ `?title=${encodeURIComponent('Hi there, thanks for adding me!')}`
+ `&description=${encodeURIComponent(`My prefix is "${DEFAULT_PREFIX}", `
+ `but you can also @mention me instead.\nCheck out ${DEFAULT_PREFIX}help to get started!`)}`
+ `&link=${encodeURIComponent(`/bot/${client.user._id}`)}`
+ `&redir=${encodeURIComponent(`https://github.com/janderedev/revolt-automod`)}`
+ `&color=${encodeURIComponent("#ff6e6d")}`
+ `&image=${encodeURIComponent(client.user.generateAvatarURL({ size: 128 }))}`
+ `&image_large=false`;
client.on('serverMemberJoin', (member) => {
if (member.id.user != client.user?.id) return;
if (!member.server) return;
const embed: SendableEmbed = {
title: 'Hi there, thanks for adding me!',
description: `My prefix is "${DEFAULT_PREFIX}", but you can also @mention me instead.\nCheck out ${DEFAULT_PREFIX}help to get started!`,
icon_url: client.user.avatarURL,
colour: '#ff6e6d',
url: `/bot/${client.user.id}`,
}
let channels = member.server.channels.filter(
c => c
&& c.channel_type == 'TextChannel'
&& hasPermForChannel(member, c, 'SendMessage')
&& hasPermForChannel(member, c, 'SendEmbeds')
&& c.type == 'TextChannel'
&& member.hasPermission(c, 'SendMessage')
&& member.hasPermission(c, 'SendEmbeds')
);
// Attempt to find an appropriate channel, otherwise use the first one available
@ -147,6 +134,8 @@ client.on('member/join', (member) => {
|| channels[0];
if (!channel) return logger.debug('Cannot send hello message: No suitable channel found');
channel.sendMessage(`[:wave:](${url} "Hi there!")`)
.catch(e => logger.debug('Cannot send hello message: ' + e));
channel.sendMessage({
content: `:wave: "Hi there!")`,
embeds: [embed],
}).catch(e => logger.debug('Cannot send hello message: ' + e));
});

View File

@ -6,14 +6,14 @@ import logger from "../logger";
(async () => {
if (!client.user) await new Promise<void>(r => client.once('ready', () => r()));
logger.info(`Starting to fetch users in ${client.servers.size} servers.`);
logger.info(`Starting to fetch users in ${client.servers.size()} servers.`);
const promises: Promise<any>[] = [];
for (const server of client.servers) {
for (const server of client.servers.entries()) {
promises.push(server[1].fetchMembers());
}
const res = await Promise.allSettled(promises);
logger.done(`Downloaded all users from ${res.filter(r => r.status == 'fulfilled').length} servers `
+ `with ${res.filter(r => r.status == 'rejected').length} errors. Cache size: ${client.users.size}`);
+ `with ${res.filter(r => r.status == 'rejected').length} errors. Cache size: ${client.users.size()}`);
})();

View File

@ -30,14 +30,14 @@ if (!isNaN(PORT)) {
}
});
const setServerCount = () => metrics.servers.set(client.servers.size);
const setServerCount = () => metrics.servers.set(client.servers.size());
client.once('ready', setServerCount);
client.on('server/update', setServerCount);
client.on('server/delete', setServerCount);
client.on('serverUpdate', setServerCount);
client.on('serverDelete', setServerCount);
const measureLatency = async () => {
const wsPing = client.websocket.ping;
const wsPing = -1; // currently not exported by revolt.js, todo?
if (wsPing != undefined) metrics.wsPing.set(wsPing);
}

View File

@ -1,146 +1,161 @@
import { Member } from "@janderedev/revolt.js/dist/maps/Members";
import { Server } from "@janderedev/revolt.js/dist/maps/Servers";
import { Server, ServerMember } from "revolt.js";
import { client, dbs } from "../..";
import LogMessage from "automod/dist/types/LogMessage";
import Xlsx from 'xlsx';
import logger from "../logger";
import { getAutumnURL, sanitizeMessageContent, sendLogMessage } from "../util";
import { sanitizeMessageContent, sendLogMessage } from "../util";
// the `packet` event is emitted before the client's cache
// is updated, which allows us to get the old message content
// if it was cached before
client.on('packet', async (packet) => {
if (packet.type == 'MessageUpdate') {
try {
if (!packet.data.content) return;
client.on('messageUpdate', async (message, oldMessage) => {
try {
if (!message.content) return;
let m = client.messages.get(packet.id);
if (message.authorId == client.user?.id) return;
if (m?.author_id == client.user?._id) return;
let oldMsgRaw = String(oldMessage.content ?? '(Unknown)');
let newMsgRaw = String(message.content);
let oldMsg = sanitizeMessageContent(oldMsgRaw) || '(Empty)';
let newMsg = sanitizeMessageContent(newMsgRaw) || '(Empty)';
let oldMsgRaw = String(m?.content ?? '(Unknown)');
let newMsgRaw = String(packet.data.content);
let oldMsg = sanitizeMessageContent(oldMsgRaw) || '(Empty)';
let newMsg = sanitizeMessageContent(newMsgRaw) || '(Empty)';
let channel = message.channel;
let server = channel?.server;
if (!server || !channel) return logger.warn('Received message update in unknown channel or server');
let channel = client.channels.get(packet.channel);
let server = channel?.server;
if (!server || !channel) return logger.warn('Received message update in unknown channel or server');
let config = await dbs.SERVERS.findOne({ id: server._id });
if (config?.logs?.messageUpdate) {
const attachFullMessage = oldMsg.length > 800 || newMsg.length > 800;
let embed: LogMessage = {
title: `Message edited in ${server.name}`,
description:
`[#${channel.name}](/server/${server._id}/channel/${channel._id}) | ` +
`[@${sanitizeMessageContent(
m?.author?.username ?? "Unknown User"
)}](/@${m?.author_id}) | ` +
`[Jump to message](/server/${server._id}/channel/${channel._id}/${packet.id})`,
fields: [],
color: "#829dff",
overrides: {
discord: {
description: `Author: @${
m?.author?.username || m?.author_id || "Unknown"
} | Channel: ${channel?.name || channel?._id}`,
},
let config = await dbs.SERVERS.findOne({ id: server.id });
if (config?.logs?.messageUpdate) {
const attachFullMessage = oldMsg.length > 800 || newMsg.length > 800;
let embed: LogMessage = {
title: `Message edited in ${server.name}`,
description:
`[#${channel.name}](/server/${server.id}/channel/${channel.id}) | ` +
`@${sanitizeMessageContent(
message.author?.username ?? "Unknown User"
)} (${message.authorId}) | ` +
`[Jump to message](/server/${server.id}/channel/${channel.id}/${message.id})`,
fields: [],
color: "#829dff",
overrides: {
discord: {
description: `Author: @${
message.author?.username || message.authorId || "Unknown"
} | Channel: ${channel.name || channel.id}`,
},
};
},
};
if (attachFullMessage) {
embed.attachments = [
{ name: 'old_message.txt', content: Buffer.from(oldMsgRaw) },
{ name: 'new_message.txt', content: Buffer.from(newMsgRaw) },
];
} else {
embed.fields!.push({ title: 'Old content', content: oldMsg });
embed.fields!.push({ title: 'New content', content: newMsg });
}
await sendLogMessage(config.logs.messageUpdate, embed);
if (attachFullMessage) {
embed.attachments = [
{ name: 'old_message.txt', content: Buffer.from(oldMsgRaw) },
{ name: 'new_message.txt', content: Buffer.from(newMsgRaw) },
];
} else {
embed.fields!.push({ title: 'Old content', content: oldMsg });
embed.fields!.push({ title: 'New content', content: newMsg });
}
} catch(e) {
console.error(e);
await sendLogMessage(config.logs.messageUpdate, embed);
}
} catch(e) {
console.error(e);
}
if (packet.type == 'MessageDelete') {
try {
let channel = client.channels.get(packet.channel);
if (!channel) return;
let message = client.messages.get(packet.id);
if (!message) return;
let msgRaw = String(message.content ?? '(Unknown)');
let msg = sanitizeMessageContent(msgRaw);
let config = await dbs.SERVERS.findOne({ id: message.channel?.server?._id });
if (config?.logs?.messageUpdate) {
let embed: LogMessage = {
title: `Message deleted in ${message.channel?.server?.name}`,
description: `[\\[#${channel.name}\\]](/server/${channel.server_id}/channel/${channel._id}) | `
+ `[\\[Author\\]](/@${message.author_id}) | `
+ `[\\[Jump to context\\]](/server/${channel.server_id}/channel/${channel._id}/${packet.id})`,
fields: [],
color: '#ff6b6b',
overrides: {
discord: {
description: `Author: @${message.author?.username || message.author_id} | Channel: ${message.channel?.name || message.channel_id}`
},
}
}
if (msg.length > 1000) {
embed.attachments?.push({ name: 'message.txt', content: Buffer.from(msgRaw) });
} else {
embed.fields!.push({ title: 'Content', content: msg || "(Empty)" });
}
if (message.attachments?.length) {
let autumnURL = await getAutumnURL();
embed.fields!.push({ title: 'Attachments', content: message.attachments.map(a =>
`[\\[${a.filename}\\]](<${autumnURL}/${a.tag}/${a._id}/${a.filename}>)`).join(' | ') })
}
await sendLogMessage(config.logs.messageUpdate, embed);
}
} catch(e) {
console.error(e);
}
}
if (packet.type == 'BulkMessageDelete') {
const channel = client.channels.get(packet.channel);
});
client.on('messageDelete', async (message) => {
try {
let channel = client.channels.get(message.channelId);
let author = message.authorId ? client.users.get(message.authorId) : null;
if (!channel) return;
try {
let config = await dbs.SERVERS.findOne({ id: channel.server?._id });
if (config?.logs?.messageUpdate) {
let embed: LogMessage = {
title: `Bulk delete in ${channel.server?.name}`,
description: `${packet.ids.length} messages deleted in ` +
`[#${channel.name}](/server/${channel.server_id}/channel/${channel._id})`,
fields: [],
color: '#ff392b',
overrides: {
discord: {
description: `${packet.ids.length} messages deleted in #${channel.name}`,
}
}
}
let msgRaw = String(message.content ?? '(Unknown)');
let msg = sanitizeMessageContent(msgRaw);
await sendLogMessage(config.logs.messageUpdate, embed);
let config = await dbs.SERVERS.findOne({ id: channel?.server?.id });
if (config?.logs?.messageUpdate) {
let embed: LogMessage = {
title: `Message deleted in ${channel?.server?.name}`,
description: `[#${channel.name}](/server/${channel.serverId}/channel/${channel.id}) | `
+ `@${sanitizeMessageContent(
author?.username ?? "Unknown User"
)} (${message.authorId}) | `
+ `[\\[Jump to context\\]](/server/${channel.serverId}/channel/${channel.id}/${message.id})`,
fields: [],
color: '#ff6b6b',
overrides: {
discord: {
description: `Author: @${author?.username || message.authorId} | Channel: ${channel?.name || message.channelId}`
},
}
}
} catch(e) {
console.error(e);
if (msg.length > 1000) {
embed.attachments?.push({ name: 'message.txt', content: Buffer.from(msgRaw) });
} else {
embed.fields!.push({ title: 'Content', content: msg || "(Empty)" });
}
if (message.attachments?.length) {
let autumnURL = client.configuration?.features.autumn.url;
embed.fields!.push({ title: 'Attachments', content: message.attachments.map(a =>
`[\\[${a.filename}\\]](<${autumnURL}/${a.tag}/${a.id}/${a.filename}>)`).join(' | ') })
}
await sendLogMessage(config.logs.messageUpdate, embed);
}
} catch(e) {
console.error(e);
}
});
async function logModAction(type: 'warn'|'kick'|'ban'|'votekick', server: Server, mod: Member, target: string, reason: string|null, infractionID: string, extraText?: string): Promise<void> {
client.on('messageDeleteBulk', async (messages) => {
const channel = client.channels.get(messages[0].channelId);
if (!channel) return;
try {
let config = await dbs.SERVERS.findOne({ id: server._id });
let config = await dbs.SERVERS.findOne({ id: channel.serverId });
if (config?.logs?.messageUpdate) {
const data: String[][] = [
['Message ID', 'Author ID', 'Author Name', 'Content', 'Attachment URLs'],
[],
];
for (const message of messages) {
data.push([
message.id,
message.authorId ?? '',
message.authorId ? client.users.get(message.authorId)?.username ?? '' : '',
message.content ?? '',
message.attachments?.map(a => a.id).join(', ') ?? '',
]);
}
const sheet = Xlsx.utils.aoa_to_sheet(data);
const csv = Xlsx.utils.sheet_to_csv(data);
let embed: LogMessage = {
title: `Bulk delete in ${channel.server?.name}`,
description: `${messages.length} messages deleted in ` +
`[#${channel.name}](/server/${channel.serverId}/channel/${channel.id})`,
fields: [],
attachments: [{ name: 'messages.csv', content: Buffer.from(csv) }],
color: '#ff392b',
overrides: {
discord: {
description: `${messages.length} messages deleted in #${channel.name}`,
}
}
}
await sendLogMessage(config.logs.messageUpdate, embed);
}
} catch(e) {
console.error(e);
}
});
async function logModAction(type: 'warn'|'kick'|'ban'|'votekick', server: Server, mod: ServerMember, target: string, reason: string|null, infractionID: string, extraText?: string): Promise<void> {
try {
let config = await dbs.SERVERS.findOne({ id: server.id });
if (config?.logs?.modAction) {
let aType = type == 'ban' ? 'banned' : type + 'ed';

View File

@ -29,11 +29,11 @@ async function processUnban(ban: TempBan) {
if (expired.includes(ban.id)) return;
let server = client.servers.get(ban.server) || await client.servers.fetch(ban.server);
if (!server.havePermission('BanMembers')) return logger.debug(`No permission to process unbans in ${server._id}, skipping`);
if (!server.havePermission('BanMembers')) return logger.debug(`No permission to process unbans in ${server.id}, skipping`);
let serverBans = await server.fetchBans();
if (serverBans.bans.find(b => b._id.user == ban.bannedUser)) {
logger.debug(`Unbanning user ${ban.bannedUser} from ${server._id}`);
if (serverBans.find(b => b.id.user == ban.bannedUser)) {
logger.debug(`Unbanning user ${ban.bannedUser} from ${server.id}`);
let promises = [
server.unbanUser(ban.bannedUser),

View File

@ -1,23 +1,20 @@
import { Member } from "@janderedev/revolt.js/dist/maps/Members";
import { User } from "@janderedev/revolt.js/dist/maps/Users";
import { ServerMember } from "revolt.js";
import { User } from "revolt.js";
import { client, dbs } from "..";
import Infraction from "automod/dist/types/antispam/Infraction";
import FormData from 'form-data';
import axios from 'axios';
import { Server } from "@janderedev/revolt.js/dist/maps/Servers";
import { Server } from "revolt.js";
import LogConfig from "automod/dist/types/LogConfig";
import LogMessage from "automod/dist/types/LogMessage";
import { ColorResolvable, MessageEmbed } from "discord.js";
import logger from "./logger";
import { ulid } from "ulid";
import { Channel } from "@janderedev/revolt.js/dist/maps/Channels";
import { Permission } from "@janderedev/revolt.js/dist/permissions/definitions";
import { Message } from "@janderedev/revolt.js/dist/maps/Messages";
import { Channel } from "revolt.js";
import { Message } from "revolt.js";
import { isSudo } from "./commands/admin/botadm";
import { SendableEmbed } from "revolt-api";
import MessageCommandContext from "../struct/MessageCommandContext";
import ServerConfig from "automod/dist/types/ServerConfig";
import { ClientboundNotification } from "@janderedev/revolt.js";
const NO_MANAGER_MSG = "🔒 Missing permission";
const ULID_REGEX = /^[0-9A-HJ-KM-NP-TV-Z]{26}$/i;
@ -26,18 +23,6 @@ const CHANNEL_MENTION_REGEX = /^<#[0-9A-HJ-KM-NP-TV-Z]{26}>$/i;
const RE_HTTP_URI = /^http(s?):\/\//g;
const RE_MAILTO_URI = /^mailto:/g;
let autumn_url: string | null = null;
let apiConfig: any = axios.get(client.apiURL).then((res) => {
autumn_url = (res.data as any).features.autumn.url;
});
async function getAutumnURL() {
return (
autumn_url ||
((await axios.get(client.apiURL)).data as any).features.autumn.url
);
}
/**
* Parses user input and returns an user object.
* Supports: `userID`, `<@userID>` (mention), `username`, `@username` (if user is cached).
@ -80,10 +65,10 @@ async function parseUser(text: string): Promise<User | null> {
*/
async function parseUserOrId(
text: string
): Promise<User | { _id: string } | null> {
): Promise<User | { id: string } | null> {
let parsed = await parseUser(text);
if (parsed) return parsed;
if (ULID_REGEX.test(text)) return { _id: text.toUpperCase() };
if (ULID_REGEX.test(text)) return { id: text.toUpperCase() };
return null;
}
@ -91,17 +76,17 @@ async function isModerator(message: Message, announceSudo?: boolean) {
let member = message.member!,
server = message.channel!.server!;
if (hasPerm(member, "KickMembers")) return true;
if (member.hasPermission(member.server!, "KickMembers")) return true;
const [isManager, mods, isSudo] = await Promise.all([
isBotManager(message),
dbs.SERVERS.findOne({ id: server._id }),
dbs.SERVERS.findOne({ id: server.id }),
checkSudoPermission(message, announceSudo),
]);
return (
isManager ||
(mods?.moderators?.indexOf(member.user?._id!) ?? -1) > -1 ||
(mods?.moderators?.indexOf(member.user?.id!) ?? -1) > -1 ||
isSudo
);
}
@ -109,15 +94,15 @@ async function isBotManager(message: Message, announceSudo?: boolean) {
let member = message.member!,
server = message.channel!.server!;
if (hasPerm(member, "ManageServer")) return true;
if (member.hasPermission(member.server!, "ManageServer")) return true;
const [managers, isSudo] = await Promise.all([
dbs.SERVERS.findOne({ id: server._id }),
dbs.SERVERS.findOne({ id: server.id }),
checkSudoPermission(message, announceSudo),
]);
return (
(managers?.botManagers?.indexOf(member.user?._id!) ?? -1) > -1 || isSudo
(managers?.botManagers?.indexOf(member.user?.id!) ?? -1) > -1 || isSudo
);
}
async function checkSudoPermission(
@ -137,68 +122,38 @@ async function checkSudoPermission(
}
}
async function getPermissionLevel(
user: User | Member,
member: ServerMember | User,
server: Server
): Promise<0 | 1 | 2 | 3> {
if (member instanceof User) {
member = client.serverMembers.getByKey({ server: server.id, user: member.id }) || await server.fetchMember(member.id);
}
if (isSudo(member.user!)) return 3;
if (member.hasPermission(member.server!, "ManageServer")) return 3;
const config = await dbs.SERVERS.findOne({ id: server.id });
if (config?.botManagers?.includes(member.id.user)) return 2;
if (
isSudo(
user instanceof User
? user
: user.user || (await client.users.fetch(user._id.user))
)
)
return 3;
const member = user instanceof User ? await server.fetchMember(user) : user;
if (user instanceof Member) user = user.user!;
if (hasPerm(member, "ManageServer")) return 3;
const config = await dbs.SERVERS.findOne({ id: server._id });
if (config?.botManagers?.includes(user._id)) return 2;
if (
config?.moderators?.includes(user._id) ||
hasPerm(member, "KickMembers")
config?.moderators?.includes(member.id.user) ||
member.hasPermission(member.server!, "KickMembers")
)
return 1;
return 0;
}
function getPermissionBasedOnRole(member: Member): 0 | 1 | 2 | 3 {
if (hasPerm(member, "ManageServer")) return 3;
if (hasPerm(member, "KickMembers")) return 1;
function getPermissionBasedOnRole(member: ServerMember): 0 | 1 | 2 | 3 {
if (member.hasPermission(member.server!, "ManageServer")) return 3;
if (member.hasPermission(member.server!, "KickMembers")) return 1;
return 0;
}
/**
* @deprecated Unnecessary
*/
function hasPerm(member: Member, perm: keyof typeof Permission): boolean {
let p = Permission[perm];
if (member.server?.owner == member.user?._id) return true;
return member.hasPermission(member.server!, perm);
}
/**
* @deprecated Unnecessary
*/
function hasPermForChannel(
member: Member,
channel: Channel,
perm: keyof typeof Permission
): boolean {
if (!member.server) throw "hasPermForChannel(): Server is undefined";
return member.hasPermission(channel, perm);
}
async function getOwnMemberInServer(server: Server): Promise<Member> {
return (
client.members.getKey({ server: server._id, user: client.user!._id }) ||
(await server.fetchMember(client.user!._id))
);
async function getOwnMemberInServer(server: Server): Promise<ServerMember> {
return server.member || await server.fetchMember(client.user!.id);
}
async function storeInfraction(
@ -220,7 +175,7 @@ async function uploadFile(file: any, filename: string): Promise<string> {
let data = new FormData();
data.append("file", file, { filename: filename });
let req = await axios.post((await getAutumnURL()) + "/attachments", data, {
let req = await axios.post(client.configuration?.features.autumn.url + "/attachments", data, {
headers: data.getHeaders(),
});
return (req.data as any)["id"] as string;
@ -432,8 +387,8 @@ function dedupeArray<T>(...arrays: T[][]): T[] {
function getMutualServers(user: User) {
const servers: Server[] = [];
for (const member of client.members) {
if (member[1]._id.user == user._id && member[1].server)
for (const member of client.serverMembers.entries()) {
if (member[1].id.user == user.id && member[1].server)
servers.push(member[1].server);
}
return servers;
@ -445,19 +400,21 @@ const awaitClient = () =>
else resolve();
});
const getDmChannel = async (user: string | { _id: string } | User) => {
if (typeof user == "string")
const getDmChannel = async (user: string | { id: string } | User) => {
if (typeof user == "string") {
user = client.users.get(user) || (await client.users.fetch(user));
if (!(user instanceof User))
user =
client.users.get(user._id) || (await client.users.fetch(user._id));
}
if (!(user instanceof User)) {
user = client.users.get(user.id) || (await client.users.fetch(user.id));
}
return (
Array.from(client.channels).find(
(c) =>
c[1].channel_type == "DirectMessage" &&
c[1].recipient?._id == (user as User)._id
)?.[1] || (await (user as User).openDM())
Array.from(client.channels.values()).find(
(c: Channel) =>
c.type == "DirectMessage" &&
c.recipient?.id == (user as User).id
) || (await (user as User).openDM())
);
};
@ -469,7 +426,7 @@ const generateInfractionDMEmbed = (
) => {
const embed: SendableEmbed = {
title: server.name,
icon_url: server.generateIconURL({ max_side: 128 }),
icon_url: server.icon?.createFileURL({ max_side: 128 }),
colour: "#ff9e2f",
url: message.url,
description:
@ -485,7 +442,7 @@ const generateInfractionDMEmbed = (
`**Reason:** ${infraction.reason}\n` +
`**Moderator:** [@${sanitizeMessageContent(
message.author?.username || "Unknown"
)}](/@${message.author_id})\n` +
)}](/@${message.authorId})\n` +
`**Infraction ID:** \`${infraction._id}\`` +
(infraction.actionType == "ban" && infraction.expires
? infraction.expires == Infinity
@ -545,14 +502,13 @@ const yesNoMessage = (
});
let destroyed = false;
const cb = async (packet: ClientboundNotification) => {
if (packet.type != "MessageReact") return;
if (packet.id != msg._id) return;
if (packet.user_id != allowedUser) return;
const cb = async (m: Message, userId: string, emoji: string) => {
if (m.id != msg.id) return;
if (userId != allowedUser) return;
switch (packet.emoji_id) {
switch (emoji) {
case EMOJI_YES:
channel.client.removeListener("packet", cb);
client.removeListener("messageReactionAdd", cb);
destroyed = true;
resolve(true);
msg.edit({
@ -569,7 +525,7 @@ const yesNoMessage = (
break;
case EMOJI_NO:
channel.client.removeListener("packet", cb);
client.removeListener("messageReactionAdd", cb);
destroyed = true;
resolve(false);
msg.edit({
@ -587,16 +543,16 @@ const yesNoMessage = (
default:
logger.warn(
"Received unexpected reaction: " + packet.emoji_id
"Received unexpected reaction: " + emoji
);
}
};
channel.client.on("packet", cb);
client.on("messageReactionAdd", cb);
setTimeout(() => {
if (!destroyed) {
resolve(false);
channel.client.removeListener("packet", cb);
client.removeListener("messageReactionAdd", cb);
msg.edit({
embeds: [
{
@ -615,14 +571,19 @@ const yesNoMessage = (
// Get all cached members of a server. Whoever put STRINGIFIED JSON as map keys is now on my hit list.
const getMembers = (id: string) =>
Array.from(client.members.entries())
Array.from(client.serverMembers.entries())
.filter((item) => item[0].includes(`"${id}"`))
.map((entry) => entry[1]);
const memberRanking = (member: ServerMember) => {
const inferior = (member.server?.member?.ranking ?? Infinity) < member.ranking;
const kickable = member.server?.havePermission('KickMembers') && inferior;
const bannable = member.server?.havePermission('BanMembers') && inferior;
return { inferior, kickable, bannable }
}
export {
getAutumnURL,
hasPerm,
hasPermForChannel,
getOwnMemberInServer,
isModerator,
isBotManager,
@ -642,6 +603,7 @@ export {
generateInfractionDMEmbed,
yesNoMessage,
getMembers,
memberRanking,
EmbedColor,
NO_MANAGER_MSG,
ULID_REGEX,

View File

@ -18,12 +18,6 @@ logger.info('Initializing client');
let db = MongoDB();
let client = new AutomodClient({
// pongTimeout: 10,
// onPongTimeout: 'RECONNECT',
fixReplyCrash: true,
messageTimeoutFix: true,
apiURL: process.env.API_URL,
messageRateLimiter: true,
autoReconnect: true,
}, db);
login(client);

View File

@ -1,12 +1,13 @@
import * as Revolt from "@janderedev/revolt.js";
import * as Revolt from "revolt.js";
import { IMonkManager } from 'monk';
import logger from '../bot/logger';
import { adminBotLog } from "../bot/logging";
import { ClientOptions } from "revolt.js/src/Client";
class AutomodClient extends Revolt.Client {
db: IMonkManager;
constructor(options: Partial<Revolt.ClientOptions> | undefined, monk: IMonkManager) {
constructor(options: Partial<ClientOptions> | undefined, monk: IMonkManager) {
super(options);
this.db = monk;
@ -29,13 +30,6 @@ let login = (client: Revolt.Client): Promise<void> => new Promise((resolve, reje
adminBotLog({ message: 'Bot logged in', type: 'INFO' });
resolve();
});
client.on('packet', packet => {
if (packet.type == 'InvalidSession' as any) {
logger.error('Authentication failed: ' + JSON.stringify(packet));
process.exit(99);
}
});
});
export default AutomodClient;

View File

@ -1,14 +1,9 @@
import { Message } from "@janderedev/revolt.js/dist/maps/Messages";
import { Server } from "@janderedev/revolt.js/dist/maps/Servers";
import logger from "../bot/logger";
import { Message } from "revolt.js";
import { Server } from "revolt.js";
class MessageCommandContext extends Message {
// The server to which the command should be applied.
serverContext: Server;
/* Override types */
declare content: string;
}
export default MessageCommandContext;

View File

@ -25,22 +25,6 @@ __metadata:
languageName: node
linkType: hard
"@insertish/exponential-backoff@npm:3.1.0-patch.2":
version: 3.1.0-patch.2
resolution: "@insertish/exponential-backoff@npm:3.1.0-patch.2"
checksum: 510a531965965c8cc633a91653ca09ffa8408925eb403d07c072bed065ec8ce429b4fd42fb0639a3dbee73d300d4422c306ebaaab3292b06778a224a2b5b0bf1
languageName: node
linkType: hard
"@insertish/isomorphic-ws@npm:^4.0.1":
version: 4.0.1
resolution: "@insertish/isomorphic-ws@npm:4.0.1"
peerDependencies:
ws: "*"
checksum: 64e6464b379784d0c8df31868eb8301b3e3827f91131755c38f66a007fcd791314c6ef49f3ead37bb5d62cc7fd52f2171b2e0ce04564a744905f72d3cd86f1ba
languageName: node
linkType: hard
"@insertish/oapi@npm:0.1.18":
version: 0.1.18
resolution: "@insertish/oapi@npm:0.1.18"
@ -59,26 +43,6 @@ __metadata:
languageName: node
linkType: hard
"@janderedev/revolt.js@npm:latest":
version: 6.0.20-patch.9
resolution: "@janderedev/revolt.js@npm:6.0.20-patch.9"
dependencies:
"@insertish/exponential-backoff": 3.1.0-patch.2
"@insertish/isomorphic-ws": ^4.0.1
axios: ^0.21.4
eventemitter3: ^4.0.7
lodash.defaultsdeep: ^4.6.1
lodash.flatten: ^4.4.0
lodash.isequal: ^4.5.0
long: ^5.2.0
mobx: ^6.3.2
revolt-api: 0.5.16
ulid: ^2.3.0
ws: ^8.2.2
checksum: 942f8cb7339f6378738d97ff788680dc63c287624e749b95b867a82c877bc6416a4a7b85264bf8797e034132d5a84843d75b820b6a1c37a760a88f13114772a0
languageName: node
linkType: hard
"@sapphire/async-queue@npm:^1.5.0":
version: 1.5.0
resolution: "@sapphire/async-queue@npm:1.5.0"
@ -96,6 +60,48 @@ __metadata:
languageName: node
linkType: hard
"@solid-primitives/map@npm:^0.4.3":
version: 0.4.3
resolution: "@solid-primitives/map@npm:0.4.3"
dependencies:
"@solid-primitives/trigger": ^1.0.3
peerDependencies:
solid-js: ^1.6.12
checksum: e2408d7309c2bc0b93126771ad796cc3cbc2b150a03b4f3d4963dbc6df2ad26e671277fc14aafe1c117f1228c35557686e709accd6237ac511d2e05a6682006d
languageName: node
linkType: hard
"@solid-primitives/set@npm:^0.4.3":
version: 0.4.3
resolution: "@solid-primitives/set@npm:0.4.3"
dependencies:
"@solid-primitives/trigger": ^1.0.3
peerDependencies:
solid-js: ^1.6.12
checksum: fcab5679185633b887d6d9ef4c12ded12d1773969a66079ce98dc18bbb2869f9fe743a1f3cd1f5721b52dcd274ae096470daa8ab1284643b4b26eeb28b7a5698
languageName: node
linkType: hard
"@solid-primitives/trigger@npm:^1.0.3":
version: 1.0.5
resolution: "@solid-primitives/trigger@npm:1.0.5"
dependencies:
"@solid-primitives/utils": ^6.0.0
peerDependencies:
solid-js: ^1.6.12
checksum: 5f137ec425b317c09de6b994928992201206c16be7a01f7add46e0ee987d76a947a7f4f9396a945eeb671c43307b6f5d55bd57d90738880cebdaa0907aca65dd
languageName: node
linkType: hard
"@solid-primitives/utils@npm:^6.0.0":
version: 6.0.0
resolution: "@solid-primitives/utils@npm:6.0.0"
peerDependencies:
solid-js: ^1.6.12
checksum: c581b995e2d16c9ed0546baef52a9e60f54dda457a3733bac467a19f2a63227179eb0ec6faa16397af4cacc13fa281288cf967a206b0a75255412fafadc55411
languageName: node
linkType: hard
"@types/bson@npm:*":
version: 4.0.5
resolution: "@types/bson@npm:4.0.5"
@ -196,15 +202,6 @@ __metadata:
languageName: node
linkType: soft
"axios@npm:^0.21.4":
version: 0.21.4
resolution: "axios@npm:0.21.4"
dependencies:
follow-redirects: ^1.14.0
checksum: 44245f24ac971e7458f3120c92f9d66d1fc695e8b97019139de5b0cc65d9b8104647db01e5f46917728edfc0cfd88eb30fc4c55e6053eef4ace76768ce95ff3c
languageName: node
linkType: hard
"axios@npm:^0.22.0":
version: 0.22.0
resolution: "axios@npm:0.22.0"
@ -298,6 +295,13 @@ __metadata:
languageName: node
linkType: hard
"csstype@npm:^3.1.0":
version: 3.1.2
resolution: "csstype@npm:3.1.2"
checksum: e1a52e6c25c1314d6beef5168da704ab29c5186b877c07d822bd0806717d9a265e8493a2e35ca7e68d0f5d472d43fac1cdce70fd79fd0853dff81f3028d857b5
languageName: node
linkType: hard
"dayjs@npm:^1.10.7":
version: 1.11.7
resolution: "dayjs@npm:1.11.7"
@ -369,10 +373,10 @@ __metadata:
languageName: node
linkType: hard
"eventemitter3@npm:^4.0.7":
version: 4.0.7
resolution: "eventemitter3@npm:4.0.7"
checksum: 1875311c42fcfe9c707b2712c32664a245629b42bb0a5a84439762dd0fd637fc54d078155ea83c2af9e0323c9ac13687e03cfba79b03af9f40c89b4960099374
"eventemitter3@npm:^5.0.0":
version: 5.0.0
resolution: "eventemitter3@npm:5.0.0"
checksum: b974bafbab860e0a5bbb21add4c4e82f9d5691c583c03f2e4c5d44a2d6c4556d79223621bdcfc6c8e14366a4af9df6b5ea9d6caf65fbffc80b66f3e1dceacbc9
languageName: node
linkType: hard
@ -390,7 +394,7 @@ __metadata:
languageName: node
linkType: hard
"follow-redirects@npm:^1.14.0, follow-redirects@npm:^1.14.4, follow-redirects@npm:^1.14.8":
"follow-redirects@npm:^1.14.4, follow-redirects@npm:^1.14.8":
version: 1.15.2
resolution: "follow-redirects@npm:1.15.2"
peerDependenciesMeta:
@ -457,6 +461,15 @@ __metadata:
languageName: node
linkType: hard
"isomorphic-ws@npm:^5.0.0":
version: 5.0.0
resolution: "isomorphic-ws@npm:5.0.0"
peerDependencies:
ws: "*"
checksum: e20eb2aee09ba96247465fda40c6d22c1153394c0144fa34fe6609f341af4c8c564f60ea3ba762335a7a9c306809349f9b863c8beedf2beea09b299834ad5398
languageName: node
linkType: hard
"js-yaml@npm:^4.1.0":
version: 4.1.0
resolution: "js-yaml@npm:4.1.0"
@ -475,20 +488,6 @@ __metadata:
languageName: node
linkType: hard
"lodash.flatten@npm:^4.4.0":
version: 4.4.0
resolution: "lodash.flatten@npm:4.4.0"
checksum: 0ac34a393d4b795d4b7421153d27c13ae67e08786c9cbb60ff5b732210d46f833598eee3fb3844bb10070e8488efe390ea53bb567377e0cb47e9e630bf0811cb
languageName: node
linkType: hard
"lodash.isequal@npm:^4.5.0":
version: 4.5.0
resolution: "lodash.isequal@npm:4.5.0"
checksum: da27515dc5230eb1140ba65ff8de3613649620e8656b19a6270afe4866b7bd461d9ba2ac8a48dcc57f7adac4ee80e1de9f965d89d4d81a0ad52bb3eec2609644
languageName: node
linkType: hard
"lodash@npm:^4.17.21":
version: 4.17.21
resolution: "lodash@npm:4.17.21"
@ -505,7 +504,7 @@ __metadata:
languageName: node
linkType: hard
"long@npm:^5.2.0":
"long@npm:^5.2.1":
version: 5.2.1
resolution: "long@npm:5.2.1"
checksum: 9264da12d1b7df67e5aa6da4498144293caf1ad12e7f092efe4e9a2d32c53f0bbf7334f7cef997080a2a3af061142558ab366efa71698d98b1cdb883477445a7
@ -544,13 +543,6 @@ __metadata:
languageName: node
linkType: hard
"mobx@npm:^6.3.2":
version: 6.8.0
resolution: "mobx@npm:6.8.0"
checksum: f09bb079292ea59023a7e35a9c73ed577e3de9a0175ec3d5a2adc8192e2e3a352b29ec0981ee06d1d63f701f81bb7fc6cc19fd9089edf84a754a8a75ef00ef7f
languageName: node
linkType: hard
"mongodb@npm:^3.2.3":
version: 3.7.3
resolution: "mongodb@npm:3.7.3"
@ -750,14 +742,14 @@ __metadata:
languageName: node
linkType: hard
"revolt-api@npm:0.5.16, revolt-api@npm:^0.5.16":
version: 0.5.16
resolution: "revolt-api@npm:0.5.16"
"revolt-api@npm:^0.5.17, revolt-api@npm:latest":
version: 0.5.17
resolution: "revolt-api@npm:0.5.17"
dependencies:
"@insertish/oapi": 0.1.18
axios: ^0.26.1
lodash.defaultsdeep: ^4.6.1
checksum: ce39f61e371c1b7da0704191317bccf88b6630f1d8ffcef6bc9c699ebdc8cfbb3fcc5e054f96f9751c2f4a048398d4b349670cd067bcaad2e099d0c30efd9cfe
checksum: aa722f4739c09bea46f738a1b9aef61af126e06aa924a61fcf33caa53561c5de4e7e2ddde26b496cdd0546e113cf324821fead0035973e2ebdb2633df482091b
languageName: node
linkType: hard
@ -765,7 +757,6 @@ __metadata:
version: 0.0.0-use.local
resolution: "revolt-automod@workspace:."
dependencies:
"@janderedev/revolt.js": latest
"@types/monk": ^6.0.0
automod: ^0.1.0
axios: ^0.22.0
@ -776,13 +767,30 @@ __metadata:
log75: ^2.2.0
monk: ^7.3.4
prom-client: ^14.0.1
revolt-api: ^0.5.16
revolt-api: latest
revolt.js: ^7.0.0
typescript: ^4.4.3
ulid: ^2.3.0
xlsx: ^0.17.3
languageName: unknown
linkType: soft
"revolt.js@portal:../revolt.js::locator=revolt-automod%40workspace%3A.":
version: 0.0.0-use.local
resolution: "revolt.js@portal:../revolt.js::locator=revolt-automod%40workspace%3A."
dependencies:
"@solid-primitives/map": ^0.4.3
"@solid-primitives/set": ^0.4.3
eventemitter3: ^5.0.0
isomorphic-ws: ^5.0.0
long: ^5.2.1
revolt-api: ^0.5.17
solid-js: ^1.7.2
ulid: ^2.3.0
ws: ^8.13.0
languageName: node
linkType: soft
"safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2":
version: 5.2.1
resolution: "safe-buffer@npm:5.2.1"
@ -806,6 +814,23 @@ __metadata:
languageName: node
linkType: hard
"seroval@npm:^0.5.0":
version: 0.5.1
resolution: "seroval@npm:0.5.1"
checksum: a4c1e42d6a65ed12de3c1f1b6a5b6b996e575c5bc838e1998e92daed7bc05421f3f6c82096387082dba33c475d64a31d0d932ac9b693352549259216e38dc091
languageName: node
linkType: hard
"solid-js@npm:^1.7.2":
version: 1.7.3
resolution: "solid-js@npm:1.7.3"
dependencies:
csstype: ^3.1.0
seroval: ^0.5.0
checksum: 052a3148b6d0960312793781435005c16a7a80c2271e2bf2370ec22ec57ffd77e3e4a41335c1bd785ab36500adef86da79536445983efbed404db860e11593d4
languageName: node
linkType: hard
"sparse-bitfield@npm:^3.0.3":
version: 3.0.3
resolution: "sparse-bitfield@npm:3.0.3"
@ -956,7 +981,7 @@ __metadata:
languageName: node
linkType: hard
"ws@npm:^8.2.2, ws@npm:^8.9.0":
"ws@npm:^8.13.0, ws@npm:^8.9.0":
version: 8.13.0
resolution: "ws@npm:8.13.0"
peerDependencies:

View File

@ -14,7 +14,6 @@
"license": "ISC",
"dependencies": {
"@discordjs/rest": "^0.4.1",
"@janderedev/revolt.js": "latest",
"automod": "^0.1.0",
"axios": "^0.26.1",
"discord-api-types": "^0.31.2",
@ -25,7 +24,8 @@
"log75": "^2.2.0",
"monk": "^7.3.4",
"prom-client": "^14.0.1",
"revolt-api": "^0.5.3-rc.8",
"revolt-api": "latest",
"revolt.js": "^7.0.0",
"smart-replace": "^1.0.2",
"ulid": "^2.3.0"
},
@ -34,6 +34,7 @@
"typescript": "^4.7.4"
},
"resolutions": {
"automod": "portal:../lib"
"automod": "portal:../lib",
"revolt.js": "portal:../revolt.js"
}
}

View File

@ -303,7 +303,7 @@ client.on("interactionCreate", async (interaction) => {
embed.addField(
"Adding AutoMod to your server",
`You can add the Revolt bot to your server ` +
`[here](https://app.revolt.chat/bot/${revoltClient.user?._id} "Open Revolt"). To add the Discord counterpart, ` +
`[here](https://app.revolt.chat/bot/${revoltClient.user?.id} "Open Revolt"). To add the Discord counterpart, ` +
`click [here](${INVITE_URL} "Add Discord bot").`
);
@ -480,11 +480,11 @@ client.on("interactionCreate", async (interaction) => {
if (revoltMsg) {
const author = await revoltFetchUser(
revoltMsg.author_id
revoltMsg.authorId
);
embed.addField(
"Message Author",
`**@${author?.username}** (${revoltMsg.author_id})`
`**@${author?.username}** (${revoltMsg.authorId})`
);
}
}

View File

@ -1,6 +1,6 @@
import { BRIDGED_MESSAGES, BRIDGE_CONFIG, BRIDGE_USER_CONFIG, logger } from "..";
import { client } from "./client";
import { AUTUMN_URL, client as revoltClient } from "../revolt/client";
import { client as revoltClient } from "../revolt/client";
import axios from 'axios';
import { ulid } from "ulid";
import GenericEmbed from "../types/GenericEmbed";
@ -196,7 +196,7 @@ client.on("messageCreate", async (message) => {
await BRIDGED_MESSAGES.update(
{ "discord.messageId": message.id },
{
$set: { "revolt.messageId": msg._id },
$set: { "revolt.messageId": msg.id },
}
);
@ -233,7 +233,7 @@ client.on("messageCreate", async (message) => {
});
const res = await axios.post(
`${AUTUMN_URL}/attachments`,
`${revoltClient.configuration?.features.autumn.url}/attachments`,
formData,
{ headers: formData.getHeaders() }
);
@ -280,7 +280,7 @@ client.on("messageCreate", async (message) => {
});
const res = await axios.post(
`${AUTUMN_URL}/attachments`,
`${revoltClient.configuration?.features.autumn.url}/attachments`,
formData,
{ headers: formData.getHeaders() }
);
@ -338,7 +338,7 @@ client.on("messageCreate", async (message) => {
await axios
.post(
`${revoltClient.apiURL}/channels/${channel._id}/messages`,
`${revoltClient.options.baseURL}/channels/${channel.id}/messages`,
payload,
{
headers: {
@ -474,7 +474,7 @@ async function renderMessageBody(message: string): Promise<string> {
: undefined;
return revoltChannel
? `<#${revoltChannel._id}>`
? `<#${revoltChannel.id}>`
: `#${(channel as TextChannel)?.name || id}`;
},
{ cacheMatchResults: true, maxMatches: 10 }

View File

@ -1,21 +1,18 @@
import { Client } from '@janderedev/revolt.js';
import axios from 'axios';
import { Client } from 'revolt.js';
import { logger } from '..';
let AUTUMN_URL = `http://autumnUrl`;
let AUTUMN_URL: string = '';
const client = new Client({
apiURL: process.env.REVOLT_API_URL,
baseURL: process.env.REVOLT_API_URL || 'https://api.revolt.chat',
autoReconnect: true,
});
const login = () => new Promise((resolve: (value: Client) => void) => {
client.loginBot(process.env['REVOLT_TOKEN']!);
client.once('ready', async () => {
logger.info(`Revolt: ${client.user?.username} ready - ${client.servers.size} servers`);
const apiConfig = await axios.get(client.apiURL);
AUTUMN_URL = apiConfig.data?.features?.autumn?.url;
logger.info(`Revolt: ${client.user?.username} ready - ${client.servers.size()} servers`);
AUTUMN_URL = client.configuration?.features.autumn.url ?? '';
resolve(client);
});

View File

@ -26,7 +26,7 @@ fetchEmojiList()
)
.catch((e) => console.error(e));
client.on("message/delete", async (id) => {
client.on("messageDelete", async (id) => {
try {
logger.debug(`[D] Revolt: ${id}`);
@ -83,15 +83,15 @@ client.on("message/delete", async (id) => {
}
});
client.on("message/update", async (message) => {
client.on("messageUpdate", async (message) => {
if (!message.content || typeof message.content != "string") return;
if (message.author_id == client.user?._id) return;
if (message.authorId == client.user?.id) return;
try {
logger.debug(`[E] Revolt: ${message.content}`);
const [bridgeCfg, bridgedMsg] = await Promise.all([
BRIDGE_CONFIG.findOne({ revolt: message.channel_id }),
BRIDGE_CONFIG.findOne({ revolt: message.channelId }),
BRIDGED_MESSAGES.findOne({ "revolt.nonce": message.nonce }),
]);
@ -127,18 +127,18 @@ client.on("message/update", async (message) => {
}
});
client.on("message", async (message) => {
client.on("messageCreate", async (message) => {
try {
logger.debug(`[M] Revolt: ${message._id} ${message.content}`);
logger.debug(`[M] Revolt: ${message.id} ${message.content}`);
const [bridgeCfg, bridgedMsg, ...repliedMessages] = await Promise.all([
BRIDGE_CONFIG.findOne({ revolt: message.channel_id }),
BRIDGE_CONFIG.findOne({ revolt: message.channelId }),
BRIDGED_MESSAGES.findOne(
message.nonce
? { "revolt.nonce": message.nonce }
: { "revolt.messageId": message._id }
: { "revolt.messageId": message.id }
),
...(message.reply_ids?.map((id) =>
...(message.replyIds?.map((id) =>
BRIDGED_MESSAGES.findOne({ "revolt.messageId": id })
) ?? []),
]);
@ -147,7 +147,7 @@ client.on("message", async (message) => {
return logger.debug(
`Revolt: Message has already been bridged; ignoring`
);
if (message.system && bridgeCfg?.config?.disable_system_messages)
if (message.systemMessage && bridgeCfg?.config?.disable_system_messages)
return logger.debug(
`Revolt: System message bridging disabled; ignoring`
);
@ -182,7 +182,7 @@ client.on("message", async (message) => {
token: hook.token || "",
};
await BRIDGE_CONFIG.update(
{ revolt: message.channel_id },
{ revolt: message.channelId },
{
$set: {
discordWebhook: bridgeCfg.discordWebhook,
@ -193,7 +193,7 @@ client.on("message", async (message) => {
logger.warn(
`Unable to create new webhook for channel ${bridgeCfg.discord}; Deleting link\n${e}`
);
await BRIDGE_CONFIG.remove({ revolt: message.channel_id });
await BRIDGE_CONFIG.remove({ revolt: message.channelId });
await message.channel
?.sendMessage(
":warning: I was unable to create a webhook in the bridged Discord channel. " +
@ -206,15 +206,15 @@ client.on("message", async (message) => {
}
await BRIDGED_MESSAGES.update(
{ "revolt.messageId": message._id },
{ "revolt.messageId": message.id },
{
$set: {
revolt: {
messageId: message._id,
messageId: message.id,
nonce: message.nonce,
},
channels: {
revolt: message.channel_id,
revolt: message.channelId,
discord: bridgeCfg.discord,
},
},
@ -238,23 +238,23 @@ client.on("message", async (message) => {
content:
message.content
? await renderMessageBody(message.content)
: message.system
? await renderSystemMessage(message.system)
: message.systemMessage
? await renderSystemMessage(message.systemMessage)
: undefined,
username: message.system
username: message.systemMessage
? "Revolt"
: (bridgeCfg.config?.bridge_nicknames
? message.masquerade?.name ??
message.member?.nickname ??
message.author?.username
: message.author?.username) ?? "Unknown user",
avatarURL: message.system
avatarURL: message.systemMessage
? "https://app.revolt.chat/assets/logo_round.png"
: bridgeCfg.config?.bridge_nicknames
? message.masquerade?.avatar ??
message.member?.generateAvatarURL({ max_side: 128 }) ??
message.author?.generateAvatarURL({ max_side: 128 })
: message.author?.generateAvatarURL({ max_side: 128 }),
message.member?.avatarURL ??
message.author?.avatarURL
: message.author?.avatarURL,
embeds: message.embeds?.length
? message.embeds
.filter((e) => e.type == "Text")
@ -293,15 +293,15 @@ client.on("message", async (message) => {
);
} else {
const msg = await revoltFetchMessage(
message.reply_ids?.[0],
message.replyIds?.[0],
message.channel
);
const brMsg = repliedMessages.find(
(m) => m?.revolt.messageId == msg?._id
(m) => m?.revolt.messageId == msg?.id
);
embed.setAuthor({
name: `@${msg?.author?.username ?? "Unknown"}`,
iconURL: msg?.author?.generateAvatarURL({ size: 64 }),
iconURL: msg?.author?.avatarURL,
url: brMsg
? `https://discord.com/channels/${
channel.guildId
@ -338,7 +338,7 @@ client.on("message", async (message) => {
msgUrl = msg.url;
} else {
const brMsg = repliedMessages.find(
(m) => m?.revolt.messageId == msg?._id
(m) => m?.revolt.messageId == msg?.id
);
if (brMsg)
msgUrl = `https://discord.com/channels/${
@ -367,7 +367,7 @@ client.on("message", async (message) => {
for (const attachment of message.attachments) {
payload.files.push({
attachment: `${AUTUMN_URL}/attachments/${attachment._id}/${attachment.filename}`,
attachment: `${AUTUMN_URL}/attachments/${attachment.id}/${attachment.filename}`,
name: attachment.filename,
});
}
@ -378,7 +378,7 @@ client.on("message", async (message) => {
.then(async (res) => {
await BRIDGED_MESSAGES.update(
{
"revolt.messageId": message._id,
"revolt.messageId": message.id,
},
{
$set: {
@ -400,7 +400,7 @@ client.on("message", async (message) => {
"Revolt: Got Unknown Webhook error, deleting webhook config"
);
await BRIDGE_CONFIG.update(
{ revolt: message.channel_id },
{ revolt: message.channelId },
{ $set: { discordWebhook: undefined } }
);
} catch (e) {
@ -436,7 +436,7 @@ async function renderMessageBody(message: string): Promise<string> {
const channel = client.channels.get(id);
const bridgeCfg = channel
? await BRIDGE_CONFIG.findOne({ revolt: channel._id })
? await BRIDGE_CONFIG.findOne({ revolt: channel.id })
: undefined;
const discordChannel = bridgeCfg?.discord
? discordClient.channels.cache.get(bridgeCfg.discord)

View File

@ -1,6 +1,6 @@
import { Channel } from "@janderedev/revolt.js/dist/maps/Channels";
import { Message } from "@janderedev/revolt.js/dist/maps/Messages";
import { User } from "@janderedev/revolt.js/dist/maps/Users";
import { Channel } from "revolt.js";
import { Message } from "revolt.js";
import { User } from "revolt.js";
import { Message as DiscordMessage, TextChannel, User as DiscordUser } from "discord.js";
import { client as discordClient } from "./discord/client";
import { client as revoltClient } from "./revolt/client"

View File

@ -41,22 +41,6 @@ __metadata:
languageName: node
linkType: hard
"@insertish/exponential-backoff@npm:3.1.0-patch.2":
version: 3.1.0-patch.2
resolution: "@insertish/exponential-backoff@npm:3.1.0-patch.2"
checksum: 510a531965965c8cc633a91653ca09ffa8408925eb403d07c072bed065ec8ce429b4fd42fb0639a3dbee73d300d4422c306ebaaab3292b06778a224a2b5b0bf1
languageName: node
linkType: hard
"@insertish/isomorphic-ws@npm:^4.0.1":
version: 4.0.1
resolution: "@insertish/isomorphic-ws@npm:4.0.1"
peerDependencies:
ws: "*"
checksum: 64e6464b379784d0c8df31868eb8301b3e3827f91131755c38f66a007fcd791314c6ef49f3ead37bb5d62cc7fd52f2171b2e0ce04564a744905f72d3cd86f1ba
languageName: node
linkType: hard
"@insertish/oapi@npm:0.1.18":
version: 0.1.18
resolution: "@insertish/oapi@npm:0.1.18"
@ -75,26 +59,6 @@ __metadata:
languageName: node
linkType: hard
"@janderedev/revolt.js@npm:latest":
version: 6.0.20-patch.9
resolution: "@janderedev/revolt.js@npm:6.0.20-patch.9"
dependencies:
"@insertish/exponential-backoff": 3.1.0-patch.2
"@insertish/isomorphic-ws": ^4.0.1
axios: ^0.21.4
eventemitter3: ^4.0.7
lodash.defaultsdeep: ^4.6.1
lodash.flatten: ^4.4.0
lodash.isequal: ^4.5.0
long: ^5.2.0
mobx: ^6.3.2
revolt-api: 0.5.16
ulid: ^2.3.0
ws: ^8.2.2
checksum: 942f8cb7339f6378738d97ff788680dc63c287624e749b95b867a82c877bc6416a4a7b85264bf8797e034132d5a84843d75b820b6a1c37a760a88f13114772a0
languageName: node
linkType: hard
"@sapphire/async-queue@npm:^1.3.1, @sapphire/async-queue@npm:^1.5.0":
version: 1.5.0
resolution: "@sapphire/async-queue@npm:1.5.0"
@ -119,6 +83,48 @@ __metadata:
languageName: node
linkType: hard
"@solid-primitives/map@npm:^0.4.3":
version: 0.4.3
resolution: "@solid-primitives/map@npm:0.4.3"
dependencies:
"@solid-primitives/trigger": ^1.0.3
peerDependencies:
solid-js: ^1.6.12
checksum: e2408d7309c2bc0b93126771ad796cc3cbc2b150a03b4f3d4963dbc6df2ad26e671277fc14aafe1c117f1228c35557686e709accd6237ac511d2e05a6682006d
languageName: node
linkType: hard
"@solid-primitives/set@npm:^0.4.3":
version: 0.4.3
resolution: "@solid-primitives/set@npm:0.4.3"
dependencies:
"@solid-primitives/trigger": ^1.0.3
peerDependencies:
solid-js: ^1.6.12
checksum: fcab5679185633b887d6d9ef4c12ded12d1773969a66079ce98dc18bbb2869f9fe743a1f3cd1f5721b52dcd274ae096470daa8ab1284643b4b26eeb28b7a5698
languageName: node
linkType: hard
"@solid-primitives/trigger@npm:^1.0.3":
version: 1.0.5
resolution: "@solid-primitives/trigger@npm:1.0.5"
dependencies:
"@solid-primitives/utils": ^6.0.0
peerDependencies:
solid-js: ^1.6.12
checksum: 5f137ec425b317c09de6b994928992201206c16be7a01f7add46e0ee987d76a947a7f4f9396a945eeb671c43307b6f5d55bd57d90738880cebdaa0907aca65dd
languageName: node
linkType: hard
"@solid-primitives/utils@npm:^6.0.0":
version: 6.0.0
resolution: "@solid-primitives/utils@npm:6.0.0"
peerDependencies:
solid-js: ^1.6.12
checksum: c581b995e2d16c9ed0546baef52a9e60f54dda457a3733bac467a19f2a63227179eb0ec6faa16397af4cacc13fa281288cf967a206b0a75255412fafadc55411
languageName: node
linkType: hard
"@types/bson@npm:*":
version: 4.0.5
resolution: "@types/bson@npm:4.0.5"
@ -191,15 +197,6 @@ __metadata:
languageName: node
linkType: soft
"axios@npm:^0.21.4":
version: 0.21.4
resolution: "axios@npm:0.21.4"
dependencies:
follow-redirects: ^1.14.0
checksum: 44245f24ac971e7458f3120c92f9d66d1fc695e8b97019139de5b0cc65d9b8104647db01e5f46917728edfc0cfd88eb30fc4c55e6053eef4ace76768ce95ff3c
languageName: node
linkType: hard
"axios@npm:^0.26.1":
version: 0.26.1
resolution: "axios@npm:0.26.1"
@ -231,7 +228,6 @@ __metadata:
resolution: "bridge@workspace:."
dependencies:
"@discordjs/rest": ^0.4.1
"@janderedev/revolt.js": latest
automod: ^0.1.0
axios: ^0.26.1
discord-api-types: ^0.31.2
@ -242,7 +238,8 @@ __metadata:
log75: ^2.2.0
monk: ^7.3.4
prom-client: ^14.0.1
revolt-api: ^0.5.3-rc.8
revolt-api: latest
revolt.js: ^7.0.0
smart-replace: ^1.0.2
typescript: ^4.7.4
ulid: ^2.3.0
@ -281,6 +278,13 @@ __metadata:
languageName: node
linkType: hard
"csstype@npm:^3.1.0":
version: 3.1.2
resolution: "csstype@npm:3.1.2"
checksum: e1a52e6c25c1314d6beef5168da704ab29c5186b877c07d822bd0806717d9a265e8493a2e35ca7e68d0f5d472d43fac1cdce70fd79fd0853dff81f3028d857b5
languageName: node
linkType: hard
"debug@npm:*":
version: 4.3.4
resolution: "debug@npm:4.3.4"
@ -359,10 +363,10 @@ __metadata:
languageName: node
linkType: hard
"eventemitter3@npm:^4.0.7":
version: 4.0.7
resolution: "eventemitter3@npm:4.0.7"
checksum: 1875311c42fcfe9c707b2712c32664a245629b42bb0a5a84439762dd0fd637fc54d078155ea83c2af9e0323c9ac13687e03cfba79b03af9f40c89b4960099374
"eventemitter3@npm:^5.0.0":
version: 5.0.0
resolution: "eventemitter3@npm:5.0.0"
checksum: b974bafbab860e0a5bbb21add4c4e82f9d5691c583c03f2e4c5d44a2d6c4556d79223621bdcfc6c8e14366a4af9df6b5ea9d6caf65fbffc80b66f3e1dceacbc9
languageName: node
linkType: hard
@ -373,7 +377,7 @@ __metadata:
languageName: node
linkType: hard
"follow-redirects@npm:^1.14.0, follow-redirects@npm:^1.14.8":
"follow-redirects@npm:^1.14.8":
version: 1.15.2
resolution: "follow-redirects@npm:1.15.2"
peerDependenciesMeta:
@ -433,6 +437,15 @@ __metadata:
languageName: node
linkType: hard
"isomorphic-ws@npm:^5.0.0":
version: 5.0.0
resolution: "isomorphic-ws@npm:5.0.0"
peerDependencies:
ws: "*"
checksum: e20eb2aee09ba96247465fda40c6d22c1153394c0144fa34fe6609f341af4c8c564f60ea3ba762335a7a9c306809349f9b863c8beedf2beea09b299834ad5398
languageName: node
linkType: hard
"js-yaml@npm:^4.1.0":
version: 4.1.0
resolution: "js-yaml@npm:4.1.0"
@ -460,20 +473,6 @@ __metadata:
languageName: node
linkType: hard
"lodash.flatten@npm:^4.4.0":
version: 4.4.0
resolution: "lodash.flatten@npm:4.4.0"
checksum: 0ac34a393d4b795d4b7421153d27c13ae67e08786c9cbb60ff5b732210d46f833598eee3fb3844bb10070e8488efe390ea53bb567377e0cb47e9e630bf0811cb
languageName: node
linkType: hard
"lodash.isequal@npm:^4.5.0":
version: 4.5.0
resolution: "lodash.isequal@npm:4.5.0"
checksum: da27515dc5230eb1140ba65ff8de3613649620e8656b19a6270afe4866b7bd461d9ba2ac8a48dcc57f7adac4ee80e1de9f965d89d4d81a0ad52bb3eec2609644
languageName: node
linkType: hard
"lodash@npm:^4.17.21":
version: 4.17.21
resolution: "lodash@npm:4.17.21"
@ -490,7 +489,7 @@ __metadata:
languageName: node
linkType: hard
"long@npm:^5.2.0":
"long@npm:^5.2.1":
version: 5.2.1
resolution: "long@npm:5.2.1"
checksum: 9264da12d1b7df67e5aa6da4498144293caf1ad12e7f092efe4e9a2d32c53f0bbf7334f7cef997080a2a3af061142558ab366efa71698d98b1cdb883477445a7
@ -529,13 +528,6 @@ __metadata:
languageName: node
linkType: hard
"mobx@npm:^6.3.2":
version: 6.8.0
resolution: "mobx@npm:6.8.0"
checksum: f09bb079292ea59023a7e35a9c73ed577e3de9a0175ec3d5a2adc8192e2e3a352b29ec0981ee06d1d63f701f81bb7fc6cc19fd9089edf84a754a8a75ef00ef7f
languageName: node
linkType: hard
"mongodb@npm:^3.2.3":
version: 3.7.3
resolution: "mongodb@npm:3.7.3"
@ -726,17 +718,33 @@ __metadata:
languageName: node
linkType: hard
"revolt-api@npm:0.5.16, revolt-api@npm:^0.5.3-rc.8":
version: 0.5.16
resolution: "revolt-api@npm:0.5.16"
"revolt-api@npm:^0.5.17, revolt-api@npm:latest":
version: 0.5.17
resolution: "revolt-api@npm:0.5.17"
dependencies:
"@insertish/oapi": 0.1.18
axios: ^0.26.1
lodash.defaultsdeep: ^4.6.1
checksum: ce39f61e371c1b7da0704191317bccf88b6630f1d8ffcef6bc9c699ebdc8cfbb3fcc5e054f96f9751c2f4a048398d4b349670cd067bcaad2e099d0c30efd9cfe
checksum: aa722f4739c09bea46f738a1b9aef61af126e06aa924a61fcf33caa53561c5de4e7e2ddde26b496cdd0546e113cf324821fead0035973e2ebdb2633df482091b
languageName: node
linkType: hard
"revolt.js@portal:../revolt.js::locator=bridge%40workspace%3A.":
version: 0.0.0-use.local
resolution: "revolt.js@portal:../revolt.js::locator=bridge%40workspace%3A."
dependencies:
"@solid-primitives/map": ^0.4.3
"@solid-primitives/set": ^0.4.3
eventemitter3: ^5.0.0
isomorphic-ws: ^5.0.0
long: ^5.2.1
revolt-api: ^0.5.17
solid-js: ^1.7.2
ulid: ^2.3.0
ws: ^8.13.0
languageName: node
linkType: soft
"safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2":
version: 5.2.1
resolution: "safe-buffer@npm:5.2.1"
@ -760,6 +768,13 @@ __metadata:
languageName: node
linkType: hard
"seroval@npm:^0.5.0":
version: 0.5.1
resolution: "seroval@npm:0.5.1"
checksum: a4c1e42d6a65ed12de3c1f1b6a5b6b996e575c5bc838e1998e92daed7bc05421f3f6c82096387082dba33c475d64a31d0d932ac9b693352549259216e38dc091
languageName: node
linkType: hard
"smart-replace@npm:^1.0.2":
version: 1.0.2
resolution: "smart-replace@npm:1.0.2"
@ -767,6 +782,16 @@ __metadata:
languageName: node
linkType: hard
"solid-js@npm:^1.7.2":
version: 1.7.3
resolution: "solid-js@npm:1.7.3"
dependencies:
csstype: ^3.1.0
seroval: ^0.5.0
checksum: 052a3148b6d0960312793781435005c16a7a80c2271e2bf2370ec22ec57ffd77e3e4a41335c1bd785ab36500adef86da79536445983efbed404db860e11593d4
languageName: node
linkType: hard
"sparse-bitfield@npm:^3.0.3":
version: 3.0.3
resolution: "sparse-bitfield@npm:3.0.3"
@ -894,7 +919,7 @@ __metadata:
languageName: node
linkType: hard
"ws@npm:^8.2.2, ws@npm:^8.9.0":
"ws@npm:^8.13.0, ws@npm:^8.9.0":
version: 8.13.0
resolution: "ws@npm:8.13.0"
peerDependencies:

1
revolt.js Submodule

@ -0,0 +1 @@
Subproject commit d452295c85c0d700ea536ebed2061c5daf960612