discord.js-light v4
Discord.js v13 introduces several major changes including a completely new caching system which enables users to fully customize the library to match their caching preferences, however not all caching configurations are officially supported and some may introduce several side effects.
This library aims to improve support and usability when using discord.js with limited or disabled caches.
Branches
- master - based on the discord.js master branch (not actively maintained, should not be used)
- v4 - current npm version, based on discord.js v13
- v3 - old npm version, based on discord.js v12
- v2 - deprecated
- v1 - deprecated
v4 Features
- Fully supports the new discord.js caching system, including unsupported configurations, with little to no side effects
- Discord.js partials system removed and replaced with an internal "always on" solution
- Events always work, regardless of caching options (partial structures are given when missing), see djs-cache-test
- Partials can be created on demand to interact with the Discord API without fetching first
- Additional utilities to improve usability with caches disabled
Usage
const Discord = require("discord.js-light");
const client = new Discord.Client({
makeCache: Discord.Options.cacheWithLimits({
ApplicationCommandManager: 0,
BaseGuildEmojiManager: 0,
ChannelManager: 0,
GuildChannelManager: 0,
GuildBanManager: 0,
GuildInviteManager: 0,
GuildManager: Infinity,
GuildMemberManager: 0,
GuildStickerManager: 0,
GuildScheduledEventManager: 0,
MessageManager: 0,
PermissionOverwriteManager: 0,
PresenceManager: 0,
ReactionManager: 0,
ReactionUserManager: 0,
RoleManager: 0,
StageInstanceManager: 0,
ThreadManager: 0,
ThreadMemberManager: 0,
UserManager: 0,
VoiceStateManager: 0
}),
intents: [ ],
});
client.on("messageCreate", async message => {
if(!message.guild) return;
const guildNameOrId = message.guild.partial ? message.guild.id : message.guild.name;
const channelNameOrId = message.channel.partial ? message.channel.id : message.channel.name;
await message.channel.send(`hello from guild ${guildNameOrId} and channel ${channelNameOrId}`);
});
client.login("your token here");
Cache Configuration
Discord.js's new caching configuration is very powerful, here are a few examples:
{
ChannelManager: 0,
GuildChannelManager: { maxSize: 0 },
RoleManager: 5,
UserManager: {
maxSize: 10,
keepOverLimit: (value, key, collection) => value.id === value.client.user.id
},
GuildMemberManager: {
maxSize: Infinity,
sweepFilter: collection => (value, key, collection) => value.id !== value.client.user.id,
sweepInterval: 600
}
}
New sweeper options added with discord.js v13.4.0 (discord.js-light 4.5.0):
new Discord.Client({
makeCache: Discord.Options.cacheWithLimits({
UserManager: {
maxSize: 50,
keepOverLimit: (value, key, collection) => value.id === value.client.user.id
},
MessageManager: {
maxSize: 100
}
}),
sweepers: {
users: {
interval: 600,
filter: user => user.id !== user.client.user.id
},
messages: {
interval: 600,
filter: message => message.author?.id !== message.client.user.id
}
}
})
For further information refer to the official discord.js documentation.
Non-standard stuff
...Manager#forge
All managers implement this method to create partial versions of uncached objects on demand. This enables making API requests without fetching uncached objects first. This is only used to send requests to the API, if you need to access the object's properties, you need to fetch it. Some forge methods require additional parameters, check your intelisense.
await client.users.forge(id).send("hello");
Collection#forceSet
All caches implement this method, which is the same as .cache.set()
but works even if the caches are completely disabled (set to 0). Use this to manually cache fetched items.
const user = await client.users.fetch(id);
client.users.cache.forceSet(id, user);
GuildChannel#fetchOverwrites
Method added to improve accessibility to permission checking when caches are disabled. This can be used to work with permissions directly but to use regular permission checking methods, they need to be manually added to the cache.
const overwrites = await channel.fetchOverwrites();
console.log(overwrites)
overwrites.forEach(overwrite => {
channel.permissionOverwrites.cache.forceSet(overwrite.id, overwrite);
})
shardConnect
Event fired when each individual internal shard connects.
client.on("shardConnect", (shardId, guilds) => {
console.log(shardId)
console.log(guilds)
});
guildEmojisUpdate
Event fired instead of the standard emoji events when the emoji cache is disabled. If the emojis cache is disabled, emojiCreate, emojiUpdate and emojiDelete will never be fired.
client.on("guildEmojisUpdate", emojis => {
console.log(emojis)
})
guildStickersUpdate
Event fired instead of the standard sticker events when the sticker cache is disabled. If the stickers cache is disabled, stickerCreate, stickerUpdate and stickerDelete will never be fired.
client.on("guildStickersUpdate", stickers => {
console.log(stickers)
})
rest
Event fired when the library makes a request to the discord API. Use this to debug rate limit issues.
client.on("rest", request => {
console.log(request);
});
Notes and Important Info
Fetching data does not automatically cache if cache limits are set to 0. Use the non-standard Collection#forceSet
method instead to manually cache fetched items. Manually cached items can be accessed, updated, swept and removed normally.
The bot member is cached by default (unless removed by the user). GuildMemberManager auto-sweep will still remove it if not excluded in your sweepFilter.
The everyone role is cached by default (unless removed by the user). RoleManager auto-sweep will still remove it if not excluded in your sweepFilter.
ChannelManager and GuildChannelManager should be configured together, otherwise weird things can happen if they have different configurations, use at your own risk. If anything prioritize enabling ChannelManager over GuildChannelManager.
Note about continued development: v4 will likely be the last discord.js-light version. As of v13, discord.js is now much better than what it used to be in terms of configurability and resource management, and v14 will likely be even better, to the point where discord.js-light probably wont be useful anymore. For now v4 will still be maintained and will still keep up with discord.js's v13 development as needed, but this adventure might reach a conclusion soon. So long and thanks for all the fish!
Examples
An example for maximizing cache efficiency while keeping full support for permission checking. Using the new autosweep functionality and the non-standard forceSet methods to keep only active text channels cached.
const Discord = require("discord.js-light");
function channelFilter(channel) {
return !channel.lastMessageId || Discord.SnowflakeUtil.timestampFrom(channel.lastMessageId) < Date.now() - 3600000;
}
const makeCache = Discord.Options.cacheWithLimits({
GuildManager: Infinity,
RoleManager: Infinity,
PermissionOverwrites: Infinity,
ChannelManager: {
maxSize: 0,
sweepFilter: () => channelFilter,
sweepInterval: 3600
},
GuildChannelManager: {
maxSize: 0,
sweepFilter: () => channelFilter,
sweepInterval: 3600
},
});
const client = new Discord.Client({ makeCache, intents: [ ] });
client.on("messageCreate", async message => {
if(!client.channels.cache.has(message.channel.id)) {
const channel = await client.channels.fetch(message.channel.id);
client.channels.cache.forceSet(channel.id, channel);
message.guild?.channels.cache.forceSet(channel.id, channel);
}
console.log(message.channel.permissionsFor(message.member));
});
An example for caching roles only for the bot itself and ignoring all other roles. Use in combination with the previous example if you want to check permissions in channels as well.
const Discord = require("discord.js-light");
const makeCache = Discord.Options.cacheWithLimits({
GuildManager: Infinity,
RoleManager: {
maxSize: Infinity,
sweepFilter: () => role => !role.guild.me.roles.has(role.id),
sweepInterval: 3600
},
});
const client = new Discord.Client({ makeCache, intents: [ ] });
client.on("ready", () => {
client.guilds.forEach(guild => {
guild.roles.cache.maxSize = 0;
guild.roles.cache.sweep(role => !guild.me.roles.has(role.id))
});
});
client.on("guildMemberUpdate", async (oldMember, newMember) => {
if(newMember.id === client.user.id) {
for(const role of newMember.roles.cache.values()) {
if(role.partial) {
const fetched = await newMember.guild.roles.fetch(role.id);
newMember.guild.roles.cache.forceSet(role.id, fetched);
}
}
}
});
Bots using discord.js-light